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