1 | /*␊ |
2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.␊ |
3 | *␊ |
4 | * @APPLE_LICENSE_HEADER_START@␊ |
5 | * ␊ |
6 | * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights␊ |
7 | * Reserved. This file contains Original Code and/or Modifications of␊ |
8 | * Original Code as defined in and that are subject to the Apple Public␊ |
9 | * Source License Version 2.0 (the "License"). You may not use this file␊ |
10 | * except in compliance with the License. Please obtain a copy of the␊ |
11 | * License at http://www.apple.com/publicsource and read it before using␊ |
12 | * this file.␊ |
13 | * ␊ |
14 | * The Original Code and all software distributed under the License are␊ |
15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER␊ |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,␊ |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,␊ |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the␊ |
19 | * License for the specific language governing rights and limitations␊ |
20 | * under the License.␊ |
21 | * ␊ |
22 | * @APPLE_LICENSE_HEADER_END@␊ |
23 | */␊ |
24 | /* ␊ |
25 | * Mach Operating System␊ |
26 | * Copyright (c) 1990 Carnegie-Mellon University␊ |
27 | * Copyright (c) 1989 Carnegie-Mellon University␊ |
28 | * All rights reserved. The CMU software License Agreement specifies␊ |
29 | * the terms and conditions for use and redistribution.␊ |
30 | */␊ |
31 | ␊ |
32 | /*␊ |
33 | * INTEL CORPORATION PROPRIETARY INFORMATION␊ |
34 | *␊ |
35 | * This software is supplied under the terms of a license agreement or ␊ |
36 | * nondisclosure agreement with Intel Corporation and may not be copied ␊ |
37 | * nor disclosed except in accordance with the terms of that agreement.␊ |
38 | *␊ |
39 | * Copyright 1988, 1989 Intel Corporation␊ |
40 | */␊ |
41 | ␊ |
42 | /*␊ |
43 | * Copyright 1993 NeXT Computer, Inc.␊ |
44 | * All rights reserved.␊ |
45 | */␊ |
46 | ␊ |
47 | /*␊ |
48 | * Copyright 2007 VMware Inc.␊ |
49 | * "Preboot" ramdisk support added by David Elliott␊ |
50 | * GPT support added by David Elliott. Based on IOGUIDPartitionScheme.cpp.␊ |
51 | */␊ |
52 | ␊ |
53 | //Azi: style the rest later...␊ |
54 | ␊ |
55 | // Allow UFS_SUPPORT to be overridden with preprocessor option.␊ |
56 | #ifndef UFS_SUPPORT␊ |
57 | // zef: Disabled UFS support␊ |
58 | #define UFS_SUPPORT 0␊ |
59 | #endif␊ |
60 | ␊ |
61 | #if UFS_SUPPORT␊ |
62 | #include "ufs.h"␊ |
63 | #endif␊ |
64 | #include <limits.h>␊ |
65 | #include <IOKit/storage/IOApplePartitionScheme.h>␊ |
66 | #include <IOKit/storage/IOGUIDPartitionScheme.h>␊ |
67 | #include "libsaio.h"␊ |
68 | #include "boot.h"␊ |
69 | #include "bootstruct.h"␊ |
70 | #include "memory.h"␊ |
71 | #include "fdisk.h"␊ |
72 | #include "hfs.h"␊ |
73 | #include "ntfs.h"␊ |
74 | #include "msdos.h"␊ |
75 | #include "ext2fs.h"␊ |
76 | #include "befs.h"␊ |
77 | #include "freebsd.h"␊ |
78 | #include "openbsd.h"␊ |
79 | #include "xml.h"␊ |
80 | #include "disk.h"␊ |
81 | // For EFI_GUID␊ |
82 | #include "efi.h"␊ |
83 | ␊ |
84 | ␊ |
85 | typedef struct gpt_hdr gpt_hdr;␊ |
86 | typedef struct gpt_ent gpt_ent;␊ |
87 | ␊ |
88 | #include "efi_tables.h"␊ |
89 | ␊ |
90 | #define PROBEFS_SIZE BPS * 4 /* buffer size for filesystem probe */␊ |
91 | #define CD_BPS 2048 /* CD-ROM block size */␊ |
92 | #define N_CACHE_SECS (BIOS_LEN / BPS) /* Must be a multiple of 4 for CD-ROMs */␊ |
93 | #define UFS_FRONT_PORCH 0␊ |
94 | #define kAPMSector 2 /* Sector number of Apple partition map */␊ |
95 | #define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */␊ |
96 | ␊ |
97 | // IORound and IOTrunc convenience functions, in the spirit of vm's round_page() and trunc_page().␊ |
98 | #define IORound(value, multiple) ((((value) + (multiple) - 1) / (multiple)) * (multiple))␊ |
99 | #define IOTrunc(value, multiple) (((value) / (multiple)) * (multiple));␊ |
100 | ␊ |
101 | // trackbuf points to the start of the track cache. Biosread() ␊ |
102 | // will store the sectors read from disk to this memory area.␊ |
103 | static char * const trackbuf = (char *) ptov(BIOS_ADDR);␊ |
104 | ␊ |
105 | // biosbuf points to a sector within the track cache, and is updated by Biosread().␊ |
106 | static char * biosbuf;␊ |
107 | ␊ |
108 | // Map a disk drive to bootable volumes contained within.␊ |
109 | struct DiskBVMap␊ |
110 | {␊ |
111 | int␉␉␉␉␉biosdev;␉// BIOS device number (unique).␊ |
112 | BVRef␉␉␉␉bvr;␉␉// Chain of boot volumes on the disk.␊ |
113 | int␉␉␉␉␉bvrcnt;␉␉// Number of boot volumes.␊ |
114 | struct DiskBVMap *␉next;␉␉// Linkage to next mapping.␊ |
115 | };␊ |
116 | ␊ |
117 | static struct DiskBVMap * gDiskBVMap = NULL;␊ |
118 | static struct disk_blk0 * gBootSector = NULL;␊ |
119 | ␊ |
120 | // Function pointers to be filled in when a ramdisk is available:␊ |
121 | int (*p_ramdiskReadBytes)(int biosdev, unsigned int blkno, unsigned int byteoff, unsigned int byteCount, void * buffer) = NULL;␊ |
122 | int (*p_get_ramdisk_info)(int biosdev, struct driveInfo *dip) = NULL;␊ |
123 | ␊ |
124 | static bool getOSVersion(BVRef bvr, char *str);␊ |
125 | ␊ |
126 | extern void spinActivityIndicator(int sectors);␊ |
127 | ␊ |
128 | //==========================================================================␊ |
129 | ␊ |
130 | static int getDriveInfo(int biosdev, struct driveInfo *dip)␊ |
131 | {␊ |
132 | ␉static struct driveInfo cached_di;␊ |
133 | ␉int cc;␊ |
134 | ␊ |
135 | ␉// Real BIOS devices are 8-bit, so anything above that is for internal use.␊ |
136 | ␉// Don't cache ramdisk drive info since it doesn't require several BIOS␊ |
137 | ␉// calls and is thus not worth it.␊ |
138 | ␉if (biosdev >= 0x100)␊ |
139 | ␉{␊ |
140 | ␉␉if (p_get_ramdisk_info != NULL)␊ |
141 | ␉␉{␊ |
142 | ␉␉␉cc = (*p_get_ramdisk_info)(biosdev, dip);␊ |
143 | ␉␉}␊ |
144 | ␉␉else␊ |
145 | ␉␉{␊ |
146 | ␉␉␉cc = -1;␊ |
147 | ␉␉}␊ |
148 | ␉␉if (cc < 0)␊ |
149 | ␉␉{␊ |
150 | ␉␉␉dip->valid = 0;␊ |
151 | ␉␉␉return -1;␊ |
152 | ␉␉}␊ |
153 | ␉␉else␊ |
154 | ␉␉{␊ |
155 | ␉␉␉return 0;␊ |
156 | ␉␉}␊ |
157 | ␉}␊ |
158 | ␊ |
159 | ␉if (!cached_di.valid || biosdev != cached_di.biosdev)␊ |
160 | ␉{␊ |
161 | ␉cc = get_drive_info(biosdev, &cached_di);␊ |
162 | ␊ |
163 | ␉␉if (cc < 0)␊ |
164 | ␉␉{␊ |
165 | ␉␉␉cached_di.valid = 0;␊ |
166 | ␉␉␉DEBUG_DISK(("get_drive_info returned error\n"));␊ |
167 | ␉␉␉return (-1); // BIOS call error␊ |
168 | ␉␉}␊ |
169 | ␉}␊ |
170 | ␊ |
171 | ␉bcopy(&cached_di, dip, sizeof(cached_di));␊ |
172 | ␊ |
173 | ␉return 0;␊ |
174 | }␊ |
175 | ␊ |
176 | //==========================================================================␊ |
177 | // Maps (E)BIOS return codes to message strings.␊ |
178 | ␊ |
179 | struct NamedValue␊ |
180 | {␊ |
181 | ␉unsigned char value;␊ |
182 | ␉const char * name;␊ |
183 | };␊ |
184 | ␊ |
185 | static const char * getNameForValue(const struct NamedValue * nameTable, unsigned char value)␊ |
186 | {␊ |
187 | ␉const struct NamedValue * np;␊ |
188 | ␊ |
189 | ␉for ( np = nameTable; np->value; np++)␊ |
190 | ␉{␊ |
191 | ␉␉if (np->value == value)␊ |
192 | ␉␉{␊ |
193 | ␉␉␉return np->name;␊ |
194 | ␉␉}␊ |
195 | ␉}␊ |
196 | ␉return NULL;␊ |
197 | }␊ |
198 | ␊ |
199 | #define ECC_CORRECTED_ERR 0x11␊ |
200 | ␊ |
201 | static const struct NamedValue bios_errors[] = {␊ |
202 | ␉{ 0x10, "Media error" },␊ |
203 | ␉{ 0x11, "Corrected ECC error" },␊ |
204 | ␉{ 0x20, "Controller or device error" },␊ |
205 | ␉{ 0x40, "Seek failed" },␊ |
206 | ␉{ 0x80, "Device timeout" },␊ |
207 | ␉{ 0xAA, "Drive not ready" },␊ |
208 | ␉{ 0x00, 0 }␊ |
209 | };␊ |
210 | ␊ |
211 | static const char * bios_error(int errnum)␊ |
212 | {␊ |
213 | ␉static char errorstr[] = "Error 0x00";␊ |
214 | ␉const char * errname;␊ |
215 | ␊ |
216 | ␉errname = getNameForValue(bios_errors, errnum);␊ |
217 | ␊ |
218 | ␉if (errname)␊ |
219 | ␉{␊ |
220 | ␉␉return errname;␊ |
221 | ␉}␊ |
222 | ␊ |
223 | ␉sprintf(errorstr, "Error 0x%02x", errnum);␊ |
224 | ␉return errorstr; // No string, print error code only␊ |
225 | }␊ |
226 | ␊ |
227 | //==========================================================================␊ |
228 | // Use BIOS INT13 calls to read the sector specified. This function will also␊ |
229 | // perform read-ahead to cache a few subsequent sector to the sector cache.␊ |
230 | // ␊ |
231 | // Returns 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.␊ |
232 | ␊ |
233 | static bool cache_valid = false;␊ |
234 | ␊ |
235 | static int Biosread(int biosdev, unsigned long long secno)␊ |
236 | {␊ |
237 | ␉static int xbiosdev, xcyl, xhead;␊ |
238 | ␉static unsigned int xsec, xnsecs;␊ |
239 | ␉struct driveInfo di;␊ |
240 | ␊ |
241 | ␉int rc = -1;␊ |
242 | ␉int cyl, head, sec;␊ |
243 | ␉int tries = 0;␊ |
244 | ␉int bps, divisor;␊ |
245 | ␊ |
246 | ␉if (getDriveInfo(biosdev, &di) < 0)␊ |
247 | ␉{␊ |
248 | ␉␉return -1;␊ |
249 | ␉}␊ |
250 | ␉if (di.no_emulation)␊ |
251 | ␉{␊ |
252 | ␉␉/* Always assume 2k block size; BIOS may lie about geometry */␊ |
253 | ␉␉bps = 2048;␊ |
254 | ␉}␊ |
255 | ␉else␊ |
256 | ␉{␊ |
257 | ␉␉bps = di.di.params.phys_nbps;␊ |
258 | ␊ |
259 | ␉␉if (bps == 0)␊ |
260 | ␉␉{␊ |
261 | ␉␉␉return -1;␊ |
262 | ␉␉}␊ |
263 | ␉}␊ |
264 | ␉divisor = bps / BPS;␊ |
265 | ␊ |
266 | ␉DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));␊ |
267 | ␊ |
268 | ␉// To read the disk sectors, use EBIOS if we can. Otherwise,␊ |
269 | ␉// revert to the standard BIOS calls.␊ |
270 | ␊ |
271 | ␉if ((biosdev >= kBIOSDevTypeHardDrive) && (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))␊ |
272 | ␉{␊ |
273 | ␉␉if (cache_valid && (biosdev == xbiosdev) && (secno >= xsec) && ((unsigned int)secno < (xsec + xnsecs)))␊ |
274 | ␉␉{␊ |
275 | ␉␉␉biosbuf = trackbuf + (BPS * (secno - xsec));␊ |
276 | ␉␉␉return 0;␊ |
277 | ␉␉}␊ |
278 | ␊ |
279 | ␉␉xnsecs = N_CACHE_SECS;␊ |
280 | ␉␉xsec = (secno / divisor) * divisor;␊ |
281 | ␉␉cache_valid = false;␊ |
282 | ␊ |
283 | ␉␉while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))␊ |
284 | ␉␉{␊ |
285 | ␉␉␉if (rc == ECC_CORRECTED_ERR)␊ |
286 | ␉␉␉{␊ |
287 | ␉␉␉␉/* Ignore corrected ECC errors */␊ |
288 | ␉␉␉␉rc = 0;␊ |
289 | ␉␉␉␉break;␊ |
290 | ␉␉␉}␊ |
291 | ␊ |
292 | ␉␉␉error(" EBIOS read error: %s\n", bios_error(rc), rc);␊ |
293 | ␉␉␉error(" Block 0x%x Sectors %d\n", secno, xnsecs);␊ |
294 | ␉␉␉sleep(1);␊ |
295 | ␉␉}␊ |
296 | ␉}␊ |
297 | ␊ |
298 | ␉else␊ |
299 | ␉{␊ |
300 | ␉␉/* spc = spt * heads */␊ |
301 | ␉␉int spc = (di.di.params.phys_spt * di.di.params.phys_heads);␊ |
302 | ␉␉cyl = secno / spc;␊ |
303 | ␉␉head = (secno % spc) / di.di.params.phys_spt;␊ |
304 | ␉␉sec = secno % di.di.params.phys_spt;␊ |
305 | ␊ |
306 | ␉␉if (cache_valid && (biosdev == xbiosdev) && (cyl == xcyl) &&␊ |
307 | ␉␉␉(head == xhead) && ((unsigned int)sec >= xsec) && ((unsigned int)sec < (xsec + xnsecs)))␊ |
308 | ␉␉{␊ |
309 | ␉␉␉// this sector is in trackbuf cache␊ |
310 | ␉␉␉biosbuf = trackbuf + (BPS * (sec - xsec));␊ |
311 | ␉␉␉return 0;␊ |
312 | ␉␉}␊ |
313 | ␊ |
314 | ␉␉// Cache up to a track worth of sectors, but do not cross a track boundary.␊ |
315 | ␊ |
316 | ␉␉xcyl = cyl;␊ |
317 | ␉␉xhead = head;␊ |
318 | ␉␉xsec = sec;␊ |
319 | ␉␉xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;␊ |
320 | ␊ |
321 | ␉␉cache_valid = false;␊ |
322 | ␊ |
323 | ␉␉while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) && (++tries < 5))␊ |
324 | ␉␉{␊ |
325 | ␉␉␉if (rc == ECC_CORRECTED_ERR)␊ |
326 | ␉␉␉{␊ |
327 | ␉␉␉␉/* Ignore corrected ECC errors */␊ |
328 | ␉␉␉␉rc = 0;␊ |
329 | ␉␉␉␉break;␊ |
330 | ␉␉␉}␊ |
331 | ␉␉␉error(" BIOS read error: %s\n", bios_error(rc), rc);␊ |
332 | ␉␉␉error(" Block %d, Cyl %d Head %d Sector %d\n",␊ |
333 | ␉␉␉secno, cyl, head, sec);␊ |
334 | ␉␉␉sleep(1);␊ |
335 | ␉␉}␊ |
336 | ␉}␊ |
337 | ␊ |
338 | ␉// If the BIOS reported success, mark the sector cache as valid.␊ |
339 | ␊ |
340 | ␉if (rc == 0)␊ |
341 | ␉{␊ |
342 | ␉␉cache_valid = true;␊ |
343 | ␉}␊ |
344 | ␊ |
345 | ␉biosbuf = trackbuf + (secno % divisor) * BPS;␊ |
346 | ␉xbiosdev = biosdev;␊ |
347 | ␊ |
348 | ␉spinActivityIndicator(xnsecs);␊ |
349 | ␊ |
350 | ␉return rc;␊ |
351 | }␊ |
352 | ␊ |
353 | //==========================================================================␊ |
354 | ␊ |
355 | int testBiosread(int biosdev, unsigned long long secno)␊ |
356 | {␊ |
357 | ␉return Biosread(biosdev, secno);␊ |
358 | }␊ |
359 | ␊ |
360 | //==========================================================================␊ |
361 | ␊ |
362 | static int readBytes(int biosdev, unsigned long long blkno, unsigned int byteoff, unsigned int byteCount, void * buffer)␊ |
363 | {␊ |
364 | ␉// ramdisks require completely different code for reading.␊ |
365 | ␉if(p_ramdiskReadBytes != NULL && biosdev >= 0x100)␊ |
366 | ␉{␊ |
367 | ␉␉return (*p_ramdiskReadBytes)(biosdev, blkno, byteoff, byteCount, buffer);␊ |
368 | ␉}␊ |
369 | ␊ |
370 | ␉char * cbuf = (char *) buffer;␊ |
371 | ␉int error;␊ |
372 | ␉int copy_len;␊ |
373 | ␊ |
374 | ␉DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__, biosdev, blkno, byteCount, (unsigned)cbuf));␊ |
375 | ␊ |
376 | ␉for (; byteCount; cbuf += copy_len, blkno++)␊ |
377 | ␉{␊ |
378 | ␉␉error = Biosread(biosdev, blkno);␊ |
379 | ␊ |
380 | ␉␉if (error)␊ |
381 | ␉␉{␊ |
382 | ␉␉␉DEBUG_DISK(("error\n"));␊ |
383 | ␉␉␉return (-1);␊ |
384 | ␉␉}␊ |
385 | ␊ |
386 | ␉␉copy_len = ((byteCount + byteoff) > BPS) ? (BPS - byteoff) : byteCount;␊ |
387 | ␉␉bcopy( biosbuf + byteoff, cbuf, copy_len );␊ |
388 | ␉␉byteCount -= copy_len;␊ |
389 | ␉␉byteoff = 0;␊ |
390 | ␉}␊ |
391 | ␊ |
392 | ␉DEBUG_DISK(("done\n"));␊ |
393 | ␊ |
394 | ␉return 0; ␊ |
395 | }␊ |
396 | ␊ |
397 | //==========================================================================␊ |
398 | ␊ |
399 | static int isExtendedFDiskPartition( const struct fdisk_part * part )␊ |
400 | {␊ |
401 | ␉static unsigned char extParts[] =␊ |
402 | ␉{␊ |
403 | ␉␉0x05, /* Extended */␊ |
404 | ␉␉0x0f, /* Win95 extended */␊ |
405 | ␉␉0x85, /* Linux extended */␊ |
406 | ␉};␊ |
407 | ␊ |
408 | ␉unsigned int i;␊ |
409 | ␊ |
410 | ␉for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++)␊ |
411 | ␉{␊ |
412 | ␉␉if (extParts[i] == part->systid)␊ |
413 | ␉␉{␊ |
414 | ␉␉␉return 1;␊ |
415 | ␉␉}␊ |
416 | ␉}␊ |
417 | ␉return 0;␊ |
418 | }␊ |
419 | ␊ |
420 | //==========================================================================␊ |
421 | ␊ |
422 | static int getNextFDiskPartition( int biosdev, int * partno,␊ |
423 | const struct fdisk_part ** outPart )␊ |
424 | {␊ |
425 | ␉static int sBiosdev = -1;␊ |
426 | ␉static int sNextPartNo;␊ |
427 | ␉static unsigned int sFirstBase;␊ |
428 | ␉static unsigned int sExtBase;␊ |
429 | ␉static unsigned int sExtDepth;␊ |
430 | ␉static struct fdisk_part * sExtPart;␊ |
431 | ␉struct fdisk_part * part;␊ |
432 | ␊ |
433 | ␉if ( sBiosdev != biosdev || *partno < 0 )␊ |
434 | ␉{␊ |
435 | ␉␉// Fetch MBR.␊ |
436 | ␉␉if ( readBootSector( biosdev, DISK_BLK0, 0 ) ) return 0;␊ |
437 | ␊ |
438 | ␉␉sBiosdev = biosdev;␊ |
439 | ␉␉sNextPartNo = 0;␊ |
440 | ␉␉sFirstBase = 0;␊ |
441 | ␉␉sExtBase = 0;␊ |
442 | ␉␉sExtDepth = 0;␊ |
443 | ␉␉sExtPart = NULL;␊ |
444 | ␉}␊ |
445 | ␊ |
446 | ␉while (1)␊ |
447 | ␉{␊ |
448 | ␉␉part = NULL;␊ |
449 | ␊ |
450 | ␉␉if ( sNextPartNo < FDISK_NPART )␊ |
451 | ␉␉{␊ |
452 | ␉␉␉part = (struct fdisk_part *) gBootSector->parts[sNextPartNo];␊ |
453 | ␉␉}␊ |
454 | ␉␉else if ( sExtPart )␊ |
455 | ␉␉{␊ |
456 | ␉␉␉unsigned int blkno = sExtPart->relsect + sFirstBase;␊ |
457 | ␊ |
458 | ␉␉␉// Save the block offset of the first extended partition.␊ |
459 | ␊ |
460 | ␉␉␉if (sExtDepth == 0)␊ |
461 | ␉␉␉{␊ |
462 | ␉␉␉␉sFirstBase = blkno;␊ |
463 | ␉␉␉}␊ |
464 | ␉␉␉sExtBase = blkno;␊ |
465 | ␊ |
466 | ␉␉␉// Load extended partition table.␊ |
467 | ␊ |
468 | ␉␉␉if ( readBootSector( biosdev, blkno, 0 ) == 0 )␊ |
469 | ␉␉␉{␊ |
470 | ␉␉␉␉sNextPartNo = 0;␊ |
471 | ␉␉␉␉sExtDepth++;␊ |
472 | ␉␉␉␉sExtPart = NULL;␊ |
473 | ␉␉␉␉continue;␊ |
474 | ␉␉␉}␊ |
475 | ␉␉␉// Fall through to part == NULL␊ |
476 | ␉␉}␊ |
477 | ␊ |
478 | ␉␉if ( part == NULL ) break; // Reached end of partition chain.␊ |
479 | ␊ |
480 | ␉␉// Advance to next partition number.␊ |
481 | ␊ |
482 | ␉␉sNextPartNo++;␊ |
483 | ␊ |
484 | ␉␉if ( isExtendedFDiskPartition(part) )␊ |
485 | ␉␉{␊ |
486 | ␉␉␉sExtPart = part;␊ |
487 | ␉␉␉continue;␊ |
488 | ␉␉}␊ |
489 | ␊ |
490 | ␉␉// Skip empty slots.␊ |
491 | ␊ |
492 | ␉␉if ( part->systid == 0x00 )␊ |
493 | ␉␉{␊ |
494 | ␉␉␉continue;␊ |
495 | ␉␉}␊ |
496 | ␊ |
497 | ␉␉// Change relative offset to an absolute offset.␊ |
498 | ␉␉part->relsect += sExtBase;␊ |
499 | ␊ |
500 | ␉␉*outPart = part;␊ |
501 | ␉␉*partno = sExtDepth ? (int)(sExtDepth + FDISK_NPART) : sNextPartNo;␊ |
502 | ␊ |
503 | ␉␉break;␊ |
504 | ␉}␊ |
505 | ␊ |
506 | ␉return (part != NULL);␊ |
507 | }␊ |
508 | ␊ |
509 | //==========================================================================␊ |
510 | ␊ |
511 | static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff,␊ |
512 | const struct fdisk_part * part,␊ |
513 | FSInit initFunc, FSLoadFile loadFunc,␊ |
514 | FSReadFile readFunc,␊ |
515 | FSGetDirEntry getdirFunc,␊ |
516 | FSGetFileBlock getBlockFunc,␊ |
517 | FSGetUUID getUUIDFunc,␊ |
518 | BVGetDescription getDescriptionFunc,␊ |
519 | BVFree bvFreeFunc,␊ |
520 | int probe, int type, unsigned int bvrFlags )␊ |
521 | {␊ |
522 | ␉BVRef bvr = (BVRef) malloc( sizeof(*bvr) );␊ |
523 | ␉if ( bvr )␊ |
524 | ␉{␊ |
525 | ␉␉bzero(bvr, sizeof(*bvr));␊ |
526 | ␊ |
527 | ␉␉bvr->biosdev = biosdev;␊ |
528 | ␉␉bvr->part_no = partno;␊ |
529 | ␉␉bvr->part_boff = blkoff;␊ |
530 | ␉␉bvr->part_type = part->systid;␊ |
531 | ␉␉bvr->fs_loadfile = loadFunc;␊ |
532 | ␉␉bvr->fs_readfile = readFunc;␊ |
533 | ␉␉bvr->fs_getdirentry = getdirFunc;␊ |
534 | ␉␉bvr->fs_getfileblock= getBlockFunc;␊ |
535 | ␉␉bvr->fs_getuuid = getUUIDFunc;␊ |
536 | ␉␉bvr->description = getDescriptionFunc;␊ |
537 | ␉␉bvr->type = type;␊ |
538 | ␉␉bvr->bv_free = bvFreeFunc;␊ |
539 | ␊ |
540 | ␉␉if ((part->bootid & FDISK_ACTIVE) && (part->systid == FDISK_HFS))␊ |
541 | ␉␉{␊ |
542 | ␉␉␉bvr->flags |= kBVFlagPrimary;␊ |
543 | ␉␉}␊ |
544 | ␉␉␊ |
545 | // Probe the filesystem.␊ |
546 | ␊ |
547 | if ( initFunc )␊ |
548 | {␊ |
549 | bvr->flags |= kBVFlagNativeBoot;␊ |
550 | ␊ |
551 | if ( probe && initFunc( bvr ) != 0 )␊ |
552 | {␊ |
553 | // filesystem probe failed.␊ |
554 | ␊ |
555 | DEBUG_DISK(("%s: failed probe on dev %x part %d\n", __FUNCTION__, biosdev, partno));␊ |
556 | ␊ |
557 | (*bvr->bv_free)(bvr);␊ |
558 | bvr = NULL;␊ |
559 | }␊ |
560 | if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
561 | {␊ |
562 | ␉bvr->flags |= kBVFlagBootable;␊ |
563 | }␊ |
564 | }␊ |
565 | else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
566 | {␊ |
567 | bvr->flags |= kBVFlagForeignBoot;␊ |
568 | }␊ |
569 | else␊ |
570 | {␊ |
571 | (*bvr->bv_free)(bvr);␊ |
572 | bvr = NULL;␊ |
573 | }␊ |
574 | }␊ |
575 | ␊ |
576 | ␉if (bvr) bvr->flags |= bvrFlags;␊ |
577 | ␉{␊ |
578 | ␉␉return bvr;␊ |
579 | ␉}␊ |
580 | }␊ |
581 | ␊ |
582 | //==========================================================================␊ |
583 | ␊ |
584 | BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff,␊ |
585 | const DPME * part,␊ |
586 | FSInit initFunc, FSLoadFile loadFunc,␊ |
587 | FSReadFile readFunc,␊ |
588 | FSGetDirEntry getdirFunc,␊ |
589 | FSGetFileBlock getBlockFunc,␊ |
590 | FSGetUUID getUUIDFunc,␊ |
591 | BVGetDescription getDescriptionFunc,␊ |
592 | BVFree bvFreeFunc,␊ |
593 | int probe, int type, unsigned int bvrFlags )␊ |
594 | {␊ |
595 | BVRef bvr = (BVRef) malloc( sizeof(*bvr) );␊ |
596 | if ( bvr )␊ |
597 | {␊ |
598 | bzero(bvr, sizeof(*bvr));␊ |
599 | ␊ |
600 | bvr->biosdev = biosdev;␊ |
601 | bvr->part_no = partno;␊ |
602 | bvr->part_boff = blkoff;␊ |
603 | bvr->fs_loadfile = loadFunc;␊ |
604 | bvr->fs_readfile = readFunc;␊ |
605 | bvr->fs_getdirentry = getdirFunc;␊ |
606 | bvr->fs_getfileblock= getBlockFunc;␊ |
607 | bvr->fs_getuuid = getUUIDFunc;␊ |
608 | bvr->description = getDescriptionFunc;␊ |
609 | bvr->type = type;␊ |
610 | bvr->bv_free = bvFreeFunc;␊ |
611 | strlcpy(bvr->name, part->dpme_name, DPISTRLEN);␊ |
612 | strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN);␊ |
613 | ␊ |
614 | /*␊ |
615 | if ( part->bootid & FDISK_ACTIVE )␊ |
616 | bvr->flags |= kBVFlagPrimary;␊ |
617 | */␊ |
618 | ␊ |
619 | // Probe the filesystem.␊ |
620 | ␊ |
621 | if ( initFunc )␊ |
622 | {␊ |
623 | bvr->flags |= kBVFlagNativeBoot | kBVFlagBootable | kBVFlagSystemVolume;␊ |
624 | ␊ |
625 | if ( probe && initFunc( bvr ) != 0 )␊ |
626 | {␊ |
627 | // filesystem probe failed.␊ |
628 | ␊ |
629 | DEBUG_DISK(("%s: failed probe on dev %x part %d\n", __FUNCTION__, biosdev, partno));␊ |
630 | ␊ |
631 | (*bvr->bv_free)(bvr);␊ |
632 | bvr = NULL;␊ |
633 | }␊ |
634 | }␊ |
635 | /*␊ |
636 | else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
637 | {␊ |
638 | bvr->flags |= kBVFlagForeignBoot;␊ |
639 | }␊ |
640 | */␊ |
641 | else␊ |
642 | {␊ |
643 | (*bvr->bv_free)(bvr);␊ |
644 | bvr = NULL;␊ |
645 | }␊ |
646 | }␊ |
647 | if (bvr) bvr->flags |= bvrFlags;␊ |
648 | return bvr;␊ |
649 | }␊ |
650 | ␊ |
651 | //==========================================================================␊ |
652 | ␊ |
653 | // GUID's in LE form:␊ |
654 | // http://en.wikipedia.org/wiki/GUID_Partition_Table␊ |
655 | // 00000000-0000-0000-0000-000000000000 - Unused Entry partition ␊ |
656 | // 024DEE41-33E7-11D3-9D69-0008C781F39F - MBR partition scheme ␊ |
657 | // C12A7328-F81F-11D2-BA4B-00A0C93EC93B - turbo - or an EFI System Partition␊ |
658 | EFI_GUID const GPT_EFISYS_GUID␉ = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } };␊ |
659 | // 21686148-6449-6E6F-744E-656564454649 - BIOS Boot partition ␊ |
660 | // E3C9E316-0B5C-4DB8-817D-F92DF00215AE - Microsoft Reserved Partition ␊ |
661 | EFI_GUID const GPT_BASICDATA2_GUID = { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } };␊ |
662 | // EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 - zef - Basic Data Partition - for foreign OS support␊ |
663 | EFI_GUID const GPT_BASICDATA_GUID = { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } };␊ |
664 | // 5808C8AA-7E8F-42E0-85D2-E1E90434CFB3 - Logical Disk Manager metadata partition␊ |
665 | // AF9B60A0-1431-4F62-BC68-3311714A69AD - Logical Disk Manager data partition␊ |
666 | // DE94BBA4-06D1-4D40-A16A-BFD50179D6AC - Windows Recovery Environment␊ |
667 | // 48465300-0000-11AA-AA11-00306543ECAC - Hierarchical File System Plus (HFS+) partition␊ |
668 | EFI_GUID const GPT_HFS_GUID␉␉ = { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };␊ |
669 | // 55465300-0000-11AA-AA11-00306543ECAC - Apple UFS ␊ |
670 | // 52414944-0000-11AA-AA11-00306543ECAC - Apple RAID partition␊ |
671 | // 426F6F74-0000-11AA-AA11-00306543ECAC - turbo - Apple Boot Partition␊ |
672 | EFI_GUID const GPT_BOOT_GUID␉ = { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };␊ |
673 | // 4C616265-6C00-11AA-AA11-00306543ECAC - Apple Label␊ |
674 | // 5265636F-7665-11AA-AA11-00306543ECAC - Apple TV Recovery partition␊ |
675 | // 53746F72-6167-11AA-AA11-00306543ECAC - Apple Core Storage (i.e. Lion FileVault) partition (Apple_Boot Recovery HD)␊ |
676 | // EFI_GUID const GPT_RECOVERY_GUID␉ = { 0x53746F72, 0x6167, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };␊ |
677 | ␊ |
678 | BVRef newGPTBVRef( int biosdev, int partno, unsigned int blkoff,␊ |
679 | const gpt_ent * part,␊ |
680 | FSInit initFunc, FSLoadFile loadFunc,␊ |
681 | FSReadFile readFunc,␊ |
682 | FSGetDirEntry getdirFunc,␊ |
683 | FSGetFileBlock getBlockFunc,␊ |
684 | FSGetUUID getUUIDFunc,␊ |
685 | BVGetDescription getDescriptionFunc,␊ |
686 | BVFree bvFreeFunc,␊ |
687 | int probe, int type, unsigned int bvrFlags )␊ |
688 | {␊ |
689 | BVRef bvr = (BVRef) malloc( sizeof(*bvr) );␊ |
690 | if ( bvr )␊ |
691 | {␊ |
692 | bzero(bvr, sizeof(*bvr));␊ |
693 | ␊ |
694 | bvr->biosdev = biosdev;␊ |
695 | bvr->part_no = partno;␊ |
696 | bvr->part_boff = blkoff;␊ |
697 | bvr->fs_loadfile = loadFunc;␊ |
698 | bvr->fs_readfile = readFunc;␊ |
699 | bvr->fs_getdirentry = getdirFunc;␊ |
700 | bvr->fs_getfileblock= getBlockFunc;␊ |
701 | bvr->fs_getuuid = getUUIDFunc;␊ |
702 | bvr->description = getDescriptionFunc;␊ |
703 | ␉bvr->type = type;␊ |
704 | bvr->bv_free = bvFreeFunc;␊ |
705 | // FIXME: UCS-2 -> UTF-8 the name␊ |
706 | strlcpy(bvr->name, "----", DPISTRLEN);␊ |
707 | if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)part->ent_type) == 0) ||␊ |
708 | (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)part->ent_type) == 0) )␊ |
709 | strlcpy(bvr->type_name, "GPT HFS+", DPISTRLEN);␊ |
710 | else␊ |
711 | strlcpy(bvr->type_name, "GPT Unknown", DPISTRLEN);␊ |
712 | ␊ |
713 | /*␊ |
714 | if ( part->bootid & FDISK_ACTIVE )␊ |
715 | bvr->flags |= kBVFlagPrimary;␊ |
716 | */␊ |
717 | ␊ |
718 | // Probe the filesystem.␊ |
719 | ␊ |
720 | if ( initFunc )␊ |
721 | {␊ |
722 | bvr->flags |= kBVFlagNativeBoot;␊ |
723 | ␊ |
724 | if ( probe && initFunc( bvr ) != 0 )␊ |
725 | {␊ |
726 | // filesystem probe failed.␊ |
727 | ␊ |
728 | DEBUG_DISK(("%s: failed probe on dev %x part %d\n",␊ |
729 | __FUNCTION__, biosdev, partno));␊ |
730 | ␊ |
731 | (*bvr->bv_free)(bvr);␊ |
732 | bvr = NULL;␊ |
733 | }␊ |
734 | if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
735 | {␊ |
736 | ␉bvr->flags |= kBVFlagBootable;␊ |
737 | }␊ |
738 | }␊ |
739 | else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )␊ |
740 | {␊ |
741 | bvr->flags |= kBVFlagForeignBoot;␊ |
742 | }␊ |
743 | else␊ |
744 | {␊ |
745 | (*bvr->bv_free)(bvr);␊ |
746 | bvr = NULL;␊ |
747 | }␊ |
748 | }␊ |
749 | if (bvr) bvr->flags |= bvrFlags;␊ |
750 | return bvr;␊ |
751 | }␊ |
752 | ␊ |
753 | //==========================================================================␊ |
754 | ␊ |
755 | /* A note on partition numbers:␊ |
756 | * IOKit makes the primary partitions numbers 1-4, and then␊ |
757 | * extended partitions are numbered consecutively 5 and up.␊ |
758 | * So, for example, if you have two primary partitions and␊ |
759 | * one extended partition they will be numbered 1, 2, 5.␊ |
760 | */␊ |
761 | ␊ |
762 | static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )␊ |
763 | {␊ |
764 | const struct fdisk_part * part;␊ |
765 | struct DiskBVMap * map;␊ |
766 | int partno = -1;␊ |
767 | BVRef bvr;␊ |
768 | #if UFS_SUPPORT␊ |
769 | BVRef booterUFS = NULL;␊ |
770 | #endif␊ |
771 | int spc;␊ |
772 | struct driveInfo di;␊ |
773 | boot_drive_info_t *dp;␊ |
774 | ␊ |
775 | /* Initialize disk info */␊ |
776 | if (getDriveInfo(biosdev, &di) != 0) {␊ |
777 | ␉return NULL;␊ |
778 | }␊ |
779 | dp = &di.di;␊ |
780 | spc = (dp->params.phys_spt * dp->params.phys_heads);␊ |
781 | if (spc == 0) {␊ |
782 | ␉/* This is probably a CD-ROM; punt on the geometry. */␊ |
783 | ␉spc = 1;␊ |
784 | }␊ |
785 | ␊ |
786 | do {␊ |
787 | // Create a new mapping.␊ |
788 | ␊ |
789 | map = (struct DiskBVMap *) malloc( sizeof(*map) );␊ |
790 | if ( map )␊ |
791 | {␊ |
792 | map->biosdev = biosdev;␊ |
793 | map->bvr = NULL;␊ |
794 | map->bvrcnt = 0;␊ |
795 | map->next = gDiskBVMap;␊ |
796 | gDiskBVMap = map;␊ |
797 | ␊ |
798 | // Create a record for each partition found on the disk.␊ |
799 | ␊ |
800 | while ( getNextFDiskPartition( biosdev, &partno, &part ) )␊ |
801 | {␊ |
802 | DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,␊ |
803 | partno, part->systid));␊ |
804 | bvr = 0;␊ |
805 | ␊ |
806 | switch ( part->systid )␊ |
807 | {␊ |
808 | #if UFS_SUPPORT␊ |
809 | case FDISK_UFS:␊ |
810 | bvr = newFDiskBVRef(␊ |
811 | biosdev, partno,␊ |
812 | part->relsect + UFS_FRONT_PORCH/BPS,␊ |
813 | part,␊ |
814 | UFSInitPartition,␊ |
815 | UFSLoadFile,␊ |
816 | UFSReadFile,␊ |
817 | UFSGetDirEntry,␊ |
818 | UFSGetFileBlock,␊ |
819 | UFSGetUUID,␊ |
820 | UFSGetDescription,␊ |
821 | UFSFree,␊ |
822 | 0,␊ |
823 | kBIOSDevTypeHardDrive, 0);␊ |
824 | break;␊ |
825 | #endif␊ |
826 | ␊ |
827 | case FDISK_HFS:␊ |
828 | bvr = newFDiskBVRef(␊ |
829 | biosdev, partno,␊ |
830 | part->relsect,␊ |
831 | part,␊ |
832 | HFSInitPartition,␊ |
833 | HFSLoadFile,␊ |
834 | HFSReadFile,␊ |
835 | HFSGetDirEntry,␊ |
836 | HFSGetFileBlock,␊ |
837 | HFSGetUUID,␊ |
838 | HFSGetDescription,␊ |
839 | HFSFree,␊ |
840 | 0,␊ |
841 | kBIOSDevTypeHardDrive, 0);␊ |
842 | break;␊ |
843 | ␊ |
844 | // turbo - we want the booter type scanned also␊ |
845 | case FDISK_BOOTER:␊ |
846 | if (part->bootid & FDISK_ACTIVE)␊ |
847 | gBIOSBootVolume = newFDiskBVRef(␊ |
848 | biosdev, partno,␊ |
849 | part->relsect,␊ |
850 | part,␊ |
851 | HFSInitPartition,␊ |
852 | HFSLoadFile,␊ |
853 | HFSReadFile,␊ |
854 | HFSGetDirEntry,␊ |
855 | HFSGetFileBlock,␊ |
856 | HFSGetUUID,␊ |
857 | HFSGetDescription,␊ |
858 | HFSFree,␊ |
859 | 0,␊ |
860 | kBIOSDevTypeHardDrive, 0);␊ |
861 | break;␊ |
862 | ␊ |
863 | #if UFS_SUPPORT␊ |
864 | case FDISK_BOOTER:␊ |
865 | booterUFS = newFDiskBVRef(␊ |
866 | biosdev, partno,␊ |
867 | ((part->relsect + spc - 1) / spc) * spc,␊ |
868 | part,␊ |
869 | UFSInitPartition,␊ |
870 | UFSLoadFile,␊ |
871 | UFSReadFile,␊ |
872 | UFSGetDirEntry,␊ |
873 | UFSGetFileBlock,␊ |
874 | UFSGetUUID,␊ |
875 | UFSGetDescription,␊ |
876 | UFSFree,␊ |
877 | 0,␊ |
878 | kBIOSDevTypeHardDrive, 0);␊ |
879 | break;␊ |
880 | #endif␊ |
881 | ␊ |
882 | case FDISK_FAT32:␊ |
883 | case FDISK_DOS12:␊ |
884 | case FDISK_DOS16S:␊ |
885 | case FDISK_DOS16B:␊ |
886 | case FDISK_SMALLFAT32:␊ |
887 | case FDISK_DOS16SLBA:␊ |
888 | bvr = newFDiskBVRef(␊ |
889 | biosdev, partno,␊ |
890 | part->relsect,␊ |
891 | part,␊ |
892 | MSDOSInitPartition,␊ |
893 | MSDOSLoadFile,␊ |
894 | MSDOSReadFile,␊ |
895 | MSDOSGetDirEntry,␊ |
896 | MSDOSGetFileBlock,␊ |
897 | MSDOSGetUUID,␊ |
898 | MSDOSGetDescription,␊ |
899 | MSDOSFree,␊ |
900 | 0,␊ |
901 | kBIOSDevTypeHardDrive, 0);␊ |
902 | break;␊ |
903 | ␉␉␉␉␉␉␊ |
904 | case FDISK_NTFS:␊ |
905 | bvr = newFDiskBVRef(␊ |
906 | biosdev, partno,␊ |
907 | part->relsect,␊ |
908 | part,␊ |
909 | 0, 0, 0, 0, 0,␊ |
910 | NTFSGetUUID,␊ |
911 | NTFSGetDescription,␊ |
912 | (BVFree)free,␊ |
913 | 0, kBIOSDevTypeHardDrive, 0);␊ |
914 | break;␊ |
915 | ␊ |
916 | case FDISK_LINUX:␊ |
917 | bvr = newFDiskBVRef(␊ |
918 | biosdev, partno,␊ |
919 | part->relsect,␊ |
920 | part,␊ |
921 | 0, 0, 0, 0, 0,␊ |
922 | EX2GetUUID,␊ |
923 | EX2GetDescription,␊ |
924 | (BVFree)free,␊ |
925 | 0, kBIOSDevTypeHardDrive, 0);␊ |
926 | break;␊ |
927 | ␊ |
928 | case FDISK_BEFS:␊ |
929 | bvr = newFDiskBVRef(␊ |
930 | biosdev, partno,␊ |
931 | part->relsect,␊ |
932 | part,␊ |
933 | 0, 0, 0, 0, 0, 0,␊ |
934 | BeFSGetDescription,␊ |
935 | (BVFree)free,␊ |
936 | 0, kBIOSDevTypeHardDrive, 0);␊ |
937 | break;␊ |
938 | ␊ |
939 | case FDISK_FREEBSD:␊ |
940 | bvr = newFDiskBVRef(␊ |
941 | biosdev, partno,␊ |
942 | part->relsect,␊ |
943 | part,␊ |
944 | 0, 0, 0, 0, 0, 0,␊ |
945 | FreeBSDGetDescription,␊ |
946 | (BVFree)free,␊ |
947 | 0, kBIOSDevTypeHardDrive, 0);␊ |
948 | break;␊ |
949 | ␊ |
950 | case FDISK_OPENBSD:␊ |
951 | bvr = newFDiskBVRef(␊ |
952 | biosdev, partno,␊ |
953 | part->relsect,␊ |
954 | part,␊ |
955 | 0, 0, 0, 0, 0, 0,␊ |
956 | OpenBSDGetDescription,␊ |
957 | (BVFree)free,␊ |
958 | 0, kBIOSDevTypeHardDrive, 0);␊ |
959 | break;␊ |
960 | ␊ |
961 | default:␊ |
962 | bvr = newFDiskBVRef(␊ |
963 | biosdev, partno,␊ |
964 | part->relsect,␊ |
965 | part,␊ |
966 | 0, 0, 0, 0, 0, 0, 0,␊ |
967 | (BVFree)free,␊ |
968 | 0,␊ |
969 | kBIOSDevTypeHardDrive, 0);␊ |
970 | break;␊ |
971 | }␊ |
972 | ␊ |
973 | if ( bvr )␊ |
974 | {␊ |
975 | bvr->next = map->bvr;␊ |
976 | map->bvr = bvr;␊ |
977 | map->bvrcnt++;␊ |
978 | }␊ |
979 | }␊ |
980 | ␊ |
981 | #if UFS_SUPPORT␊ |
982 | // Booting from a CD with an UFS filesystem embedded␊ |
983 | // in a booter partition.␊ |
984 | ␊ |
985 | if ( booterUFS )␊ |
986 | {␊ |
987 | if ( map->bvrcnt == 0 )␊ |
988 | {␊ |
989 | map->bvr = booterUFS;␊ |
990 | map->bvrcnt++;␊ |
991 | }␊ |
992 | else free( booterUFS );␊ |
993 | }␊ |
994 | #endif␊ |
995 | }␊ |
996 | } while (0);␊ |
997 | ␊ |
998 | /*␊ |
999 | * If no FDisk partition, then we will check for␊ |
1000 | * an Apple partition map elsewhere.␊ |
1001 | */␊ |
1002 | #if UNUSED␊ |
1003 | if (map->bvrcnt == 0) {␊ |
1004 | ␉static struct fdisk_part cdpart;␊ |
1005 | ␉cdpart.systid = 0xCD;␊ |
1006 | ␊ |
1007 | ␉/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */␊ |
1008 | ␉bvr = newFDiskBVRef(␊ |
1009 | ␉␉␉ biosdev, 0,␊ |
1010 | ␉␉␉ 0,␊ |
1011 | ␉␉␉ &cdpart,␊ |
1012 | ␉␉␉ HFSInitPartition,␊ |
1013 | ␉␉␉ HFSLoadFile,␊ |
1014 | HFSReadFile,␊ |
1015 | ␉␉␉ HFSGetDirEntry,␊ |
1016 | HFSGetFileBlock,␊ |
1017 | HFSGetUUID,␊ |
1018 | ␉␉␉ 0,␊ |
1019 | ␉␉␉ kBIOSDevTypeHardDrive);␊ |
1020 | ␉bvr->next = map->bvr;␊ |
1021 | ␉map->bvr = bvr;␊ |
1022 | ␉map->bvrcnt++;␊ |
1023 | }␊ |
1024 | #endif␊ |
1025 | // Actually this should always be true given the above code␊ |
1026 | if(map == gDiskBVMap)␊ |
1027 | {␊ |
1028 | // Don't leave a null map in the chain␊ |
1029 | if(map->bvrcnt == 0 && map->bvr == NULL)␊ |
1030 | {␊ |
1031 | gDiskBVMap = map->next;␊ |
1032 | free(map);␊ |
1033 | map = NULL;␊ |
1034 | }␊ |
1035 | }␊ |
1036 | ␊ |
1037 | if (countPtr) *countPtr = map ? map->bvrcnt : 0;␊ |
1038 | ␊ |
1039 | return map ? map->bvr : NULL;␊ |
1040 | }␊ |
1041 | ␊ |
1042 | //==========================================================================␊ |
1043 | ␊ |
1044 | static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )␊ |
1045 | {␊ |
1046 | struct DiskBVMap * map;␊ |
1047 | struct Block0 *block0_p;␊ |
1048 | unsigned int blksize;␊ |
1049 | unsigned int factor;␊ |
1050 | void *buffer = malloc(BPS);␊ |
1051 | ␊ |
1052 | /* Check for alternate block size */␊ |
1053 | if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {␊ |
1054 | return NULL;␊ |
1055 | }␊ |
1056 | block0_p = buffer;␊ |
1057 | if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {␊ |
1058 | blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);␊ |
1059 | if (blksize != BPS) {␊ |
1060 | free(buffer);␊ |
1061 | buffer = malloc(blksize);␊ |
1062 | }␊ |
1063 | factor = blksize / BPS;␊ |
1064 | } else {␊ |
1065 | blksize = BPS;␊ |
1066 | factor = 1;␊ |
1067 | }␊ |
1068 | ␊ |
1069 | do {␊ |
1070 | // Create a new mapping.␊ |
1071 | ␊ |
1072 | map = (struct DiskBVMap *) malloc( sizeof(*map) );␊ |
1073 | if ( map )␊ |
1074 | {␊ |
1075 | int error;␊ |
1076 | DPME *dpme_p = (DPME *)buffer;␊ |
1077 | UInt32 i, npart = UINT_MAX;␊ |
1078 | BVRef bvr;␊ |
1079 | ␊ |
1080 | map->biosdev = biosdev;␊ |
1081 | map->bvr = NULL;␊ |
1082 | map->bvrcnt = 0;␊ |
1083 | map->next = gDiskBVMap;␊ |
1084 | gDiskBVMap = map;␊ |
1085 | ␊ |
1086 | for (i=0; i<npart; i++) {␊ |
1087 | error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );␊ |
1088 | ␊ |
1089 | if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {␊ |
1090 | break;␊ |
1091 | }␊ |
1092 | ␊ |
1093 | if (i==0) {␊ |
1094 | npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);␊ |
1095 | }␊ |
1096 | /*␊ |
1097 | printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",␊ |
1098 | dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",␊ |
1099 | dpme.dpme_pblock_start, dpme.dpme_pblocks,␊ |
1100 | dpme.dpme_lblock_start, dpme.dpme_lblocks,␊ |
1101 | dpme.dpme_boot_block);␊ |
1102 | */␊ |
1103 | ␊ |
1104 | if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {␊ |
1105 | bvr = newAPMBVRef(biosdev,␊ |
1106 | i,␊ |
1107 | OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,␊ |
1108 | dpme_p,␊ |
1109 | HFSInitPartition,␊ |
1110 | HFSLoadFile,␊ |
1111 | HFSReadFile,␊ |
1112 | HFSGetDirEntry,␊ |
1113 | HFSGetFileBlock,␊ |
1114 | HFSGetUUID,␊ |
1115 | HFSGetDescription,␊ |
1116 | HFSFree,␊ |
1117 | 0,␊ |
1118 | kBIOSDevTypeHardDrive, 0);␊ |
1119 | bvr->next = map->bvr;␊ |
1120 | map->bvr = bvr;␊ |
1121 | map->bvrcnt++;␊ |
1122 | }␊ |
1123 | }␊ |
1124 | }␊ |
1125 | } while (0);␊ |
1126 | ␊ |
1127 | free(buffer);␊ |
1128 | ␊ |
1129 | if (countPtr) *countPtr = map ? map->bvrcnt : 0;␊ |
1130 | ␊ |
1131 | return map ? map->bvr : NULL;␊ |
1132 | }␊ |
1133 | ␊ |
1134 | //==========================================================================␊ |
1135 | ␊ |
1136 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -␊ |
1137 | ␊ |
1138 | /*␊ |
1139 | * Trying to figure out the filsystem type of a given partition.␊ |
1140 | */␊ |
1141 | static int probeFileSystem(int biosdev, unsigned int blkoff)␊ |
1142 | {␊ |
1143 | // detected filesystem type;␊ |
1144 | int result = -1;␊ |
1145 | int fatbits;␊ |
1146 | ␊ |
1147 | // Allocating buffer for 4 sectors.␊ |
1148 | const void * probeBuffer = malloc(PROBEFS_SIZE);␊ |
1149 | if (probeBuffer == NULL)␊ |
1150 | goto exit;␊ |
1151 | ␊ |
1152 | // Reading first 4 sectors of current partition␊ |
1153 | int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);␊ |
1154 | if (error)␊ |
1155 | goto exit;␊ |
1156 | ␊ |
1157 | if (HFSProbe(probeBuffer))␊ |
1158 | result = FDISK_HFS;␊ |
1159 | else if (EX2Probe(probeBuffer))␊ |
1160 | ␉ result = FDISK_LINUX;␊ |
1161 | else if (FreeBSDProbe(probeBuffer))␊ |
1162 | ␉ result = FDISK_FREEBSD;␊ |
1163 | else if (OpenBSDProbe(probeBuffer))␊ |
1164 | ␉ result = FDISK_OPENBSD;␊ |
1165 | else if (NTFSProbe(probeBuffer))␊ |
1166 | result = FDISK_NTFS;␊ |
1167 | else if (BeFSProbe(probeBuffer))␊ |
1168 | result = FDISK_BEFS;␊ |
1169 | else if ( (fatbits = MSDOSProbe(probeBuffer)) )␊ |
1170 | {␊ |
1171 | ␉ switch (fatbits)␊ |
1172 | ␉ {␊ |
1173 | ␉␉ case 32:␊ |
1174 | ␉␉ default:␊ |
1175 | ␉␉␉ result = FDISK_FAT32;␊ |
1176 | ␉␉␉ break;␊ |
1177 | ␉␉ case 16:␊ |
1178 | ␉␉␉ result = FDISK_DOS16B;␊ |
1179 | ␉␉␉ break;␊ |
1180 | ␉␉ case 12:␊ |
1181 | ␉␉␉ result = FDISK_DOS12;␊ |
1182 | ␉␉␉ break;␉␉␉ ␊ |
1183 | ␉ }␊ |
1184 | }␊ |
1185 | else␊ |
1186 | // Couldn't detect filesystem type␊ |
1187 | result = 0;␊ |
1188 | ␊ |
1189 | exit:␊ |
1190 | if (probeBuffer != NULL) free((void *)probeBuffer);␊ |
1191 | return result;␊ |
1192 | }␊ |
1193 | ␊ |
1194 | static bool isPartitionUsed(gpt_ent * partition)␊ |
1195 | {␊ |
1196 | //␊ |
1197 | // Ask whether the given partition is used.␊ |
1198 | //␊ |
1199 | ␊ |
1200 | return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;␊ |
1201 | }␊ |
1202 | ␊ |
1203 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -␊ |
1204 | ␊ |
1205 | static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr )␊ |
1206 | {␊ |
1207 | struct DiskBVMap * map = NULL;␊ |
1208 | void *buffer = malloc(BPS);␊ |
1209 | int error;␊ |
1210 | if ( (error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer )) != 0) {␊ |
1211 | verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);␊ |
1212 | goto scanErr;␊ |
1213 | }␊ |
1214 | struct REAL_disk_blk0 *fdiskMap = buffer;␊ |
1215 | if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )␊ |
1216 | {␊ |
1217 | verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);␊ |
1218 | goto scanErr;␊ |
1219 | }␊ |
1220 | ␊ |
1221 | int fdiskID = 0;␊ |
1222 | unsigned index;␊ |
1223 | for ( index = 0; index < FDISK_NPART; index++ )␊ |
1224 | {␊ |
1225 | if ( fdiskMap->parts[index].systid )␊ |
1226 | {␊ |
1227 | if ( fdiskMap->parts[index].systid == 0xEE )␊ |
1228 | {␊ |
1229 | // Fail if two 0xEE partitions are present which␊ |
1230 | // means the FDISK code will wind up parsing it.␊ |
1231 | if ( fdiskID ) goto scanErr;␊ |
1232 | ␊ |
1233 | fdiskID = index + 1;␊ |
1234 | }␊ |
1235 | }␊ |
1236 | }␊ |
1237 | ␊ |
1238 | if ( fdiskID == 0 ) goto scanErr;␊ |
1239 | verbose("Attempting to read GPT\n");␊ |
1240 | ␊ |
1241 | if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)␊ |
1242 | goto scanErr;␊ |
1243 | ␊ |
1244 | gpt_hdr *headerMap = buffer;␊ |
1245 | ␊ |
1246 | // Determine whether the partition header signature is present.␊ |
1247 | ␊ |
1248 | if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )␊ |
1249 | {␊ |
1250 | goto scanErr;␊ |
1251 | }␊ |
1252 | ␊ |
1253 | // Determine whether the partition header size is valid.␊ |
1254 | ␊ |
1255 | UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);␊ |
1256 | UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);␊ |
1257 | ␊ |
1258 | if ( headerSize < offsetof(gpt_hdr, padding) )␊ |
1259 | {␊ |
1260 | goto scanErr;␊ |
1261 | }␊ |
1262 | ␊ |
1263 | if ( headerSize > BPS )␊ |
1264 | {␊ |
1265 | goto scanErr;␊ |
1266 | }␊ |
1267 | ␊ |
1268 | // Determine whether the partition header checksum is valid.␊ |
1269 | ␊ |
1270 | headerMap->hdr_crc_self = 0;␊ |
1271 | ␊ |
1272 | if ( crc32(0, headerMap, headerSize) != headerCheck )␊ |
1273 | {␊ |
1274 | goto scanErr;␊ |
1275 | }␊ |
1276 | ␊ |
1277 | // Determine whether the partition entry size is valid.␊ |
1278 | ␊ |
1279 | UInt64 gptBlock = 0;␊ |
1280 | UInt32 gptCheck = 0;␊ |
1281 | UInt32 gptCount = 0;␊ |
1282 | UInt32 gptID = 0;␊ |
1283 | gpt_ent * gptMap = 0;␊ |
1284 | UInt32 gptSize = 0;␊ |
1285 | ␊ |
1286 | gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);␊ |
1287 | gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);␊ |
1288 | gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);␊ |
1289 | gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);␊ |
1290 | ␊ |
1291 | if ( gptSize < sizeof(gpt_ent) )␊ |
1292 | {␊ |
1293 | goto scanErr;␊ |
1294 | }␊ |
1295 | ␊ |
1296 | // Allocate a buffer large enough to hold one map, rounded to a media block.␊ |
1297 | free(buffer);␊ |
1298 | buffer = NULL;␊ |
1299 | ␊ |
1300 | UInt32 bufferSize = IORound(gptCount * gptSize, BPS);␊ |
1301 | if(bufferSize == 0)␊ |
1302 | goto scanErr;␊ |
1303 | buffer = malloc(bufferSize);␊ |
1304 | ␊ |
1305 | if(readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)␊ |
1306 | goto scanErr;␊ |
1307 | ␊ |
1308 | verbose("Read GPT\n");␊ |
1309 | ␊ |
1310 | // Allocate a new map for this BIOS device and insert it into the chain␊ |
1311 | map = malloc(sizeof(*map));␊ |
1312 | map->biosdev = biosdev;␊ |
1313 | map->bvr = NULL;␊ |
1314 | map->bvrcnt = 0;␊ |
1315 | map->next = gDiskBVMap;␊ |
1316 | gDiskBVMap = map;␊ |
1317 | ␊ |
1318 | // fdisk like partition type id.␊ |
1319 | int fsType = 0;␊ |
1320 | ␊ |
1321 | for(gptID = 1; gptID <= gptCount; ++gptID)␊ |
1322 | {␊ |
1323 | ␉␉␉␉BVRef bvr = NULL;␊ |
1324 | ␉␉␉␉unsigned int bvrFlags = 0;␊ |
1325 | ␊ |
1326 | // size on disk can be larger than sizeof(gpt_ent)␊ |
1327 | gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );␊ |
1328 | ␊ |
1329 | // NOTE: EFI_GUID's are in LE and we know we're on an x86.␊ |
1330 | // The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.␊ |
1331 | ␊ |
1332 | if (isPartitionUsed(gptMap))␊ |
1333 | {␊ |
1334 | char stringuuid[100];␊ |
1335 | efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);␊ |
1336 | verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);␊ |
1337 | ␊ |
1338 | // Getting fdisk like partition type.␊ |
1339 | fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);␊ |
1340 | ␊ |
1341 | if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||␊ |
1342 | (efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )␊ |
1343 | {␊ |
1344 | bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;␊ |
1345 | bvr = newGPTBVRef(biosdev,␊ |
1346 | gptID,␊ |
1347 | gptMap->ent_lba_start,␊ |
1348 | gptMap,␊ |
1349 | HFSInitPartition,␊ |
1350 | HFSLoadFile,␊ |
1351 | HFSReadFile,␊ |
1352 | HFSGetDirEntry,␊ |
1353 | HFSGetFileBlock,␊ |
1354 | HFSGetUUID,␊ |
1355 | HFSGetDescription,␊ |
1356 | HFSFree,␊ |
1357 | 0,␊ |
1358 | kBIOSDevTypeHardDrive, bvrFlags);␊ |
1359 | }␊ |
1360 | ␊ |
1361 | ␉␉␉// zef - foreign OS support␊ |
1362 | if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||␊ |
1363 | (efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )␊ |
1364 | {␊ |
1365 | ␉␉␉␉␉␉␉switch (fsType)␊ |
1366 | {␊ |
1367 | ␉␉␉␉␉␉␉ case FDISK_NTFS:␊ |
1368 | ␉␉␉␉␉␉␉ bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
1369 | ␉ ␉␉␉␉␉␉␉␉0, 0, 0, 0, 0, 0, NTFSGetDescription,␊ |
1370 | ␉␉ ␉␉␉␉␉␉␉(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);␊ |
1371 | ␉␉␉␉␉␉␉␉break;␊ |
1372 | ␉␉␉␉␉␉␉ case FDISK_LINUX:␊ |
1373 | ␉␉␉␉␉␉␉ bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
1374 | ␉ ␉␉␉␉␉␉␉␉0, 0, 0, 0, 0, 0, EX2GetDescription,␊ |
1375 | ␉␉ ␉␉␉␉␉␉␉(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);␊ |
1376 | ␉␉␉␉␉␉␉␉break;␊ |
1377 | ␊ |
1378 | default:␊ |
1379 | bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
1380 | 0, 0, 0, 0, 0, 0, 0,␊ |
1381 | (BVFree)free, 0, kBIOSDevTypeHardDrive, 0);␊ |
1382 | break;␊ |
1383 | }␊ |
1384 | ␉␉␉␉␉␉␉ ␊ |
1385 | }␊ |
1386 | ␊ |
1387 | // turbo - save our booter partition␊ |
1388 | // zef - only on original boot device␊ |
1389 | if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )␊ |
1390 | {␊ |
1391 | ␉␉␉␉␉␉␉switch (fsType)␊ |
1392 | {␊ |
1393 | case FDISK_HFS:␊ |
1394 | if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)␊ |
1395 | {␊ |
1396 | bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
1397 | HFSInitPartition,␊ |
1398 | HFSLoadFile,␊ |
1399 | HFSReadFile,␊ |
1400 | HFSGetDirEntry,␊ |
1401 | HFSGetFileBlock,␊ |
1402 | HFSGetUUID,␊ |
1403 | HFSGetDescription,␊ |
1404 | HFSFree,␊ |
1405 | 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);␊ |
1406 | }␊ |
1407 | break;␊ |
1408 | ␊ |
1409 | case FDISK_FAT32:␊ |
1410 | if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)␊ |
1411 | {␊ |
1412 | bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,␊ |
1413 | MSDOSInitPartition,␊ |
1414 | MSDOSLoadFile,␊ |
1415 | MSDOSReadFile,␊ |
1416 | MSDOSGetDirEntry,␊ |
1417 | MSDOSGetFileBlock,␊ |
1418 | MSDOSGetUUID,␊ |
1419 | MSDOSGetDescription,␊ |
1420 | MSDOSFree,␊ |
1421 | 0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);␊ |
1422 | }␊ |
1423 | break;␊ |
1424 | ␊ |
1425 | if (biosdev == gBIOSDev)␊ |
1426 | gBIOSBootVolume = bvr;␊ |
1427 | }␊ |
1428 | } ␊ |
1429 | ␊ |
1430 | ␉␉␉␉␉␉if (bvr)␊ |
1431 | ␉␉␉␉␉␉{␊ |
1432 | // Fixup bvr with the fake fdisk partition type.␊ |
1433 | if (fsType > 0) bvr->part_type = fsType;␊ |
1434 | ␊ |
1435 | ␉␉␉␉␉␉␉bvr->next = map->bvr;␊ |
1436 | ␉␉␉␉␉␉␉map->bvr = bvr;␊ |
1437 | ␉␉␉␉␉␉␉++map->bvrcnt;␊ |
1438 | ␉␉␉␉␉␉}␊ |
1439 | ␊ |
1440 | }␊ |
1441 | }␊ |
1442 | ␊ |
1443 | scanErr:␊ |
1444 | free(buffer);␊ |
1445 | ␊ |
1446 | if(map)␊ |
1447 | {␊ |
1448 | if(countPtr) *countPtr = map->bvrcnt;␊ |
1449 | return map->bvr;␊ |
1450 | }␊ |
1451 | else␊ |
1452 | {␊ |
1453 | if(countPtr) *countPtr = 0;␊ |
1454 | return NULL;␊ |
1455 | }␊ |
1456 | }␊ |
1457 | ␊ |
1458 | static bool getOSVersion(BVRef bvr, char *str)␊ |
1459 | {␊ |
1460 | ␉bool valid = false;␉␊ |
1461 | ␉config_file_t systemVersion;␊ |
1462 | ␉char dirSpec[512];␉␊ |
1463 | ␉␊ |
1464 | ␉sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/SystemVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);␊ |
1465 | ␉␊ |
1466 | ␉if (!loadConfigFile(dirSpec, &systemVersion))␊ |
1467 | ␉{␊ |
1468 | ␉␉valid = true;␊ |
1469 | ␉}␊ |
1470 | ␉else ␊ |
1471 | ␉{␊ |
1472 | ␉␉sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/ServerVersion.plist", BIOS_DEV_UNIT(bvr), bvr->part_no);␊ |
1473 | ␉␉␊ |
1474 | ␉␉if (!loadConfigFile(dirSpec, &systemVersion))␊ |
1475 | ␉␉{␉␊ |
1476 | bvr->OSisServer = true;␊ |
1477 | ␉␉␉valid = true;␊ |
1478 | ␉␉}␉␉␊ |
1479 | ␉}␊ |
1480 | ␉␊ |
1481 | ␉if (valid)␊ |
1482 | ␉{␉␉␊ |
1483 | ␉␉const char *val;␊ |
1484 | ␉␉int len;␊ |
1485 | ␉␉␊ |
1486 | ␉␉if (getValueForKey(kProductVersion, &val, &len, &systemVersion))␊ |
1487 | ␉␉{␊ |
1488 | ␉␉␉// getValueForKey uses const char for val␊ |
1489 | ␉␉␉// so copy it and trim␊ |
1490 | ␉␉␉*str = '\0';␊ |
1491 | ␉␉␉strncat(str, val, MIN(len, 4));␊ |
1492 | ␉␉}␊ |
1493 | ␉␉else␊ |
1494 | ␉␉␉valid = false;␊ |
1495 | ␉}␊ |
1496 | ␉␊ |
1497 | ␉return valid;␊ |
1498 | }␊ |
1499 | ␊ |
1500 | //==========================================================================␊ |
1501 | ␊ |
1502 | static void scanFSLevelBVRSettings(BVRef chain)␊ |
1503 | {␊ |
1504 | BVRef bvr;␊ |
1505 | char dirSpec[512], fileSpec[512];␊ |
1506 | char label[BVSTRLEN];␊ |
1507 | int ret;␊ |
1508 | long flags, time;␊ |
1509 | int fh, fileSize, error;␊ |
1510 | ␊ |
1511 | for (bvr = chain; bvr; bvr = bvr->next)␊ |
1512 | {␊ |
1513 | ret = -1;␊ |
1514 | error = 0;␊ |
1515 | ␊ |
1516 | //␊ |
1517 | // Check for alternate volume label on boot helper partitions.␊ |
1518 | //␊ |
1519 | if (bvr->flags & kBVFlagBooter)␊ |
1520 | {␊ |
1521 | sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);␊ |
1522 | strcpy(fileSpec, ".disk_label.contentDetails");␊ |
1523 | ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);␊ |
1524 | if (!ret)␊ |
1525 | {␊ |
1526 | fh = open(strcat(dirSpec, fileSpec), 0);␊ |
1527 | fileSize = file_size(fh);␊ |
1528 | if (fileSize > 0 && fileSize < BVSTRLEN)␊ |
1529 | {␊ |
1530 | if (read(fh, label, fileSize) != fileSize)␊ |
1531 | error = -1;␊ |
1532 | }␊ |
1533 | else␊ |
1534 | error = -1;␊ |
1535 | ␊ |
1536 | close(fh);␊ |
1537 | ␊ |
1538 | if (!error)␊ |
1539 | {␊ |
1540 | label[fileSize] = '\0';␊ |
1541 | strcpy(bvr->altlabel, label);␊ |
1542 | }␊ |
1543 | }␊ |
1544 | }␊ |
1545 | ␊ |
1546 | //␊ |
1547 | // Check for SystemVersion.plist or ServerVersion.plist␊ |
1548 | // to determine if a volume hosts an installed system.␊ |
1549 | //␊ |
1550 | if (bvr->flags & kBVFlagNativeBoot)␊ |
1551 | {␊ |
1552 | if (getOSVersion(bvr,bvr->OSVersion) == true)␊ |
1553 | {␊ |
1554 | bvr->flags |= kBVFlagSystemVolume;␊ |
1555 | }␊ |
1556 | }␊ |
1557 | ␊ |
1558 | }␊ |
1559 | }␊ |
1560 | ␊ |
1561 | void rescanBIOSDevice(int biosdev)␊ |
1562 | {␊ |
1563 | ␉struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);␊ |
1564 | ␉CacheReset();␊ |
1565 | ␉diskFreeMap(oldMap);␊ |
1566 | ␉oldMap = NULL;␊ |
1567 | ␉scanBootVolumes(biosdev, 0);␊ |
1568 | }␊ |
1569 | ␊ |
1570 | struct DiskBVMap* diskResetBootVolumes(int biosdev)␊ |
1571 | {␊ |
1572 | struct DiskBVMap * map;␊ |
1573 | struct DiskBVMap *prevMap = NULL;␊ |
1574 | for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {␊ |
1575 | if ( biosdev == map->biosdev ) {␊ |
1576 | break;␊ |
1577 | }␊ |
1578 | }␊ |
1579 | if(map != NULL)␊ |
1580 | {␊ |
1581 | verbose("Resetting BIOS device %xh\n", biosdev);␊ |
1582 | // Reset the biosbuf cache␊ |
1583 | cache_valid = false;␊ |
1584 | if(map == gDiskBVMap)␊ |
1585 | gDiskBVMap = map->next;␊ |
1586 | else if(prevMap != NULL)␊ |
1587 | prevMap->next = map->next;␊ |
1588 | else␊ |
1589 | stop("");␊ |
1590 | }␊ |
1591 | // Return the old map, either to be freed, or reinserted later␊ |
1592 | return map;␊ |
1593 | }␊ |
1594 | ␊ |
1595 | // Frees a DiskBVMap and all of its BootVolume's␊ |
1596 | void diskFreeMap(struct DiskBVMap *map)␊ |
1597 | {␊ |
1598 | if(map != NULL)␊ |
1599 | {␊ |
1600 | while(map->bvr != NULL)␊ |
1601 | {␊ |
1602 | BVRef bvr = map->bvr;␊ |
1603 | map->bvr = bvr->next;␊ |
1604 | (*bvr->bv_free)(bvr);␊ |
1605 | }␊ |
1606 | free(map);␊ |
1607 | }␊ |
1608 | }␊ |
1609 | ␊ |
1610 | BVRef diskScanBootVolumes( int biosdev, int * countPtr )␊ |
1611 | {␊ |
1612 | struct DiskBVMap * map = NULL;␊ |
1613 | BVRef bvr;␊ |
1614 | int count = 0;␊ |
1615 | ␊ |
1616 | // Find an existing mapping for this device.␊ |
1617 | ␊ |
1618 | for ( map = gDiskBVMap; map; map = map->next ) {␊ |
1619 | if ( biosdev == map->biosdev ) {␊ |
1620 | count = map->bvrcnt;␊ |
1621 | break;␊ |
1622 | }␊ |
1623 | }␊ |
1624 | ␊ |
1625 | if (map == NULL) {␊ |
1626 | bvr = diskScanGPTBootVolumes(biosdev, &count);␊ |
1627 | if (bvr == NULL) {␊ |
1628 | bvr = diskScanFDiskBootVolumes(biosdev, &count);␊ |
1629 | }␊ |
1630 | if (bvr == NULL) {␊ |
1631 | bvr = diskScanAPMBootVolumes(biosdev, &count);␊ |
1632 | }␊ |
1633 | if (bvr)␊ |
1634 | {␊ |
1635 | scanFSLevelBVRSettings(bvr);␊ |
1636 | }␊ |
1637 | } else {␊ |
1638 | bvr = map->bvr;␊ |
1639 | }␊ |
1640 | if (countPtr) *countPtr += count;␊ |
1641 | return bvr;␊ |
1642 | }␊ |
1643 | ␊ |
1644 | BVRef getBVChainForBIOSDev(int biosdev)␊ |
1645 | {␊ |
1646 | BVRef chain = NULL;␊ |
1647 | struct DiskBVMap * map = NULL;␊ |
1648 | ␊ |
1649 | for (map = gDiskBVMap; map; map = map->next)␊ |
1650 | {␊ |
1651 | if (map->biosdev == biosdev)␊ |
1652 | {␊ |
1653 | chain = map->bvr;␊ |
1654 | break;␊ |
1655 | }␊ |
1656 | }␊ |
1657 | ␊ |
1658 | return chain;␊ |
1659 | }␊ |
1660 | ␊ |
1661 | BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)␊ |
1662 | {␊ |
1663 | BVRef chain = NULL;␊ |
1664 | BVRef bvr = NULL;␊ |
1665 | BVRef newBVR = NULL;␊ |
1666 | BVRef prevBVR = NULL;␊ |
1667 | ␊ |
1668 | struct DiskBVMap * map = NULL;␊ |
1669 | int bvCount = 0;␊ |
1670 | ␊ |
1671 | const char *raw = 0;␊ |
1672 | char* val = 0;␊ |
1673 | int len;␊ |
1674 | ␊ |
1675 | getValueForKey(kHidePartition, &raw, &len, &bootInfo->chameleonConfig);␊ |
1676 | if(raw)␊ |
1677 | {␊ |
1678 | val = XMLDecode(raw); ␊ |
1679 | }␊ |
1680 | ␊ |
1681 | /*␊ |
1682 | * Traverse gDISKBVmap to get references for␊ |
1683 | * individual bvr chains of each drive.␊ |
1684 | */␊ |
1685 | for (map = gDiskBVMap; map; map = map->next)␊ |
1686 | {␊ |
1687 | for (bvr = map->bvr; bvr; bvr = bvr->next)␊ |
1688 | {␊ |
1689 | /*␊ |
1690 | * Save the last bvr.␊ |
1691 | */␊ |
1692 | if (newBVR) prevBVR = newBVR;␊ |
1693 | ␊ |
1694 | /*␊ |
1695 | * Allocate and copy the matched bvr entry into a new one.␊ |
1696 | */␊ |
1697 | newBVR = (BVRef) malloc(sizeof(*newBVR));␊ |
1698 | bcopy(bvr, newBVR, sizeof(*newBVR));␊ |
1699 | ␊ |
1700 | /*␊ |
1701 | * Adjust the new bvr's fields.␊ |
1702 | */␊ |
1703 | newBVR->next = NULL;␊ |
1704 | newBVR->filtered = true;␊ |
1705 | ␊ |
1706 | if ( (!allowFlags || newBVR->flags & allowFlags)␊ |
1707 | && (!denyFlags || !(newBVR->flags & denyFlags) )␊ |
1708 | && (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)␊ |
1709 | )␊ |
1710 | newBVR->visible = true;␊ |
1711 | ␊ |
1712 | /*␊ |
1713 | * Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,␊ |
1714 | * to be able to hide foreign partitions from the boot menu.␊ |
1715 | *␊ |
1716 | */␊ |
1717 | if ( (newBVR->flags & kBVFlagForeignBoot) )␊ |
1718 | {␊ |
1719 | char *start, *next = val;␊ |
1720 | long len = 0; ␊ |
1721 | do␊ |
1722 | {␊ |
1723 | start = strbreak(next, &next, &len);␊ |
1724 | if(len && matchVolumeToString(newBVR, start, len) )␊ |
1725 | ␉ newBVR->visible = false;␊ |
1726 | }␊ |
1727 | while ( next && *next );␊ |
1728 | }␊ |
1729 | ␊ |
1730 | /*␊ |
1731 | * Use the first bvr entry as the starting chain pointer.␊ |
1732 | */␊ |
1733 | if (!chain)␊ |
1734 | chain = newBVR;␊ |
1735 | ␊ |
1736 | /*␊ |
1737 | * Update the previous bvr's link pointer to use the new memory area.␊ |
1738 | */␊ |
1739 | if (prevBVR)␊ |
1740 | prevBVR->next = newBVR;␊ |
1741 | ␊ |
1742 | if (newBVR->visible)␊ |
1743 | bvCount++;␊ |
1744 | }␊ |
1745 | }␊ |
1746 | ␊ |
1747 | #if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P␊ |
1748 | for (bvr = chain; bvr; bvr = bvr->next)␊ |
1749 | {␊ |
1750 | printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);␊ |
1751 | }␊ |
1752 | printf("count: %d\n", bvCount);␊ |
1753 | getchar();␊ |
1754 | #endif␊ |
1755 | ␊ |
1756 | *count = bvCount;␊ |
1757 | ␊ |
1758 | free(val); ␊ |
1759 | return chain;␊ |
1760 | }␊ |
1761 | ␊ |
1762 | int freeFilteredBVChain(const BVRef chain)␊ |
1763 | {␊ |
1764 | int ret = 1;␊ |
1765 | BVRef bvr = chain;␊ |
1766 | BVRef nextBVR = NULL;␊ |
1767 | ␊ |
1768 | while (bvr)␊ |
1769 | {␊ |
1770 | nextBVR = bvr->next;␊ |
1771 | ␊ |
1772 | if (bvr->filtered)␊ |
1773 | {␊ |
1774 | free(bvr);␊ |
1775 | }␊ |
1776 | else␊ |
1777 | {␊ |
1778 | ret = 0;␊ |
1779 | break;␊ |
1780 | }␊ |
1781 | ␊ |
1782 | bvr = nextBVR;␊ |
1783 | }␊ |
1784 | ␊ |
1785 | return ret;␊ |
1786 | }␊ |
1787 | ␊ |
1788 | //==========================================================================␊ |
1789 | ␊ |
1790 | static const struct NamedValue fdiskTypes[] =␊ |
1791 | {␊ |
1792 | ␉{ FDISK_NTFS,␉␉"Windows NTFS" },␊ |
1793 | ␉{ FDISK_DOS12,␉␉"Windows FAT12" },␊ |
1794 | ␉{ FDISK_DOS16B,␉␉"Windows FAT16" },␊ |
1795 | ␉{ FDISK_DOS16S,␉␉"Windows FAT16" },␊ |
1796 | ␉{ FDISK_DOS16SLBA,␉"Windows FAT16" },␊ |
1797 | ␉{ FDISK_SMALLFAT32,␉"Windows FAT32" },␊ |
1798 | ␉{ FDISK_FAT32,␉␉"Windows FAT32" },␊ |
1799 | ␉{ FDISK_FREEBSD,␉"FreeBSD" },␊ |
1800 | ␉{ FDISK_OPENBSD,␉"OpenBSD" },␊ |
1801 | ␉{ FDISK_LINUX,␉␉"Linux" },␊ |
1802 | ␉{ FDISK_UFS,␉␉"Apple UFS" },␊ |
1803 | ␉{ FDISK_HFS,␉␉"Apple HFS" },␊ |
1804 | ␉{ FDISK_BOOTER,␉␉"Apple Boot/UFS" },␊ |
1805 | ␉{ FDISK_BEFS,␉␉"Haiku" },␊ |
1806 | ␉{ 0xCD,␉␉␉"CD-ROM" },␊ |
1807 | ␉{ 0x00,␉␉␉0 } /* must be last */␊ |
1808 | };␊ |
1809 | ␊ |
1810 | //==========================================================================␊ |
1811 | ␊ |
1812 | bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)␊ |
1813 | {␊ |
1814 | ␉char testStr[128];␊ |
1815 | ␊ |
1816 | ␉if ( !bvr || !match || !*match)␊ |
1817 | ␉␉return 0;␊ |
1818 | ␉␊ |
1819 | ␉if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )␊ |
1820 | return 0;␊ |
1821 | ␊ |
1822 | // Try to match hd(x,y) first.␊ |
1823 | sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);␊ |
1824 | if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )␊ |
1825 | return true;␊ |
1826 | ␊ |
1827 | // Try to match volume UUID.␊ |
1828 | if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)␊ |
1829 | {␊ |
1830 | if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )␊ |
1831 | return true;␊ |
1832 | }␊ |
1833 | ␊ |
1834 | // Try to match volume label (always quoted).␊ |
1835 | if ( bvr->description )␊ |
1836 | {␊ |
1837 | bvr->description(bvr, testStr, sizeof(testStr)-1);␊ |
1838 | if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )␊ |
1839 | return true;␊ |
1840 | }␊ |
1841 | ␊ |
1842 | return false;␊ |
1843 | }␊ |
1844 | ␊ |
1845 | /* If Rename Partition has defined an alias, then extract it for description purpose.␊ |
1846 | * The format for the rename string is the following:␊ |
1847 | * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...␊ |
1848 | */␊ |
1849 | ␊ |
1850 | bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)␊ |
1851 | {␊ |
1852 | char *aliasList, *entryStart, *entryNext;␊ |
1853 | ␊ |
1854 | if ( !str || strMaxLen <= 0)␊ |
1855 | return false;␊ |
1856 | ␊ |
1857 | aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->chameleonConfig));␊ |
1858 | if ( !aliasList )␊ |
1859 | return false;␊ |
1860 | ␊ |
1861 | for ( entryStart = entryNext = aliasList;␊ |
1862 | entryNext && *entryNext;␊ |
1863 | entryStart = entryNext )␊ |
1864 | {␊ |
1865 | char *volStart, *volEnd, *aliasStart;␊ |
1866 | long volLen, aliasLen;␊ |
1867 | ␊ |
1868 | // Delimit current entry␊ |
1869 | entryNext = strchr(entryStart, ';');␊ |
1870 | if ( entryNext )␊ |
1871 | {␊ |
1872 | *entryNext = '\0';␊ |
1873 | entryNext++;␊ |
1874 | }␊ |
1875 | ␊ |
1876 | volStart = strbreak(entryStart, &volEnd, &volLen);␊ |
1877 | if(!volLen)␊ |
1878 | continue;␊ |
1879 | ␊ |
1880 | aliasStart = strbreak(volEnd, 0, &aliasLen);␊ |
1881 | if(!aliasLen)␊ |
1882 | continue;␊ |
1883 | ␊ |
1884 | if ( matchVolumeToString(bvr, volStart, volLen) )␊ |
1885 | {␊ |
1886 | strncat(str, aliasStart, MIN(strMaxLen, aliasLen));␊ |
1887 | free(aliasList);␊ |
1888 | ␊ |
1889 | return true;␊ |
1890 | }␊ |
1891 | }␊ |
1892 | ␊ |
1893 | free(aliasList);␊ |
1894 | return false;␊ |
1895 | }␊ |
1896 | ␊ |
1897 | void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )␊ |
1898 | {␊ |
1899 | unsigned char type;␊ |
1900 | char *p = str;␊ |
1901 | ␊ |
1902 | if(!bvr || !p || strMaxLen <= 0)␊ |
1903 | return;␊ |
1904 | ␊ |
1905 | type = (unsigned char) bvr->part_type;␊ |
1906 | ␊ |
1907 | if (useDeviceDescription)␊ |
1908 | {␊ |
1909 | int len = getDeviceDescription(bvr, str);␊ |
1910 | if(len >= strMaxLen)␊ |
1911 | return;␊ |
1912 | ␊ |
1913 | strcpy(str + len, " ");␊ |
1914 | len++;␊ |
1915 | strMaxLen -= len;␊ |
1916 | p += len;␊ |
1917 | }␊ |
1918 | ␊ |
1919 | /* See if a partition rename is preferred */␊ |
1920 | if(getVolumeLabelAlias(bvr, p, strMaxLen)) {␊ |
1921 | strncpy(bvr->label, p, strMaxLen); ␊ |
1922 | return; // we're done here no need to seek for real name␊ |
1923 | }␊ |
1924 | ␊ |
1925 | //␊ |
1926 | // Get the volume label using filesystem specific functions␊ |
1927 | // or use the alternate volume label if available.␊ |
1928 | //␊ |
1929 | ␉if (*bvr->altlabel != '\0')␊ |
1930 | strncpy(p, bvr->altlabel, strMaxLen);␊ |
1931 | ␉else if (bvr->description)␊ |
1932 | bvr->description(bvr, p, strMaxLen);␊ |
1933 | ␊ |
1934 | if (*p == '\0') {␊ |
1935 | const char * name = getNameForValue( fdiskTypes, type );␊ |
1936 | if (name == NULL) {␊ |
1937 | name = bvr->type_name;␊ |
1938 | }␊ |
1939 | if (name == NULL) {␊ |
1940 | sprintf(p, "TYPE %02x", type);␊ |
1941 | } else {␊ |
1942 | strncpy(p, name, strMaxLen);␊ |
1943 | }␊ |
1944 | }␊ |
1945 | ␊ |
1946 | // Set the devices label␊ |
1947 | sprintf(bvr->label, p);␊ |
1948 | }␊ |
1949 | ␊ |
1950 | //==========================================================================␊ |
1951 | int readBootSector(int biosdev, unsigned int secno, void * buffer)␊ |
1952 | {␊ |
1953 | ␉int error;␊ |
1954 | ␉struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;␊ |
1955 | ␊ |
1956 | ␉if (bootSector == NULL)␊ |
1957 | ␉{␊ |
1958 | ␉␉if (gBootSector == NULL)␊ |
1959 | ␉␉{␊ |
1960 | ␉␉␉gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));␊ |
1961 | ␊ |
1962 | ␉␉␉if (gBootSector == NULL)␊ |
1963 | ␉␉␉{␊ |
1964 | ␉␉␉␉return -1;␊ |
1965 | ␉␉␉}␊ |
1966 | ␉␉}␊ |
1967 | ␊ |
1968 | bootSector = gBootSector;␊ |
1969 | ␉}␊ |
1970 | ␊ |
1971 | ␉error = readBytes(biosdev, secno, 0, BPS, bootSector);␊ |
1972 | ␊ |
1973 | ␉if (error || bootSector->signature != DISK_SIGNATURE)␊ |
1974 | ␉{␊ |
1975 | ␉␉return -1;␊ |
1976 | ␉}␊ |
1977 | ␉return 0;␊ |
1978 | }␊ |
1979 | ␊ |
1980 | /*␊ |
1981 | * Format of boot1f32 block.␊ |
1982 | */␊ |
1983 | ␊ |
1984 | #define BOOT1F32_MAGIC "BOOT "␊ |
1985 | #define BOOT1F32_MAGICLEN 11␊ |
1986 | ␊ |
1987 | struct disk_boot1f32_blk {␊ |
1988 | unsigned char init[3];␊ |
1989 | unsigned char fsheader[87];␊ |
1990 | unsigned char magic[BOOT1F32_MAGICLEN];␊ |
1991 | unsigned char bootcode[409];␊ |
1992 | unsigned short signature;␊ |
1993 | };␊ |
1994 | ␊ |
1995 | int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )␊ |
1996 | {␊ |
1997 | struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;␊ |
1998 | int error;␊ |
1999 | ␊ |
2000 | if ( bootSector == NULL )␊ |
2001 | {␊ |
2002 | if ( gBootSector == NULL )␊ |
2003 | {␊ |
2004 | gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));␊ |
2005 | if ( gBootSector == NULL ) return -1;␊ |
2006 | }␊ |
2007 | bootSector = (struct disk_boot1f32_blk *) gBootSector;␊ |
2008 | }␊ |
2009 | ␊ |
2010 | error = readBytes( biosdev, secno, 0, BPS, bootSector );␊ |
2011 | if ( error || bootSector->signature != DISK_SIGNATURE␊ |
2012 | || strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )␊ |
2013 | return -1;␊ |
2014 | ␊ |
2015 | return 0;␊ |
2016 | }␊ |
2017 | ␊ |
2018 | //==========================================================================␊ |
2019 | // Handle seek request from filesystem modules.␊ |
2020 | ␊ |
2021 | void diskSeek(BVRef bvr, long long position)␊ |
2022 | {␊ |
2023 | bvr->fs_boff = position / BPS;␊ |
2024 | bvr->fs_byteoff = position % BPS;␊ |
2025 | }␊ |
2026 | ␊ |
2027 | //==========================================================================␊ |
2028 | // Handle read request from filesystem modules.␊ |
2029 | ␊ |
2030 | int diskRead( BVRef bvr, long addr, long length )␊ |
2031 | {␊ |
2032 | return readBytes( bvr->biosdev,␊ |
2033 | bvr->fs_boff + bvr->part_boff,␊ |
2034 | bvr->fs_byteoff,␊ |
2035 | length,␊ |
2036 | (void *) addr );␊ |
2037 | }␊ |
2038 | ␊ |
2039 | int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )␊ |
2040 | {␊ |
2041 | int secs;␊ |
2042 | unsigned char *cbuf = (unsigned char *)buffer;␊ |
2043 | unsigned int copy_len;␊ |
2044 | int rc;␊ |
2045 | ␊ |
2046 | if ((len & (BPS-1)) != 0) {␊ |
2047 | error("raw disk read not sector aligned");␊ |
2048 | return -1;␊ |
2049 | }␊ |
2050 | secno += bvr->part_boff;␊ |
2051 | ␊ |
2052 | cache_valid = false;␊ |
2053 | ␊ |
2054 | while (len > 0) {␊ |
2055 | secs = len / BPS;␊ |
2056 | if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;␊ |
2057 | copy_len = secs * BPS;␊ |
2058 | ␊ |
2059 | //printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);␊ |
2060 | if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {␊ |
2061 | /* Ignore corrected ECC errors */␊ |
2062 | if (rc != ECC_CORRECTED_ERR) {␊ |
2063 | error(" EBIOS read error: %s\n", bios_error(rc), rc);␊ |
2064 | error(" Block %d Sectors %d\n", secno, secs);␊ |
2065 | return rc;␊ |
2066 | }␊ |
2067 | }␊ |
2068 | bcopy( trackbuf, cbuf, copy_len );␊ |
2069 | len -= copy_len;␊ |
2070 | cbuf += copy_len;␊ |
2071 | secno += secs;␊ |
2072 | spinActivityIndicator(secs);␊ |
2073 | }␊ |
2074 | ␊ |
2075 | return 0;␊ |
2076 | }␊ |
2077 | ␊ |
2078 | int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )␊ |
2079 | {␊ |
2080 | int secs;␊ |
2081 | unsigned char *cbuf = (unsigned char *)buffer;␊ |
2082 | unsigned int copy_len;␊ |
2083 | int rc;␊ |
2084 | ␊ |
2085 | if ((len & (BPS-1)) != 0) {␊ |
2086 | error("raw disk write not sector aligned");␊ |
2087 | return -1;␊ |
2088 | }␊ |
2089 | secno += bvr->part_boff;␊ |
2090 | ␊ |
2091 | cache_valid = false;␊ |
2092 | ␊ |
2093 | while (len > 0) {␊ |
2094 | secs = len / BPS;␊ |
2095 | if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;␊ |
2096 | copy_len = secs * BPS;␊ |
2097 | ␊ |
2098 | bcopy( cbuf, trackbuf, copy_len );␊ |
2099 | //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);␊ |
2100 | if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {␊ |
2101 | error(" EBIOS write error: %s\n", bios_error(rc), rc);␊ |
2102 | error(" Block %d Sectors %d\n", secno, secs);␊ |
2103 | return rc;␊ |
2104 | }␊ |
2105 | len -= copy_len;␊ |
2106 | cbuf += copy_len;␊ |
2107 | secno += secs;␊ |
2108 | spinActivityIndicator(secs);␊ |
2109 | }␊ |
2110 | ␊ |
2111 | return 0;␊ |
2112 | }␊ |
2113 | ␊ |
2114 | int diskIsCDROM(BVRef bvr)␊ |
2115 | {␊ |
2116 | struct driveInfo di;␊ |
2117 | ␊ |
2118 | if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {␊ |
2119 | ␉return 1;␊ |
2120 | }␊ |
2121 | return 0;␊ |
2122 | }␊ |
2123 | ␊ |
2124 | int biosDevIsCDROM(int biosdev)␊ |
2125 | {␊ |
2126 | struct driveInfo di;␊ |
2127 | ␊ |
2128 | if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)␊ |
2129 | {␊ |
2130 | ␉return 1;␊ |
2131 | }␊ |
2132 | return 0;␊ |
2133 | }␊ |
2134 | |