]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
f083c6c3 A |
6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
7 | * | |
8 | * This file contains Original Code and/or Modifications of Original Code | |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14c7c974 A |
14 | * |
15 | * The Original Code and all software distributed under the License are | |
f083c6c3 | 16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
f083c6c3 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
14c7c974 A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
26 | * Mach Operating System | |
27 | * Copyright (c) 1990 Carnegie-Mellon University | |
28 | * Copyright (c) 1989 Carnegie-Mellon University | |
29 | * All rights reserved. The CMU software License Agreement specifies | |
30 | * the terms and conditions for use and redistribution. | |
31 | */ | |
32 | ||
33 | /* | |
34 | * INTEL CORPORATION PROPRIETARY INFORMATION | |
35 | * | |
36 | * This software is supplied under the terms of a license agreement or | |
37 | * nondisclosure agreement with Intel Corporation and may not be copied | |
38 | * nor disclosed except in accordance with the terms of that agreement. | |
39 | * | |
40 | * Copyright 1988, 1989 Intel Corporation | |
41 | */ | |
42 | ||
43 | /* | |
44 | * Copyright 1993 NeXT Computer, Inc. | |
45 | * All rights reserved. | |
46 | */ | |
47 | ||
f083c6c3 | 48 | #include "bootstruct.h" |
14c7c974 | 49 | #include "libsaio.h" |
75b89a82 | 50 | #include "fdisk.h" |
f083c6c3 A |
51 | #include "ufs.h" |
52 | #include "hfs.h" | |
14c7c974 | 53 | |
f083c6c3 A |
54 | #include <limits.h> |
55 | #include <IOKit/storage/IOApplePartitionScheme.h> | |
14c7c974 | 56 | |
75b89a82 | 57 | #define BPS 512 /* sector size of the device */ |
f083c6c3 A |
58 | #define CD_BPS 2048 /* CD-ROM block size */ |
59 | #define N_CACHE_SECS (BIOS_LEN / BPS) /* Must be a multiple of 4 for CD-ROMs */ | |
75b89a82 | 60 | #define UFS_FRONT_PORCH 0 |
f083c6c3 A |
61 | #define kAPMSector 2 /* Sector number of Apple partition map */ |
62 | #define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */ | |
14c7c974 A |
63 | |
64 | /* | |
75b89a82 A |
65 | * trackbuf points to the start of the track cache. Biosread() |
66 | * will store the sectors read from disk to this memory area. | |
14c7c974 | 67 | * |
75b89a82 A |
68 | * biosbuf points to a sector within the track cache, and is |
69 | * updated by Biosread(). | |
14c7c974 | 70 | */ |
75b89a82 A |
71 | static const char * const trackbuf = (char *) ptov(BIOS_ADDR); |
72 | static const char * biosbuf; | |
14c7c974 | 73 | |
75b89a82 A |
74 | /* |
75 | * Map a disk drive to bootable volumes contained within. | |
14c7c974 | 76 | */ |
75b89a82 A |
77 | struct DiskBVMap { |
78 | int biosdev; // BIOS device number (unique) | |
79 | BVRef bvr; // chain of boot volumes on the disk | |
80 | int bvrcnt; // number of boot volumes | |
81 | struct DiskBVMap * next; // linkage to next mapping | |
82 | }; | |
14c7c974 | 83 | |
75b89a82 A |
84 | static struct DiskBVMap * gDiskBVMap = NULL; |
85 | static struct disk_blk0 * gBootSector = NULL; | |
14c7c974 | 86 | |
75b89a82 | 87 | extern void spinActivityIndicator(); |
14c7c974 | 88 | |
75b89a82 | 89 | static void getVolumeDescription(BVRef bvr, char * str, long strMaxLen); |
14c7c974 | 90 | |
75b89a82 | 91 | //========================================================================== |
14c7c974 | 92 | |
f083c6c3 | 93 | static int getDriveInfo( int biosdev, struct driveInfo *dip ) |
14c7c974 | 94 | { |
f083c6c3 A |
95 | static struct driveInfo cached_di; |
96 | int cc; | |
75b89a82 | 97 | |
f083c6c3 | 98 | if ( !cached_di.valid || biosdev != cached_di.biosdev ) |
75b89a82 | 99 | { |
f083c6c3 A |
100 | cc = get_drive_info(biosdev, &cached_di); |
101 | if (cc < 0) { | |
102 | cached_di.valid = 0; | |
103 | return (-1); // BIOS call error | |
104 | } | |
75b89a82 | 105 | } |
14c7c974 | 106 | |
f083c6c3 | 107 | bcopy(&cached_di, dip, sizeof(cached_di)); |
14c7c974 | 108 | |
75b89a82 A |
109 | return 0; |
110 | } | |
14c7c974 | 111 | |
75b89a82 A |
112 | //========================================================================== |
113 | // Maps (E)BIOS return codes to message strings. | |
14c7c974 | 114 | |
75b89a82 A |
115 | struct NamedValue { |
116 | unsigned char value; | |
117 | const char * name; | |
118 | }; | |
14c7c974 | 119 | |
75b89a82 A |
120 | static const char * getNameForValue( const struct NamedValue * nameTable, |
121 | unsigned char value ) | |
122 | { | |
123 | const struct NamedValue * np; | |
14c7c974 | 124 | |
75b89a82 A |
125 | for ( np = nameTable; np->value; np++) |
126 | if (np->value == value) | |
127 | return np->name; | |
14c7c974 | 128 | |
75b89a82 | 129 | return NULL; |
14c7c974 A |
130 | } |
131 | ||
14c7c974 A |
132 | #define ECC_CORRECTED_ERR 0x11 |
133 | ||
75b89a82 A |
134 | static const struct NamedValue bios_errors[] = { |
135 | { 0x10, "Media error" }, | |
136 | { 0x11, "Corrected ECC error" }, | |
137 | { 0x20, "Controller or device error" }, | |
138 | { 0x40, "Seek failed" }, | |
139 | { 0x80, "Device timeout" }, | |
140 | { 0xAA, "Drive not ready" }, | |
141 | { 0x00, 0 } | |
14c7c974 A |
142 | }; |
143 | ||
75b89a82 | 144 | static const char * bios_error(int errnum) |
14c7c974 | 145 | { |
75b89a82 A |
146 | static char errorstr[] = "Error 0x00"; |
147 | const char * errname; | |
148 | ||
149 | errname = getNameForValue( bios_errors, errnum ); | |
150 | if ( errname ) return errname; | |
151 | ||
152 | sprintf(errorstr, "Error 0x%02x", errnum); | |
153 | return errorstr; // No string, print error code only | |
14c7c974 A |
154 | } |
155 | ||
75b89a82 A |
156 | //========================================================================== |
157 | // Use BIOS INT13 calls to read the sector specified. This function will | |
158 | // also perform read-ahead to cache a few subsequent sector to the sector | |
159 | // cache. | |
160 | // | |
161 | // Return: | |
162 | // 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call. | |
163 | ||
164 | static int Biosread( int biosdev, unsigned int secno ) | |
14c7c974 | 165 | { |
75b89a82 A |
166 | static int xbiosdev, xcyl, xhead; |
167 | static unsigned int xsec, xnsecs; | |
168 | static BOOL cache_valid = FALSE; | |
f083c6c3 | 169 | struct driveInfo di; |
14c7c974 | 170 | |
75b89a82 | 171 | int rc = -1; |
14c7c974 | 172 | int cyl, head, sec; |
14c7c974 | 173 | int tries = 0; |
f083c6c3 | 174 | int bps, divisor; |
14c7c974 | 175 | |
f083c6c3 A |
176 | if (getDriveInfo(biosdev, &di) < 0) { |
177 | return -1; | |
178 | } | |
179 | if (di.no_emulation) { | |
180 | /* Always assume 2k block size; BIOS may lie about geometry */ | |
181 | bps = 2048; | |
182 | } else { | |
183 | bps = di.di.params.phys_nbps; | |
184 | } | |
185 | divisor = bps / BPS; | |
186 | ||
187 | DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps)); | |
14c7c974 A |
188 | |
189 | // To read the disk sectors, use EBIOS if we can. Otherwise, | |
190 | // revert to the standard BIOS calls. | |
75b89a82 A |
191 | |
192 | if ((biosdev >= kBIOSDevTypeHardDrive) && | |
f083c6c3 | 193 | (di.uses_ebios & EBIOS_FIXED_DISK_ACCESS)) |
75b89a82 | 194 | { |
14c7c974 A |
195 | if (cache_valid && |
196 | (biosdev == xbiosdev) && | |
197 | (secno >= xsec) && | |
f083c6c3 | 198 | ((unsigned int)secno < (xsec + xnsecs))) |
14c7c974 | 199 | { |
75b89a82 | 200 | biosbuf = trackbuf + (BPS * (secno - xsec)); |
14c7c974 A |
201 | return 0; |
202 | } | |
203 | ||
204 | xnsecs = N_CACHE_SECS; | |
f083c6c3 | 205 | xsec = (secno / divisor) * divisor; |
75b89a82 | 206 | cache_valid = FALSE; |
14c7c974 | 207 | |
f083c6c3 | 208 | while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5)) |
14c7c974 A |
209 | { |
210 | if (rc == ECC_CORRECTED_ERR) { | |
211 | /* Ignore corrected ECC errors */ | |
75b89a82 | 212 | rc = 0; |
14c7c974 A |
213 | break; |
214 | } | |
215 | error(" EBIOS read error: %s\n", bios_error(rc), rc); | |
216 | error(" Block %d Sectors %d\n", secno, xnsecs); | |
217 | sleep(1); | |
218 | } | |
219 | } | |
f083c6c3 | 220 | else |
75b89a82 | 221 | { |
f083c6c3 A |
222 | /* spc = spt * heads */ |
223 | int spc = (di.di.params.phys_spt * di.di.params.phys_heads); | |
14c7c974 | 224 | cyl = secno / spc; |
f083c6c3 A |
225 | head = (secno % spc) / di.di.params.phys_spt; |
226 | sec = secno % di.di.params.phys_spt; | |
14c7c974 A |
227 | |
228 | if (cache_valid && | |
229 | (biosdev == xbiosdev) && | |
230 | (cyl == xcyl) && | |
231 | (head == xhead) && | |
f083c6c3 A |
232 | ((unsigned int)sec >= xsec) && |
233 | ((unsigned int)sec < (xsec + xnsecs))) | |
14c7c974 | 234 | { |
75b89a82 A |
235 | // this sector is in trackbuf cache |
236 | biosbuf = trackbuf + (BPS * (sec - xsec)); | |
14c7c974 A |
237 | return 0; |
238 | } | |
239 | ||
240 | // Cache up to a track worth of sectors, but do not cross a | |
241 | // track boundary. | |
75b89a82 | 242 | |
14c7c974 A |
243 | xcyl = cyl; |
244 | xhead = head; | |
245 | xsec = sec; | |
f083c6c3 | 246 | xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS; |
75b89a82 | 247 | cache_valid = FALSE; |
14c7c974 A |
248 | |
249 | while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) && | |
250 | (++tries < 5)) | |
251 | { | |
252 | if (rc == ECC_CORRECTED_ERR) { | |
253 | /* Ignore corrected ECC errors */ | |
75b89a82 | 254 | rc = 0; |
14c7c974 A |
255 | break; |
256 | } | |
257 | error(" BIOS read error: %s\n", bios_error(rc), rc); | |
258 | error(" Block %d, Cyl %d Head %d Sector %d\n", | |
259 | secno, cyl, head, sec); | |
260 | sleep(1); | |
261 | } | |
262 | } | |
263 | ||
264 | // If the BIOS reported success, mark the sector cache as valid. | |
75b89a82 | 265 | |
14c7c974 A |
266 | if (rc == 0) { |
267 | cache_valid = TRUE; | |
268 | } | |
f083c6c3 | 269 | biosbuf = trackbuf + (secno % divisor) * BPS; |
14c7c974 A |
270 | xbiosdev = biosdev; |
271 | ||
75b89a82 | 272 | spinActivityIndicator(); |
14c7c974 A |
273 | |
274 | return rc; | |
275 | } | |
276 | ||
75b89a82 A |
277 | //========================================================================== |
278 | ||
279 | static int readBytes( int biosdev, unsigned int blkno, | |
280 | unsigned int byteCount, void * buffer ) | |
14c7c974 | 281 | { |
75b89a82 A |
282 | |
283 | char * cbuf = (char *) buffer; | |
284 | int error; | |
285 | int copy_len; | |
286 | ||
287 | DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__, | |
288 | biosdev, blkno, byteCount, (unsigned)cbuf)); | |
289 | ||
290 | for ( ; byteCount; cbuf += BPS, blkno++ ) | |
291 | { | |
292 | error = Biosread( biosdev, blkno ); | |
293 | if ( error ) | |
294 | { | |
295 | DEBUG_DISK(("error\n")); | |
296 | return (-1); | |
297 | } | |
298 | ||
299 | copy_len = (byteCount > BPS) ? BPS : byteCount; | |
300 | bcopy( biosbuf, cbuf, copy_len ); | |
301 | byteCount -= copy_len; | |
302 | } | |
303 | ||
304 | DEBUG_DISK(("done\n")); | |
305 | ||
306 | return 0; | |
14c7c974 A |
307 | } |
308 | ||
75b89a82 A |
309 | //========================================================================== |
310 | ||
311 | static int isExtendedFDiskPartition( const struct fdisk_part * part ) | |
14c7c974 | 312 | { |
75b89a82 A |
313 | static unsigned char extParts[] = |
314 | { | |
315 | 0x05, /* Extended */ | |
316 | 0x0f, /* Win95 extended */ | |
317 | 0x85, /* Linux extended */ | |
318 | }; | |
319 | ||
f083c6c3 | 320 | unsigned int i; |
75b89a82 A |
321 | |
322 | for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++) | |
323 | { | |
324 | if (extParts[i] == part->systid) return 1; | |
325 | } | |
326 | return 0; | |
14c7c974 A |
327 | } |
328 | ||
75b89a82 A |
329 | //========================================================================== |
330 | ||
331 | static int getNextFDiskPartition( int biosdev, int * partno, | |
332 | const struct fdisk_part ** outPart ) | |
14c7c974 | 333 | { |
75b89a82 A |
334 | static int sBiosdev = -1; |
335 | static int sNextPartNo; | |
336 | static unsigned int sExtBase; | |
337 | static unsigned int sExtDepth; | |
338 | static struct fdisk_part * sExtPart; | |
339 | struct fdisk_part * part; | |
340 | ||
341 | if ( sBiosdev != biosdev || *partno < 0 ) | |
342 | { | |
343 | // Fetch MBR. | |
344 | if ( readBootSector( biosdev, DISK_BLK0, 0 ) ) return 0; | |
345 | ||
346 | sBiosdev = biosdev; | |
347 | sNextPartNo = 0; | |
348 | sExtBase = 0; | |
349 | sExtDepth = 0; | |
350 | sExtPart = NULL; | |
351 | } | |
14c7c974 | 352 | |
75b89a82 A |
353 | while (1) |
354 | { | |
355 | part = NULL; | |
14c7c974 | 356 | |
75b89a82 A |
357 | if ( sNextPartNo < FDISK_NPART ) |
358 | { | |
359 | part = (struct fdisk_part *) gBootSector->parts[sNextPartNo]; | |
360 | } | |
361 | else if ( sExtPart ) | |
362 | { | |
363 | unsigned int blkno = sExtPart->relsect + sExtBase; | |
14c7c974 | 364 | |
75b89a82 A |
365 | // Save the block offset of the first extended partition. |
366 | ||
367 | if ( sExtDepth == 0 ) sExtBase = sExtPart->relsect; | |
368 | ||
369 | // Load extended partition table. | |
370 | ||
371 | if ( readBootSector( biosdev, blkno, 0 ) == 0 ) | |
372 | { | |
373 | sNextPartNo = 0; | |
374 | sExtDepth++; | |
375 | sExtPart = NULL; | |
376 | continue; | |
377 | } | |
378 | } | |
379 | ||
380 | if ( part == NULL ) break; // Reached end of partition chain. | |
381 | ||
382 | // Advance to next partition number. | |
383 | ||
384 | sNextPartNo++; | |
385 | ||
386 | // Assume at most one extended partition per table. | |
387 | ||
388 | if ( isExtendedFDiskPartition(part) ) | |
389 | { | |
390 | sExtPart = part; | |
391 | continue; | |
392 | } | |
393 | ||
394 | // Skip empty slots. | |
395 | ||
396 | if ( part->systid == 0x00 ) | |
397 | { | |
398 | continue; | |
399 | } | |
400 | ||
401 | // Change relative offset to an absolute offset. | |
402 | ||
403 | part->relsect += sExtBase; | |
404 | ||
405 | *outPart = part; | |
f083c6c3 | 406 | *partno = sExtDepth ? (int)(sExtDepth + 4) : sNextPartNo; |
75b89a82 A |
407 | |
408 | break; | |
14c7c974 A |
409 | } |
410 | ||
75b89a82 A |
411 | return (part != NULL); |
412 | } | |
413 | ||
414 | //========================================================================== | |
14c7c974 | 415 | |
75b89a82 A |
416 | static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff, |
417 | const struct fdisk_part * part, | |
418 | FSInit initFunc, FSLoadFile loadFunc, | |
f083c6c3 | 419 | FSGetDirEntry getdirFunc, int probe, int type ) |
75b89a82 A |
420 | { |
421 | BVRef bvr = (BVRef) malloc( sizeof(*bvr) ); | |
422 | if ( bvr ) | |
14c7c974 | 423 | { |
75b89a82 | 424 | bzero(bvr, sizeof(*bvr)); |
14c7c974 | 425 | |
75b89a82 A |
426 | bvr->biosdev = biosdev; |
427 | bvr->part_no = partno; | |
428 | bvr->part_boff = blkoff; | |
429 | bvr->part_type = part->systid; | |
430 | bvr->fs_loadfile = loadFunc; | |
431 | bvr->fs_getdirentry = getdirFunc; | |
432 | bvr->description = getVolumeDescription; | |
f083c6c3 | 433 | bvr->type = type; |
75b89a82 A |
434 | |
435 | if ( part->bootid & FDISK_ACTIVE ) | |
436 | bvr->flags |= kBVFlagPrimary; | |
437 | ||
438 | // Probe the filesystem. | |
439 | ||
440 | if ( initFunc ) | |
441 | { | |
442 | bvr->flags |= kBVFlagNativeBoot; | |
14c7c974 | 443 | |
75b89a82 A |
444 | if ( probe && initFunc( bvr ) != 0 ) |
445 | { | |
446 | // filesystem probe failed. | |
14c7c974 | 447 | |
75b89a82 A |
448 | DEBUG_DISK(("%s: failed probe on dev %x part %d\n", |
449 | __FUNCTION__, biosdev, partno)); | |
14c7c974 | 450 | |
75b89a82 A |
451 | free(bvr); |
452 | bvr = NULL; | |
453 | } | |
454 | } | |
455 | else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 ) | |
456 | { | |
457 | bvr->flags |= kBVFlagForeignBoot; | |
458 | } | |
459 | else | |
460 | { | |
461 | free(bvr); | |
462 | bvr = NULL; | |
14c7c974 A |
463 | } |
464 | } | |
75b89a82 A |
465 | return bvr; |
466 | } | |
14c7c974 | 467 | |
75b89a82 A |
468 | //========================================================================== |
469 | ||
f083c6c3 A |
470 | BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff, |
471 | const DPME * part, | |
472 | FSInit initFunc, FSLoadFile loadFunc, | |
473 | FSGetDirEntry getdirFunc, int probe, int type ) | |
474 | { | |
475 | BVRef bvr = (BVRef) malloc( sizeof(*bvr) ); | |
476 | if ( bvr ) | |
477 | { | |
478 | bzero(bvr, sizeof(*bvr)); | |
479 | ||
480 | bvr->biosdev = biosdev; | |
481 | bvr->part_no = partno; | |
482 | bvr->part_boff = blkoff; | |
483 | bvr->fs_loadfile = loadFunc; | |
484 | bvr->fs_getdirentry = getdirFunc; | |
485 | bvr->description = getVolumeDescription; | |
486 | bvr->type = type; | |
487 | strlcpy(bvr->name, part->dpme_name, DPISTRLEN); | |
488 | strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN); | |
489 | ||
490 | /* | |
491 | if ( part->bootid & FDISK_ACTIVE ) | |
492 | bvr->flags |= kBVFlagPrimary; | |
493 | */ | |
494 | ||
495 | // Probe the filesystem. | |
496 | ||
497 | if ( initFunc ) | |
498 | { | |
499 | bvr->flags |= kBVFlagNativeBoot; | |
500 | ||
501 | if ( probe && initFunc( bvr ) != 0 ) | |
502 | { | |
503 | // filesystem probe failed. | |
504 | ||
505 | DEBUG_DISK(("%s: failed probe on dev %x part %d\n", | |
506 | __FUNCTION__, biosdev, partno)); | |
507 | ||
508 | free(bvr); | |
509 | bvr = NULL; | |
510 | } | |
511 | } | |
512 | /* | |
513 | else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 ) | |
514 | { | |
515 | bvr->flags |= kBVFlagForeignBoot; | |
516 | } | |
517 | */ | |
518 | else | |
519 | { | |
520 | free(bvr); | |
521 | bvr = NULL; | |
522 | } | |
523 | } | |
524 | return bvr; | |
525 | } | |
526 | ||
527 | //========================================================================== | |
528 | ||
529 | static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr ) | |
75b89a82 A |
530 | { |
531 | const struct fdisk_part * part; | |
532 | struct DiskBVMap * map; | |
533 | int partno = -1; | |
534 | BVRef bvr; | |
535 | BVRef booterUFS = NULL; | |
f083c6c3 A |
536 | int spc; |
537 | struct driveInfo di; | |
538 | boot_drive_info_t *dp; | |
75b89a82 | 539 | |
f083c6c3 A |
540 | /* Initialize disk info */ |
541 | if (getDriveInfo(biosdev, &di) != 0) { | |
542 | return NULL; | |
543 | } | |
544 | dp = &di.di; | |
545 | spc = (dp->params.phys_spt * dp->params.phys_heads); | |
546 | if (spc == 0) { | |
547 | /* This is probably a CD-ROM; punt on the geometry. */ | |
548 | spc = 1; | |
549 | } | |
14c7c974 | 550 | |
f083c6c3 | 551 | do { |
75b89a82 | 552 | // Create a new mapping. |
14c7c974 | 553 | |
75b89a82 A |
554 | map = (struct DiskBVMap *) malloc( sizeof(*map) ); |
555 | if ( map ) | |
556 | { | |
557 | map->biosdev = biosdev; | |
558 | map->bvr = NULL; | |
559 | map->bvrcnt = 0; | |
560 | map->next = gDiskBVMap; | |
561 | gDiskBVMap = map; | |
14c7c974 | 562 | |
75b89a82 A |
563 | // Create a record for each partition found on the disk. |
564 | ||
565 | while ( getNextFDiskPartition( biosdev, &partno, &part ) ) | |
14c7c974 | 566 | { |
75b89a82 A |
567 | DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__, |
568 | partno, part->systid)); | |
75b89a82 A |
569 | bvr = 0; |
570 | ||
571 | switch ( part->systid ) | |
572 | { | |
573 | case FDISK_UFS: | |
f083c6c3 | 574 | bvr = newFDiskBVRef( |
75b89a82 A |
575 | biosdev, partno, |
576 | part->relsect + UFS_FRONT_PORCH/BPS, | |
577 | part, | |
578 | UFSInitPartition, | |
579 | UFSLoadFile, | |
580 | UFSGetDirEntry, | |
f083c6c3 A |
581 | 0, |
582 | kBIOSDevTypeHardDrive); | |
75b89a82 A |
583 | break; |
584 | ||
585 | case FDISK_HFS: | |
586 | bvr = newFDiskBVRef( | |
587 | biosdev, partno, | |
588 | part->relsect, | |
589 | part, | |
590 | HFSInitPartition, | |
591 | HFSLoadFile, | |
592 | HFSGetDirEntry, | |
f083c6c3 A |
593 | 0, |
594 | kBIOSDevTypeHardDrive); | |
75b89a82 A |
595 | break; |
596 | ||
597 | case FDISK_BOOTER: | |
75b89a82 A |
598 | booterUFS = newFDiskBVRef( |
599 | biosdev, partno, | |
600 | ((part->relsect + spc - 1) / spc) * spc, | |
601 | part, | |
602 | UFSInitPartition, | |
603 | UFSLoadFile, | |
604 | UFSGetDirEntry, | |
f083c6c3 A |
605 | 0, |
606 | kBIOSDevTypeHardDrive); | |
75b89a82 A |
607 | break; |
608 | ||
609 | default: | |
610 | bvr = newFDiskBVRef( | |
611 | biosdev, partno, | |
612 | part->relsect, | |
613 | part, | |
f083c6c3 A |
614 | 0, 0, 0, 0, |
615 | kBIOSDevTypeHardDrive); | |
75b89a82 A |
616 | break; |
617 | } | |
618 | ||
619 | if ( bvr ) | |
620 | { | |
621 | bvr->next = map->bvr; | |
622 | map->bvr = bvr; | |
623 | map->bvrcnt++; | |
624 | } | |
14c7c974 | 625 | } |
14c7c974 | 626 | |
75b89a82 A |
627 | // Booting from a CD with an UFS filesystem embedded |
628 | // in a booter partition. | |
629 | ||
630 | if ( booterUFS ) | |
631 | { | |
632 | if ( map->bvrcnt == 0 ) | |
633 | { | |
634 | map->bvr = booterUFS; | |
635 | map->bvrcnt++; | |
636 | } | |
637 | else free( booterUFS ); | |
638 | } | |
639 | } | |
640 | } while (0); | |
641 | ||
f083c6c3 A |
642 | /* |
643 | * If no FDisk partition, then we will check for | |
644 | * an Apple partition map elsewhere. | |
645 | */ | |
646 | #if 0 | |
647 | if (map->bvrcnt == 0) { | |
648 | static struct fdisk_part cdpart; | |
649 | cdpart.systid = 0xCD; | |
650 | ||
651 | /* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */ | |
652 | bvr = newFDiskBVRef( | |
653 | biosdev, 0, | |
654 | 0, | |
655 | &cdpart, | |
656 | HFSInitPartition, | |
657 | HFSLoadFile, | |
658 | HFSGetDirEntry, | |
659 | 0, | |
660 | kBIOSDevTypeHardDrive); | |
661 | bvr->next = map->bvr; | |
662 | map->bvr = bvr; | |
663 | map->bvrcnt++; | |
664 | } | |
665 | #endif | |
666 | ||
75b89a82 A |
667 | if (countPtr) *countPtr = map ? map->bvrcnt : 0; |
668 | ||
669 | return map ? map->bvr : NULL; | |
670 | } | |
671 | ||
f083c6c3 A |
672 | //========================================================================== |
673 | ||
674 | static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr ) | |
675 | { | |
676 | struct DiskBVMap * map; | |
677 | struct Block0 *block0_p; | |
678 | unsigned int blksize; | |
679 | unsigned int factor; | |
680 | void *buffer = malloc(BPS); | |
681 | ||
682 | /* Check for alternate block size */ | |
683 | if (readBytes( biosdev, 0, BPS, buffer ) != 0) { | |
684 | return NULL; | |
685 | } | |
686 | block0_p = buffer; | |
687 | if (NXSwapBigShortToHost(block0_p->sbSig) == BLOCK0_SIGNATURE) { | |
688 | blksize = NXSwapBigShortToHost(block0_p->sbBlkSize); | |
689 | if (blksize != BPS) { | |
690 | free(buffer); | |
691 | buffer = malloc(blksize); | |
692 | } | |
693 | factor = blksize / BPS; | |
694 | } else { | |
695 | blksize = BPS; | |
696 | factor = 1; | |
697 | } | |
698 | ||
699 | do { | |
700 | // Create a new mapping. | |
701 | ||
702 | map = (struct DiskBVMap *) malloc( sizeof(*map) ); | |
703 | if ( map ) | |
704 | { | |
705 | int error; | |
706 | DPME *dpme_p = (DPME *)buffer; | |
707 | UInt32 i, npart = UINT_MAX; | |
708 | BVRef bvr; | |
709 | ||
710 | map->biosdev = biosdev; | |
711 | map->bvr = NULL; | |
712 | map->bvrcnt = 0; | |
713 | map->next = gDiskBVMap; | |
714 | gDiskBVMap = map; | |
715 | ||
716 | for (i=0; i<npart; i++) { | |
717 | error = readBytes( biosdev, (kAPMSector + i) * factor, blksize, buffer ); | |
718 | ||
719 | if (error || NXSwapBigShortToHost(dpme_p->dpme_signature) != DPME_SIGNATURE) { | |
720 | break; | |
721 | } | |
722 | ||
723 | if (i==0) { | |
724 | npart = NXSwapBigLongToHost(dpme_p->dpme_map_entries); | |
725 | } | |
726 | /* | |
727 | printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n", | |
728 | dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "", | |
729 | dpme.dpme_pblock_start, dpme.dpme_pblocks, | |
730 | dpme.dpme_lblock_start, dpme.dpme_lblocks, | |
731 | dpme.dpme_boot_block); | |
732 | */ | |
733 | ||
734 | if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) { | |
735 | bvr = newAPMBVRef(biosdev, | |
736 | i, | |
737 | NXSwapBigLongToHost(dpme_p->dpme_pblock_start) * factor, | |
738 | dpme_p, | |
739 | HFSInitPartition, | |
740 | HFSLoadFile, | |
741 | HFSGetDirEntry, | |
742 | 0, | |
743 | kBIOSDevTypeHardDrive); | |
744 | bvr->next = map->bvr; | |
745 | map->bvr = bvr; | |
746 | map->bvrcnt++; | |
747 | } | |
748 | } | |
749 | } | |
750 | } while (0); | |
751 | ||
752 | free(buffer); | |
753 | ||
754 | if (countPtr) *countPtr = map ? map->bvrcnt : 0; | |
755 | ||
756 | return map ? map->bvr : NULL; | |
757 | } | |
758 | ||
759 | //========================================================================== | |
760 | ||
761 | BVRef diskScanBootVolumes( int biosdev, int * countPtr ) | |
762 | { | |
763 | struct DiskBVMap * map; | |
764 | BVRef bvr; | |
765 | int count = 0; | |
766 | ||
767 | // Find an existing mapping for this device. | |
768 | ||
769 | for ( map = gDiskBVMap; map; map = map->next ) { | |
770 | if ( biosdev == map->biosdev ) { | |
771 | count = map->bvrcnt; | |
772 | break; | |
773 | } | |
774 | } | |
775 | ||
776 | if (map == NULL) { | |
777 | bvr = diskScanFDiskBootVolumes(biosdev, &count); | |
778 | if (bvr == NULL) { | |
779 | bvr = diskScanAPMBootVolumes(biosdev, &count); | |
780 | } | |
781 | } else { | |
782 | bvr = map->bvr; | |
783 | } | |
784 | if (countPtr) *countPtr = count; | |
785 | return bvr; | |
786 | } | |
787 | ||
788 | ||
75b89a82 A |
789 | //========================================================================== |
790 | ||
791 | static const struct NamedValue fdiskTypes[] = | |
792 | { | |
793 | { 0x07, "Windows NTFS" }, | |
794 | { 0x0c, "Windows FAT32" }, | |
795 | { 0x83, "Linux" }, | |
796 | { FDISK_UFS, "Apple UFS" }, | |
797 | { FDISK_HFS, "Apple HFS" }, | |
798 | { FDISK_BOOTER, "Apple Boot/UFS" }, | |
f083c6c3 | 799 | { 0xCD, "CD-ROM" }, |
75b89a82 A |
800 | { 0x00, 0 } /* must be last */ |
801 | }; | |
802 | ||
803 | static void getVolumeDescription( BVRef bvr, char * str, long strMaxLen ) | |
804 | { | |
805 | unsigned char type = (unsigned char) bvr->part_type; | |
806 | const char * name = getNameForValue( fdiskTypes, type ); | |
807 | ||
f083c6c3 A |
808 | if (name == NULL) |
809 | name = bvr->type_name; | |
810 | ||
75b89a82 A |
811 | if ( name ) |
812 | sprintf( str, "hd(%d,%d) %s", | |
f083c6c3 | 813 | BIOS_DEV_UNIT(bvr), bvr->part_no, name ); |
75b89a82 A |
814 | else |
815 | sprintf( str, "hd(%d,%d) TYPE %02x", | |
f083c6c3 | 816 | BIOS_DEV_UNIT(bvr), bvr->part_no, type ); |
75b89a82 A |
817 | } |
818 | ||
f083c6c3 | 819 | |
75b89a82 A |
820 | //========================================================================== |
821 | ||
822 | int readBootSector( int biosdev, unsigned int secno, void * buffer ) | |
823 | { | |
824 | struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer; | |
825 | int error; | |
826 | ||
827 | if ( bootSector == NULL ) | |
828 | { | |
829 | if ( gBootSector == NULL ) | |
830 | { | |
831 | gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector)); | |
832 | if ( gBootSector == NULL ) return -1; | |
14c7c974 | 833 | } |
75b89a82 | 834 | bootSector = gBootSector; |
14c7c974 | 835 | } |
75b89a82 A |
836 | |
837 | error = readBytes( biosdev, secno, BPS, bootSector ); | |
838 | if ( error || bootSector->signature != DISK_SIGNATURE ) | |
839 | return -1; | |
840 | ||
841 | return 0; | |
842 | } | |
843 | ||
844 | //========================================================================== | |
845 | // Handle seek request from filesystem modules. | |
846 | ||
847 | void diskSeek( BVRef bvr, long long position ) | |
848 | { | |
849 | bvr->fs_boff = position / BPS; | |
850 | } | |
851 | ||
852 | //========================================================================== | |
853 | // Handle read request from filesystem modules. | |
854 | ||
855 | int diskRead( BVRef bvr, long addr, long length ) | |
856 | { | |
857 | return readBytes( bvr->biosdev, | |
858 | bvr->fs_boff + bvr->part_boff, | |
859 | length, | |
860 | (void *) addr ); | |
14c7c974 | 861 | } |
f083c6c3 A |
862 | |
863 | void turnOffFloppy(void) | |
864 | { | |
865 | /* | |
866 | * Disable floppy: | |
867 | * Hold controller in reset, | |
868 | * disable DMA and IRQ, | |
869 | * turn off floppy motors. | |
870 | */ | |
871 | outb(0x3F2, 0x00); | |
872 | } |