]> git.saurik.com Git - apple/boot.git/blame - i386/libsaio/sys.c
boot-132.tar.gz
[apple/boot.git] / i386 / libsaio / sys.c
CommitLineData
14c7c974 1/*
57c72a9a 2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
14c7c974
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
57c72a9a 6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
4f6e3300
A
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
57c72a9a 9 * Source License Version 2.0 (the "License"). You may not use this file
4f6e3300
A
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.
14c7c974
A
13 *
14 * The Original Code and all software distributed under the License are
4f6e3300 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14c7c974
A
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
4f6e3300
A
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.
14c7c974
A
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 * Copyright (c) 1988 Carnegie-Mellon University
29 * Copyright (c) 1987 Carnegie-Mellon University
30 * All rights reserved. The CMU software License Agreement specifies
31 * the terms and conditions for use and redistribution.
32 *
33 */
34/*
35 * HISTORY
36 * Revision 2.3 88/08/08 13:47:07 rvb
37 * Allocate buffers dynamically vs statically.
38 * Now b[i] and i_fs and i_buf, are allocated dynamically.
39 * boot_calloc(size) allocates and zeros a buffer rounded to a NPG
40 * boundary.
41 * Generalize boot spec to allow, xx()/mach, xx(n,[a..h])/mach,
42 * xx([a..h])/mach, ...
43 * Also default "xx" if unspecified and alloc just "/mach",
44 * where everything is defaulted
45 * Add routine, ptol(), to parse partition letters.
46 *
47 */
48
49/*
50 * Copyright (c) 1982, 1986 Regents of the University of California.
51 * All rights reserved. The Berkeley software License Agreement
52 * specifies the terms and conditions for redistribution.
53 *
54 * @(#)sys.c 7.1 (Berkeley) 6/5/86
55 */
56
14c7c974 57#include "libsaio.h"
f083c6c3 58#include "bootstruct.h"
bba600dd
A
59#include <sys/md5.h>
60#include <uuid/uuid.h>
61#include <Kernel/uuid/namespace.h>
75b89a82
A
62
63struct devsw {
64 const char * name;
65 unsigned char biosdev;
f083c6c3 66 int type;
14c7c974
A
67};
68
75b89a82
A
69static struct devsw devsw[] =
70{
f083c6c3
A
71 { "sd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_SD */
72 { "hd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_HD */
73 { "fd", 0x00, kBIOSDevTypeFloppy }, /* DEV_FD */
74 { "en", 0xE0, kBIOSDevTypeNetwork }, /* DEV_EN */
75b89a82
A
75 { 0, 0 }
76};
14c7c974 77
75b89a82
A
78/*
79 * Max number of file descriptors.
80 */
81#define NFILES 6
14c7c974 82
75b89a82 83static struct iob iob[NFILES];
14c7c974 84
75b89a82 85void * gFSLoadAddress = 0;
14c7c974 86
57c72a9a 87//static BVRef getBootVolumeRef( const char * path, const char ** outPath );
75b89a82 88static BVRef newBootVolumeRef( int biosdev, int partno );
14c7c974 89
57c72a9a
A
90//==========================================================================
91// LoadVolumeFile - LOW-LEVEL FILESYSTEM FUNCTION.
92// Load the specified file from the specified volume
93// to the load buffer at LOAD_ADDR.
94// If the file is fat, load only the i386 portion.
95
96long LoadVolumeFile(BVRef bvr, const char *filePath)
97{
98 long fileSize;
99
100 // Read file into load buffer. The data in the load buffer will be
101 // overwritten by the next LoadFile() call.
102
103 gFSLoadAddress = (void *) LOAD_ADDR;
104
105 fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
106
107 // Return the size of the file, or -1 if load failed.
108
109 return fileSize;
110}
111
75b89a82
A
112//==========================================================================
113// LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
114// Load the specified file to the load buffer at LOAD_ADDR.
f083c6c3 115// If the file is fat, load only the i386 portion.
14c7c974 116
75b89a82
A
117long LoadFile(const char * fileSpec)
118{
119 const char * filePath;
75b89a82 120 BVRef bvr;
14c7c974 121
75b89a82 122 // Resolve the boot volume from the file spec.
14c7c974 123
75b89a82
A
124 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
125 return -1;
14c7c974 126
57c72a9a
A
127 return LoadVolumeFile(bvr, filePath);
128}
129
130long ReadFileAtOffset(const char * fileSpec, void *buffer, unsigned long offset, unsigned long length)
131{
132 const char *filePath;
133 BVRef bvr;
134
135 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
136 return -1;
137
138 if (bvr->fs_readfile == NULL)
139 return -1;
140
141 return bvr->fs_readfile(bvr, (char *)filePath, buffer, offset, length);
142}
143
144long LoadThinFatFile(const char *fileSpec, void **binary)
145{
146 const char *filePath;
147 FSReadFile readFile;
148 BVRef bvr;
bba600dd 149 unsigned long length, length2;
57c72a9a
A
150
151 // Resolve the boot volume from the file spec.
152
153 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
154 return -1;
155
156 *binary = (void *)kLoadAddr;
157
75b89a82
A
158 // Read file into load buffer. The data in the load buffer will be
159 // overwritten by the next LoadFile() call.
14c7c974 160
75b89a82 161 gFSLoadAddress = (void *) LOAD_ADDR;
14c7c974 162
57c72a9a
A
163 readFile = bvr->fs_readfile;
164
165 if (readFile != NULL) {
166 // Read the first 4096 bytes (fat header)
167 length = readFile(bvr, (char *)filePath, *binary, 0, 0x1000);
168 if (length > 0) {
169 if (ThinFatFile(binary, &length) == 0) {
170 // We found a fat binary; read only the thin part
171 length = readFile(bvr, (char *)filePath,
172 (void *)kLoadAddr, (unsigned long)(*binary) - kLoadAddr, length);
173 *binary = (void *)kLoadAddr;
174 } else {
175 // Not a fat binary; read the rest of the file
176 length2 = readFile(bvr, (char *)filePath, (void *)(kLoadAddr + length), length, 0);
177 if (length2 == -1) return -1;
178 length += length2;
179 }
180 }
181 } else {
182 length = bvr->fs_loadfile(bvr, (char *)filePath);
183 if (length > 0) {
184 ThinFatFile(binary, &length);
185 }
186 }
187
188 return length;
14c7c974
A
189}
190
bba600dd
A
191long GetFSUUID(char *spec, char *uuidStr)
192{
193 BVRef bvr;
194 long rval = -1;
195 const char *devSpec;
196
197 if ((bvr = getBootVolumeRef(spec, &devSpec)) == NULL)
198 return -1;
199
200 if(bvr->fs_getuuid)
201 rval = bvr->fs_getuuid(bvr, uuidStr);
202
203 return rval;
204}
205
206
207// filesystem-specific getUUID functions call this shared string generator
208long CreateUUIDString(uint8_t uubytes[], int nbytes, char *uuidStr)
209{
210 unsigned fmtbase, fmtidx, i;
211 uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 };
212 char *p = uuidStr;
213 MD5_CTX md5c;
214 uint8_t mdresult[16];
215
216 bzero(mdresult, sizeof(mdresult));
217
218 // just like AppleFileSystemDriver
219 MD5Init(&md5c);
220 MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1));
221 MD5Update(&md5c, uubytes, nbytes);
222 MD5Final(mdresult, &md5c);
223
224 // this UUID has been made version 3 style (i.e. via namespace)
225 // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte)
226 mdresult[6] = 0x30 | ( mdresult[6] & 0x0F );
227 mdresult[8] = 0x80 | ( mdresult[8] & 0x3F );
228
229
230 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
231 i = 0; fmtbase = 0;
232 for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) {
233 for(i=0; i < uuidfmt[fmtidx]; i++) {
234 uint8_t byte = mdresult[fmtbase+i];
235 char nib;
236
237 nib = byte >> 4;
238 *p = nib + '0'; // 0x4 -> '4'
239 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
240 p++;
241
242 nib = byte & 0xf;
243 *p = nib + '0'; // 0x4 -> '4'
244 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
245 p++;
246
247 }
248 fmtbase += i;
249 if(fmtidx < sizeof(uuidfmt)-1)
250 *(p++) = '-';
251 else
252 *p = '\0';
253 }
254
255 return 0;
256}
257
57c72a9a 258
75b89a82
A
259//==========================================================================
260// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
261// Fetch the next directory entry for the given directory.
262
263long GetDirEntry(const char * dirSpec, long * dirIndex, const char ** name,
264 long * flags, long * time)
14c7c974 265{
75b89a82
A
266 const char * dirPath;
267 BVRef bvr;
268
269 // Resolve the boot volume from the dir spec.
270
271 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
14c7c974 272 return -1;
75b89a82
A
273
274 // Return 0 on success, or -1 if there are no additional entries.
275
276 return bvr->fs_getdirentry( bvr,
277 /* dirPath */ (char *)dirPath,
278 /* dirIndex */ dirIndex,
57c72a9a 279 /* dirEntry */ (char **)name, flags, time, 0, 0 );
14c7c974
A
280}
281
75b89a82
A
282//==========================================================================
283// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
284// Get attributes for the specified file.
285
57c72a9a 286static char* gMakeDirSpec;
f083c6c3 287
75b89a82
A
288long GetFileInfo(const char * dirSpec, const char * name,
289 long * flags, long * time)
14c7c974 290{
75b89a82
A
291 long index = 0;
292 const char * entryName;
293
57c72a9a
A
294 if (gMakeDirSpec == 0)
295 gMakeDirSpec = (char *)malloc(1024);
296
f083c6c3
A
297 if (!dirSpec) {
298 long idx, len;
299
300 len = strlen(name);
301
302 for (idx = len; idx && (name[idx] != '/' && name[idx] != '\\'); idx--) {}
303 if (idx == 0) {
304 gMakeDirSpec[0] = '/';
305 gMakeDirSpec[1] = '\0';
306 } else {
307 idx++;
308 strncpy(gMakeDirSpec, name, idx);
309 name += idx;
310 }
311 dirSpec = gMakeDirSpec;
312 }
313
75b89a82
A
314 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
315 {
316 if (strcmp(entryName, name) == 0)
317 return 0; // success
318 }
319 return -1; // file not found
14c7c974
A
320}
321
57c72a9a
A
322long GetFileBlock(const char *fileSpec, unsigned long long *firstBlock)
323{
324 const char * filePath;
325 BVRef bvr;
326
327 // Resolve the boot volume from the file spec.
328
329 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) {
330 printf("Boot volume for '%s' is bogus\n", fileSpec);
331 return -1;
332 }
333
334 return bvr->fs_getfileblock(bvr, (char *)filePath, firstBlock);
335}
336
75b89a82
A
337//==========================================================================
338// iob_from_fdesc()
339//
340// Return a pointer to an allocated 'iob' based on the file descriptor
341// provided. Returns NULL if the file descriptor given is invalid.
342
343static struct iob * iob_from_fdesc(int fdesc)
14c7c974 344{
75b89a82
A
345 register struct iob * io;
346
347 if (fdesc < 0 || fdesc >= NFILES ||
348 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
349 return NULL;
350 else
351 return io;
14c7c974
A
352}
353
57c72a9a 354#if UNUSED
75b89a82
A
355//==========================================================================
356// openmem()
357
358int openmem(char * buf, int len)
14c7c974 359{
75b89a82
A
360 int fdesc;
361 struct iob * io;
14c7c974 362
75b89a82 363 // Locate a free descriptor slot.
14c7c974 364
75b89a82
A
365 for (fdesc = 0; fdesc < NFILES; fdesc++)
366 if (iob[fdesc].i_flgs == 0)
367 goto gotfile;
14c7c974 368
75b89a82 369 stop("Out of file descriptors");
14c7c974 370
75b89a82
A
371gotfile:
372 io = &iob[fdesc];
373 bzero(io, sizeof(*io));
14c7c974 374
75b89a82
A
375 // Mark the descriptor as taken. Set the F_MEM flag to indicate
376 // that the file buffer is provided by the caller.
14c7c974 377
75b89a82
A
378 io->i_flgs = F_ALLOC | F_MEM;
379 io->i_buf = buf;
380 io->i_filesize = len;
14c7c974 381
75b89a82 382 return fdesc;
14c7c974 383}
57c72a9a 384#endif
14c7c974 385
75b89a82
A
386//==========================================================================
387// open() - Open the file specified by 'path' for reading.
14c7c974 388
75b89a82 389int open(const char * path, int flags)
14c7c974 390{
75b89a82
A
391 int fdesc, i;
392 struct iob * io;
393 const char * filePath;
394 BVRef bvr;
14c7c974 395
75b89a82 396 // Locate a free descriptor slot.
14c7c974 397
75b89a82
A
398 for (fdesc = 0; fdesc < NFILES; fdesc++)
399 if (iob[fdesc].i_flgs == 0)
400 goto gotfile;
14c7c974 401
75b89a82 402 stop("Out of file descriptors");
14c7c974 403
75b89a82
A
404gotfile:
405 io = &iob[fdesc];
406 bzero(io, sizeof(*io));
407
408 // Mark the descriptor as taken.
409
410 io->i_flgs = F_ALLOC;
411
412 // Resolve the boot volume from the file spec.
413
414 if ((bvr = getBootVolumeRef(path, &filePath)) == NULL)
415 goto error;
416
417 // Find the next available memory block in the download buffer.
418
419 io->i_buf = (char *) LOAD_ADDR;
14c7c974 420 for (i = 0; i < NFILES; i++)
75b89a82
A
421 {
422 if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) continue;
423 io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
424 }
425
426 // Load entire file into memory. Unnecessary open() calls must
427 // be avoided.
428
429 gFSLoadAddress = io->i_buf;
430 io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
f083c6c3
A
431 if (io->i_filesize < 0) {
432 goto error;
433 }
75b89a82
A
434
435 return fdesc;
436
437error:
438 close(fdesc);
439 return -1;
14c7c974
A
440}
441
75b89a82
A
442//==========================================================================
443// close() - Close a file descriptor.
14c7c974 444
75b89a82 445int close(int fdesc)
14c7c974 446{
75b89a82 447 struct iob * io;
14c7c974 448
75b89a82
A
449 if ((io = iob_from_fdesc(fdesc)) == NULL)
450 return (-1);
14c7c974 451
75b89a82 452 io->i_flgs = 0;
14c7c974 453
75b89a82 454 return 0;
14c7c974 455}
75b89a82
A
456
457//==========================================================================
458// lseek() - Reposition the byte offset of the file descriptor from the
459// beginning of the file. Returns the relocated offset.
460
461int b_lseek(int fdesc, int offset, int ptr)
14c7c974 462{
75b89a82 463 struct iob * io;
14c7c974 464
75b89a82
A
465 if ((io = iob_from_fdesc(fdesc)) == NULL)
466 return (-1);
14c7c974 467
75b89a82 468 io->i_offset = offset;
14c7c974 469
75b89a82 470 return offset;
14c7c974
A
471}
472
75b89a82
A
473//==========================================================================
474// tell() - Returns the byte offset of the file descriptor.
14c7c974 475
75b89a82 476int tell(int fdesc)
14c7c974 477{
75b89a82 478 struct iob * io;
14c7c974 479
75b89a82
A
480 if ((io = iob_from_fdesc(fdesc)) == NULL)
481 return 0;
482
483 return io->i_offset;
14c7c974
A
484}
485
75b89a82
A
486//==========================================================================
487// read() - Read up to 'count' bytes of data from the file descriptor
488// into the buffer pointed to by buf.
489
490int read(int fdesc, char * buf, int count)
14c7c974 491{
75b89a82
A
492 struct iob * io;
493
494 if ((io = iob_from_fdesc(fdesc)) == NULL)
495 return (-1);
496
f083c6c3 497 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
75b89a82
A
498 count = io->i_filesize - io->i_offset;
499
500 if (count <= 0)
501 return 0; // end of file
502
503 bcopy(io->i_buf + io->i_offset, buf, count);
504
505 io->i_offset += count;
506
507 return count;
14c7c974
A
508}
509
75b89a82
A
510//==========================================================================
511// file_size() - Returns the size of the file described by the file
512// descriptor.
513
514int file_size(int fdesc)
14c7c974 515{
75b89a82
A
516 struct iob * io;
517
518 if ((io = iob_from_fdesc(fdesc)) == 0)
519 return 0;
520
521 return io->i_filesize;
14c7c974
A
522}
523
75b89a82
A
524//==========================================================================
525
57c72a9a
A
526struct dirstuff * vol_opendir(BVRef bvr, const char * path)
527{
528 struct dirstuff * dirp = 0;
529
530 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
531 if (dirp == NULL)
532 goto error;
533
534 dirp->dir_path = newString(path);
535 if (dirp->dir_path == NULL)
536 goto error;
537
538 dirp->dir_bvr = bvr;
539
540 return dirp;
541
542error:
543 closedir(dirp);
544 return NULL;
545}
546
547//==========================================================================
548
75b89a82 549struct dirstuff * opendir(const char * path)
14c7c974 550{
75b89a82
A
551 struct dirstuff * dirp = 0;
552 const char * dirPath;
553 BVRef bvr;
554
555 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
556 goto error;
557
558 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
559 if (dirp == NULL)
560 goto error;
561
562 dirp->dir_path = newString(dirPath);
563 if (dirp->dir_path == NULL)
564 goto error;
565
566 dirp->dir_bvr = bvr;
567
568 return dirp;
14c7c974 569
75b89a82
A
570error:
571 closedir(dirp);
572 return NULL;
14c7c974
A
573}
574
75b89a82 575//==========================================================================
14c7c974 576
75b89a82 577int closedir(struct dirstuff * dirp)
14c7c974 578{
75b89a82
A
579 if (dirp) {
580 if (dirp->dir_path) free(dirp->dir_path);
581 free(dirp);
582 }
583 return 0;
14c7c974
A
584}
585
75b89a82
A
586//==========================================================================
587
588int readdir(struct dirstuff * dirp, const char ** name, long * flags,
589 long * time)
14c7c974 590{
75b89a82
A
591 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
592 /* dirPath */ dirp->dir_path,
593 /* dirIndex */ &dirp->dir_index,
57c72a9a
A
594 /* dirEntry */ (char **)name, flags, time,
595 0, 0);
596}
597
598//==========================================================================
599
600int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
601 long * time, FinderInfo *finderInfo, long *infoValid)
602{
603 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
604 /* dirPath */ dirp->dir_path,
605 /* dirIndex */ &dirp->dir_index,
606 /* dirEntry */ (char **)name,
607 flags, time,
608 finderInfo, infoValid);
14c7c974
A
609}
610
75b89a82
A
611//==========================================================================
612
613int currentdev()
14c7c974 614{
bba600dd
A
615 printf("currentdev = %d\n", bootInfo->kernDev);
616 return bootInfo->kernDev;
14c7c974
A
617}
618
75b89a82
A
619//==========================================================================
620
621int switchdev(int dev)
14c7c974 622{
bba600dd 623 bootInfo->kernDev = dev;
75b89a82
A
624 return dev;
625}
14c7c974 626
75b89a82 627//==========================================================================
14c7c974 628
75b89a82
A
629const char * usrDevices()
630{
f083c6c3
A
631 if (gBootFileType == kNetworkDeviceType)
632 return "";
633 return "/private/Drivers/i386";
75b89a82 634}
14c7c974 635
75b89a82 636//==========================================================================
14c7c974 637
f083c6c3
A
638const char * systemConfigDir()
639{
640 if (gBootFileType == kNetworkDeviceType)
641 return "";
642 return "/Library/Preferences/SystemConfiguration";
643}
644
645//==========================================================================
646
647int gBootFileType;
648
75b89a82
A
649BVRef scanBootVolumes( int biosdev, int * count )
650{
651 BVRef bvr = 0;
14c7c974 652
f083c6c3
A
653 bvr = diskScanBootVolumes(biosdev, count);
654 if (bvr == NULL) {
655 bvr = nbpScanBootVolumes(biosdev, count);
656 if (bvr != NULL) {
657 gBootFileType = kNetworkDeviceType;
658 }
659 } else {
660 gBootFileType = kBlockDeviceType;
75b89a82
A
661 }
662 return bvr;
14c7c974
A
663}
664
75b89a82 665//==========================================================================
14c7c974 666
75b89a82
A
667BVRef selectBootVolume( BVRef chain )
668{
669 BVRef bvr, bvr1 = 0, bvr2 = 0;
14c7c974 670
75b89a82
A
671 for ( bvr = chain; bvr; bvr = bvr->next )
672 {
673 if ( bvr->flags & kBVFlagNativeBoot ) bvr1 = bvr;
674 if ( bvr->flags & kBVFlagPrimary ) bvr2 = bvr;
675 }
14c7c974 676
f083c6c3
A
677 bvr = bvr2 ? bvr2 :
678 bvr1 ? bvr1 : chain;
14c7c974 679
75b89a82 680 return bvr;
14c7c974
A
681}
682
75b89a82
A
683//==========================================================================
684
14c7c974
A
685#define LP '('
686#define RP ')'
f083c6c3 687int gBIOSDev;
14c7c974 688
57c72a9a 689BVRef getBootVolumeRef( const char * path, const char ** outPath )
14c7c974 690{
75b89a82
A
691 const char * cp;
692 BVRef bvr;
bba600dd
A
693 int type = B_TYPE( bootInfo->kernDev );
694 int unit = B_UNIT( bootInfo->kernDev );
695 int part = B_PARTITION( bootInfo->kernDev );
75b89a82
A
696 int biosdev = gBIOSDev;
697 static BVRef lastBVR = 0;
698 static int lastKernDev;
699
700 // Search for left parenthesis in the path specification.
701
702 for (cp = path; *cp; cp++) {
703 if (*cp == LP || *cp == '/') break;
14c7c974 704 }
14c7c974 705
75b89a82
A
706 if (*cp != LP) // no left paren found
707 {
708 cp = path;
bba600dd 709 if ( lastBVR && lastKernDev == bootInfo->kernDev )
75b89a82
A
710 {
711 bvr = lastBVR;
712 goto quick_exit;
713 }
714 }
715 else if ((cp - path) == 2) // found "xx("
716 {
717 const struct devsw * dp;
718 const char * xp = path;
719 int i;
720
721 cp++;
722
723 // Check the 2 character device name pointed by 'xp'.
724
725 for (dp = devsw; dp->name; dp++)
726 {
727 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
728 break; // found matching entry
729 }
730 if (dp->name == NULL)
731 {
732 error("Unknown device '%c%c'\n", xp[0], xp[1]);
733 return NULL;
734 }
735 type = dp - devsw; // kerndev type
736
737 // Extract the optional unit number from the specification.
738 // hd(unit) or hd(unit, part).
739
740 i = 0;
741 while (*cp >= '0' && *cp <= '9')
742 {
743 i = i * 10 + *cp++ - '0';
744 unit = i;
745 }
746
747 // Extract the optional partition number from the specification.
748
749 if (*cp == ',')
750 part = atoi(++cp);
751
752 // Skip past the right paren.
753
754 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
755 if (*cp == RP) cp++;
756
f083c6c3 757 biosdev = dp->biosdev + unit;
75b89a82
A
758 }
759 else
760 {
761 // Bad device specifier, skip past the right paren.
14c7c974 762
75b89a82
A
763 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
764 if (*cp == RP) cp++;
765 }
14c7c974 766
75b89a82
A
767 if ((bvr = newBootVolumeRef(biosdev, part)) == NULL)
768 {
769 // error("newBootVolumeRef() error\n");
770 return NULL;
771 }
14c7c974 772
75b89a82
A
773 // Record the most recent device parameters in the
774 // KernBootStruct.
14c7c974 775
bba600dd 776 bootInfo->kernDev = biosdev;
14c7c974 777
75b89a82 778 lastBVR = bvr;
bba600dd 779 lastKernDev = bootInfo->kernDev;
14c7c974 780
75b89a82
A
781quick_exit:
782 // Returns the file path following the device spec.
783 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
14c7c974 784
75b89a82 785 *outPath = cp;
14c7c974 786
75b89a82 787 return bvr;
14c7c974
A
788}
789
75b89a82 790//==========================================================================
14c7c974 791
75b89a82 792static BVRef newBootVolumeRef( int biosdev, int partno )
14c7c974 793{
75b89a82 794 BVRef bvr, bvr1, bvrChain;
14c7c974 795
75b89a82 796 // Fetch the volume list from the device.
14c7c974 797
75b89a82
A
798 bvrChain = scanBootVolumes( biosdev, NULL );
799
800 // Look for a perfect match based on device and partition number.
801
802 for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
803 {
804 if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
805
806 bvr1 = bvr;
807 if ( bvr->part_no == partno ) break;
808 }
809
810 return bvr ? bvr : bvr1;
14c7c974 811}