• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
4  *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
5  *   Copyright 2010 Shao Miller
6  *   Copyright 2010-2012 Michal Soltys
7  *
8  *   Permission is hereby granted, free of charge, to any person
9  *   obtaining a copy of this software and associated documentation
10  *   files (the "Software"), to deal in the Software without
11  *   restriction, including without limitation the rights to use,
12  *   copy, modify, merge, publish, distribute, sublicense, and/or
13  *   sell copies of the Software, and to permit persons to whom
14  *   the Software is furnished to do so, subject to the following
15  *   conditions:
16  *
17  *   The above copyright notice and this permission notice shall
18  *   be included in all copies or substantial portions of the Software.
19  *
20  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27  *   OTHER DEALINGS IN THE SOFTWARE.
28  *
29  * ----------------------------------------------------------------------- */
30 
31 #include <com32.h>
32 #include <fcntl.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <fs.h>
39 #include <syslinux/disk.h>
40 #include <syslinux/pmapi.h>
41 #include "utility.h"
42 
43 static const char *bpbtypes[] = {
44     [0] =  "unknown",
45     [1] =  "2.0",
46     [2] =  "3.0",
47     [3] =  "3.2",
48     [4] =  "3.4",
49     [5] =  "4.0",
50     [6] =  "8.0 (NT+)",
51     [7] =  "7.0",
52     [8] =  "exFAT",
53 };
54 
wait_key(void)55 void wait_key(void)
56 {
57     int cnt;
58     char junk;
59 
60     /* drain */
61     do {
62 	errno = 0;
63 	cnt = read(0, &junk, 1);
64     } while (cnt > 0 || (cnt < 0 && errno == EAGAIN));
65 
66     /* wait */
67     do {
68 	errno = 0;
69 	cnt = read(0, &junk, 1);
70     } while (!cnt || (cnt < 0 && errno == EAGAIN));
71 }
72 
guid_is0(const struct guid * guid)73 int guid_is0(const struct guid *guid)
74 {
75     return
76 	!(guid->data1 ||
77 	  guid->data2 ||
78 	  guid->data3 ||
79 	  guid->data4);
80 }
81 
82 /*
83  * mode explanation:
84  *
85  * cnul - "strict" mode, never returning higher value than obtained from cbios
86  * cadd - if the disk is larger than reported geometry /and/ if the geometry has
87  *        less cylinders than 1024 - it means that the total size is somewhere
88  *        between cs and cs+1; in this particular case, we bump the cs to be able
89  *        to return matching chs triplet
90  * cmax - assume we can use any cylinder value
91  *
92  * by default cadd seems most reasonable, giving consistent results with e.g.
93  * sfdisk's behavior
94  */
lba2chs(disk_chs * dst,const struct disk_info * di,uint64_t lba,int mode)95 void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode)
96 {
97     uint32_t c, h, s, t;
98     uint32_t cs, hs, ss;
99 
100     /*
101      * Not much reason here, but if we have no valid CHS geometry, we assume
102      * "typical" ones to have something to return.
103      */
104     if (di->cbios) {
105 	cs = di->cyl;
106 	hs = di->head;
107 	ss = di->spt;
108 	if (mode == L2C_CADD) {
109 	    if (cs < 1024 && di->lbacnt > cs*hs*ss)
110 		cs++;
111 	} else if (mode == L2C_CMAX)
112 	    cs = 1024;
113     } else {
114 	if (di->disk & 0x80) {
115 	    cs = 1024;
116 	    hs = 255;
117 	    ss = 63;
118 	} else {
119 	    cs = 80;
120 	    hs = 2;
121 	    ss = 18;
122 	}
123     }
124 
125     if (lba >= cs*hs*ss) {
126 	s = ss;
127 	h = hs - 1;
128 	c = cs - 1;
129     } else {
130 	s = (lba % ss) + 1;
131 	t = lba / ss;
132 	h = t % hs;
133 	c = t / hs;
134     }
135 
136     (*dst)[0] = h;
137     (*dst)[1] = s | ((c & 0x300) >> 2);
138     (*dst)[2] = c;
139 }
140 
get_file_lba(const char * filename)141 uint32_t get_file_lba(const char *filename)
142 {
143     struct com32_filedata fd;
144     uint32_t lba = 0;
145     int size = 65536;
146     char *buf;
147 
148     buf = lmalloc(size);
149     if (!buf)
150 	return 0;
151 
152     /* Put the filename in the bounce buffer */
153     strlcpy(buf, filename, size);
154 
155     if (open_file(buf, O_RDONLY, &fd) <= 0) {
156 	goto fail;		/* Filename not found */
157     }
158 
159     /* Since the first member is the LBA, we simply cast */
160     lba = *((uint32_t *) MK_PTR(0, fd.handle));
161 
162     /* Call comapi_close() to free the structure */
163     close_file(fd.handle);
164 
165 fail:
166     lfree(buf);
167     return lba;
168 }
169 
170 /* drive offset detection */
drvoff_detect(int type)171 int drvoff_detect(int type)
172 {
173     if (bpbV40 <= type && type <= bpbVNT) {
174 	return 0x24;
175     } else if (type == bpbV70) {
176 	return 0x40;
177     } else if (type == bpbEXF) {
178 	return 0x6F;
179     }
180 
181     return -1;
182 }
183 
184 /*
185  * heuristics could certainly be improved
186  */
bpb_detect(const uint8_t * sec,const char * tag)187 int bpb_detect(const uint8_t *sec, const char *tag)
188 {
189     int a, b, c, jmp = -1, rev = 0;
190 
191     /* exFAT mess first (media descriptor is 0 here) */
192     if (!memcmp(sec + 0x03, "EXFAT   ", 8)) {
193 	rev = bpbEXF;
194 	goto out;
195     }
196 
197     /* media descriptor check */
198     if ((sec[0x15] & 0xF0) != 0xF0)
199 	goto out;
200 
201     if (sec[0] == 0xEB)	/* jump short */
202 	jmp = 2 + *(int8_t *)(sec + 1);
203     else if (sec[0] == 0xE9) /* jump near */
204 	jmp = 3 + *(int16_t *)(sec + 1);
205 
206     if (jmp < 0)    /* no boot code at all ? */
207 	goto nocode;
208 
209     /* sanity */
210     if (jmp < 0x18 || jmp > 0x1F0)
211 	goto out;
212 
213     /* detect by jump */
214     if (jmp >= 0x18 && jmp < 0x1E)
215 	rev = bpbV20;
216     else if (jmp >= 0x1E && jmp < 0x20)
217 	rev = bpbV30;
218     else if (jmp >= 0x20 && jmp < 0x24)
219 	rev = bpbV32;
220     else if (jmp >= 0x24 && jmp < 0x46)
221 	rev = bpbV34;
222 
223     /* TODO: some better V2 - V3.4 checks ? */
224 
225     if (rev)
226 	goto out;
227     /*
228      * BPB info:
229      * 2.0 ==       0x0B - 0x17
230      * 3.0 == 2.0 + 0x18 - 0x1D
231      * 3.2 == 3.0 + 0x1E - 0x1F
232      * 3.4 ==!2.0 + 0x18 - 0x23
233      * 4.0 == 3.4 + 0x24 - 0x45
234      *  NT ==~3.4 + 0x24 - 0x53
235      * 7.0 == 3.4 + 0x24 - 0x59
236      */
237 
238 nocode:
239     a = memcmp(sec + 0x03, "NTFS", 4);
240     b = memcmp(sec + 0x36, "FAT", 3);
241     c = memcmp(sec + 0x52, "FAT", 3);	/* ext. DOS 7+ bs */
242 
243     if ((sec[0x26] & 0xFE) == 0x28 && !b) {
244 	rev = bpbV40;
245     } else if (sec[0x26] == 0x80 && !a) {
246 	rev = bpbVNT;
247     } else if ((sec[0x42] & 0xFE) == 0x28 && !c) {
248 	rev = bpbV70;
249     }
250 
251 out:
252     printf("BPB detection (%s): %s\n", tag, bpbtypes[rev]);
253     return rev;
254 }
255 
256 /* vim: set ts=8 sts=4 sw=4 noet: */
257