Chameleon

Chameleon Svn Source Tree

Root/branches/JrCs/i386/libsaio/sys.c

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 * 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.c7.1 (Berkeley) 6/5/86
55 */
56
57/* Copyright 2007 VMware Inc.
58 "Preboot" ramdisk support added by David Elliott
59 */
60
61#include <AvailabilityMacros.h>
62
63#include "libsaio.h"
64#include "bootstruct.h"
65#include "ramdisk.h"
66#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
67# include <Kernel/libkern/crypto/md5.h>
68#else
69# include <sys/md5.h>
70#endif
71#include <uuid/uuid.h>
72#if 0 /* No OS X release has ever included this. */
73#include <Kernel/uuid/namespace.h>
74#else
75/* copied from uuid/namespace.h, just like BootX's fs.c does. */
76UUID_DEFINE( kFSUUIDNamespaceSHA1, 0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC );
77#endif
78
79extern int multiboot_partition;
80extern int multiboot_partition_set;
81
82struct devsw {
83 const char * name;
84 // size increased from char to short to handle non-BIOS internal devices
85 unsigned short biosdev;
86 int type;
87};
88
89static struct devsw devsw[] =
90{
91 { "sd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_SD */
92 { "hd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_HD */
93 { "fd", 0x00, kBIOSDevTypeFloppy }, /* DEV_FD */
94 { "en", 0xE0, kBIOSDevTypeNetwork }, /* DEV_EN */
95 { "rd", 0x100, kBIOSDevTypeHardDrive },
96 { "bt", 0x101, kBIOSDevTypeHardDrive }, // turbo - type for booter partition
97 { 0, 0 }
98};
99
100/*
101 * Max number of file descriptors.
102 */
103#define NFILES 6
104
105static struct iob iob[NFILES];
106
107void * gFSLoadAddress = 0;
108
109// Turbo - save what we think is our original BIOS boot volume if we have one 0xab
110BVRef gBIOSBootVolume = NULL;
111BVRef gBootVolume;
112
113// zef - ramdisk variables
114//extern BVRef gRAMDiskVolume;
115//extern bool gRAMDiskBTAliased;
116
117//static BVRef getBootVolumeRef( const char * path, const char ** outPath );
118static BVRef newBootVolumeRef( int biosdev, int partno );
119
120//==========================================================================
121// LoadVolumeFile - LOW-LEVEL FILESYSTEM FUNCTION.
122// Load the specified file from the specified volume
123// to the load buffer at LOAD_ADDR.
124// If the file is fat, load only the i386 portion.
125
126long LoadVolumeFile(BVRef bvr, const char *filePath)
127{
128 long fileSize;
129
130 // Read file into load buffer. The data in the load buffer will be
131 // overwritten by the next LoadFile() call.
132
133 gFSLoadAddress = (void *) LOAD_ADDR;
134
135 fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
136
137 // Return the size of the file, or -1 if load failed.
138
139 return fileSize;
140}
141
142//==========================================================================
143// LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
144// Load the specified file to the load buffer at LOAD_ADDR.
145// If the file is fat, load only the i386 portion.
146
147long LoadFile(const char * fileSpec)
148{
149 const char * filePath;
150 BVRef bvr;
151
152 // Resolve the boot volume from the file spec.
153
154 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
155 return -1;
156
157 return LoadVolumeFile(bvr, filePath);
158}
159
160long ReadFileAtOffset(const char * fileSpec, void *buffer, uint64_t offset, uint64_t length)
161{
162 const char *filePath;
163 BVRef bvr;
164
165 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
166 return -1;
167
168 if (bvr->fs_readfile == NULL)
169 return -1;
170
171 return bvr->fs_readfile(bvr, (char *)filePath, buffer, offset, length);
172}
173
174long LoadThinFatFile(const char *fileSpec, void **binary)
175{
176 const char *filePath;
177 FSReadFile readFile;
178 BVRef bvr;
179 unsigned long length, length2;
180
181 // Resolve the boot volume from the file spec.
182
183 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
184 return -1;
185
186 *binary = (void *)kLoadAddr;
187
188 // Read file into load buffer. The data in the load buffer will be
189 // overwritten by the next LoadFile() call.
190
191 gFSLoadAddress = (void *) LOAD_ADDR;
192
193 readFile = bvr->fs_readfile;
194
195 if (readFile != NULL) {
196 // Read the first 4096 bytes (fat header)
197 length = readFile(bvr, (char *)filePath, *binary, 0, 0x1000);
198 if (length > 0) {
199 if (ThinFatFile(binary, &length) == 0) {
200if (length == 0)
201return 0;
202 // We found a fat binary; read only the thin part
203 length = readFile(bvr, (char *)filePath,
204 (void *)kLoadAddr, (unsigned long)(*binary) - kLoadAddr, length);
205 *binary = (void *)kLoadAddr;
206 } else {
207 // Not a fat binary; read the rest of the file
208 length2 = readFile(bvr, (char *)filePath, (void *)(kLoadAddr + length), length, 0);
209 if (length2 == -1) return -1;
210 length += length2;
211 }
212 }
213 } else {
214 length = bvr->fs_loadfile(bvr, (char *)filePath);
215 if (length > 0) {
216 ThinFatFile(binary, &length);
217 }
218 }
219
220 return length;
221}
222
223#if UNUSED
224long GetFSUUID(char *spec, char *uuidStr)
225{
226 BVRef bvr;
227 long rval = -1;
228 const char *devSpec;
229
230 if ((bvr = getBootVolumeRef(spec, &devSpec)) == NULL)
231 return -1;
232
233 if(bvr->fs_getuuid)
234 rval = bvr->fs_getuuid(bvr, uuidStr);
235
236 return rval;
237}
238#endif
239
240// filesystem-specific getUUID functions call this shared string generator
241long CreateUUIDString(uint8_t uubytes[], int nbytes, char *uuidStr)
242{
243 unsigned fmtbase, fmtidx, i;
244 uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 };
245 char *p = uuidStr;
246 MD5_CTX md5c;
247 uint8_t mdresult[16];
248
249 bzero(mdresult, sizeof(mdresult));
250
251 // just like AppleFileSystemDriver
252 MD5Init(&md5c);
253 MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1));
254 MD5Update(&md5c, uubytes, nbytes);
255 MD5Final(mdresult, &md5c);
256
257 // this UUID has been made version 3 style (i.e. via namespace)
258 // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte)
259 mdresult[6] = 0x30 | ( mdresult[6] & 0x0F );
260 mdresult[8] = 0x80 | ( mdresult[8] & 0x3F );
261
262
263 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
264 i = 0; fmtbase = 0;
265 for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) {
266 for(i=0; i < uuidfmt[fmtidx]; i++) {
267 uint8_t byte = mdresult[fmtbase+i];
268 char nib;
269
270 nib = byte >> 4;
271 *p = nib + '0'; // 0x4 -> '4'
272 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
273 p++;
274
275 nib = byte & 0xf;
276 *p = nib + '0'; // 0x4 -> '4'
277 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
278 p++;
279
280 }
281 fmtbase += i;
282 if(fmtidx < sizeof(uuidfmt)-1)
283 *(p++) = '-';
284 else
285 *p = '\0';
286 }
287
288 return 0;
289}
290
291
292//==========================================================================
293// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
294// Fetch the next directory entry for the given directory.
295
296long GetDirEntry(const char * dirSpec, long * dirIndex, const char ** name,
297 long * flags, long * time)
298{
299 const char * dirPath;
300 BVRef bvr;
301
302 // Resolve the boot volume from the dir spec.
303
304 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
305 return -1;
306
307 // Return 0 on success, or -1 if there are no additional entries.
308
309 return bvr->fs_getdirentry( bvr,
310 /* dirPath */ (char *)dirPath,
311 /* dirIndex */ dirIndex,
312 /* dirEntry */ (char **)name, flags, time, 0, 0 );
313}
314
315//==========================================================================
316// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
317// Get attributes for the specified file.
318
319static char* gMakeDirSpec;
320
321long GetFileInfo(const char * dirSpec, const char * name,
322 long * flags, long * time)
323{
324 long index = 0;
325 const char * entryName;
326
327 if (gMakeDirSpec == 0)
328 gMakeDirSpec = (char *)malloc(1024);
329
330 if (!dirSpec) {
331 long idx, len;
332
333 len = strlen(name);
334
335 for (idx = len; idx && (name[idx] != '/' && name[idx] != '\\'); idx--) {}
336 if (idx == 0) {
337 gMakeDirSpec[0] = '/';
338 gMakeDirSpec[1] = '\0';
339 } else {
340 idx++;
341 strncpy(gMakeDirSpec, name, idx);
342 name += idx;
343 }
344 dirSpec = gMakeDirSpec;
345 }
346
347 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
348 {
349 if (strcmp(entryName, name) == 0)
350 return 0; // success
351 }
352 return -1; // file not found
353}
354
355long GetFileBlock(const char *fileSpec, unsigned long long *firstBlock)
356{
357 const char * filePath;
358 BVRef bvr;
359
360 // Resolve the boot volume from the file spec.
361
362 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) {
363 printf("Boot volume for '%s' is bogus\n", fileSpec);
364 return -1;
365 }
366
367 return bvr->fs_getfileblock(bvr, (char *)filePath, firstBlock);
368}
369
370//==========================================================================
371// GetFreeFD()
372
373static int GetFreeFd(void)
374{
375intfd;
376
377// Locate a free descriptor slot.
378for (fd = 0; fd < NFILES; fd++) {
379if (iob[fd].i_flgs == 0) {
380return fd;
381 }
382}
383stop("Out of file descriptors");
384// not reached
385return -1;
386}
387
388//==========================================================================
389// iob_from_fdesc()
390//
391// Return a pointer to an allocated 'iob' based on the file descriptor
392// provided. Returns NULL if the file descriptor given is invalid.
393
394static struct iob * iob_from_fdesc(int fdesc)
395{
396 register struct iob * io;
397
398 if (fdesc < 0 || fdesc >= NFILES ||
399 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
400 return NULL;
401 else
402 return io;
403}
404
405#if UNUSED
406//==========================================================================
407// openmem()
408
409int openmem(char * buf, int len)
410{
411 int fdesc;
412 struct iob * io;
413
414 fdesc = GetFreeFd();
415 io = &iob[fdesc];
416 bzero(io, sizeof(*io));
417
418 // Mark the descriptor as taken. Set the F_MEM flag to indicate
419 // that the file buffer is provided by the caller.
420
421 io->i_flgs = F_ALLOC | F_MEM;
422 io->i_buf = buf;
423 io->i_filesize = len;
424
425 return fdesc;
426}
427#endif
428
429//==========================================================================
430// open() - Open the file specified by 'path' for reading.
431
432static int open_bvr(BVRef bvr, const char *filePath, int flags)
433{
434 struct iob * io;
435intfdesc;
436inti;
437
438if (bvr == NULL) {
439return -1;
440}
441
442fdesc = GetFreeFd();
443 io = &iob[fdesc];
444 bzero(io, sizeof(*io));
445
446 // Mark the descriptor as taken.
447 io->i_flgs = F_ALLOC;
448
449 // Find the next available memory block in the download buffer.
450 io->i_buf = (char *) LOAD_ADDR;
451for (i = 0; i < NFILES; i++) {
452if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) {
453continue;
454}
455 io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
456 }
457
458// Load entire file into memory. Unnecessary open() calls must be avoided.
459 gFSLoadAddress = io->i_buf;
460 io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
461 if (io->i_filesize < 0) {
462close(fdesc);
463return -1;
464}
465return fdesc;
466}
467
468int open(const char *path, int flags)
469{
470const char*filepath;
471BVRefbvr;
472
473// Resolve the boot volume from the file spec.
474if ((bvr = getBootVolumeRef(path, &filepath)) != NULL) {
475return open_bvr(bvr, filepath, flags);
476}
477return -1;
478}
479
480int open_bvdev(const char *bvd, const char *path, int flags)
481{
482 const struct devsw*dp;
483const char*cp;
484BVRefbvr;
485inti;
486intlen;
487intunit;
488intpartition;
489
490if ((i = open(path, flags)) >= 0) {
491return i;
492 }
493
494if (bvd == NULL || (len = strlen(bvd)) < 2) {
495return -1;
496}
497
498for (dp=devsw; dp->name; dp++) {
499if (bvd[0] == dp->name[0] && bvd[1] == dp->name[1]) {
500unit = 0;
501partition = 0;
502/* get optional unit and partition */
503if (len >= 5 && bvd[2] == '(') { /* min must be present xx(0) */
504cp = &bvd[3];
505i = 0;
506while ((cp - path) < len && isdigit(*cp)) {
507i = i * 10 + *cp++ - '0';
508unit = i;
509}
510if (*cp++ == ',') {
511i = 0;
512while ((cp - path) < len && isdigit(*cp)) {
513i = i * 10 + *cp++ - '0';
514partition = i;
515}
516}
517}
518// turbo - bt(0,0) hook
519if ((dp->biosdev + unit) == 0x101) {
520// zef - use the ramdisk if available and the alias is active.
521if (gRAMDiskVolume != NULL && gRAMDiskBTAliased) {
522bvr = gRAMDiskVolume;
523} else {
524bvr = gBIOSBootVolume;
525}
526} else {
527bvr = newBootVolumeRef(dp->biosdev + unit, partition);
528}
529return open_bvr(bvr, path, flags);
530}
531 }
532 return -1;
533}
534
535//==========================================================================
536// close() - Close a file descriptor.
537
538int close(int fdesc)
539{
540 struct iob * io;
541
542 if ((io = iob_from_fdesc(fdesc)) == NULL)
543 return (-1);
544
545 io->i_flgs = 0;
546
547 return 0;
548}
549
550//==========================================================================
551// lseek() - Reposition the byte offset of the file descriptor from the
552// beginning of the file. Returns the relocated offset.
553
554int b_lseek(int fdesc, int offset, int ptr)
555{
556 struct iob * io;
557
558 if ((io = iob_from_fdesc(fdesc)) == NULL)
559 return (-1);
560
561 io->i_offset = offset;
562
563 return offset;
564}
565
566//==========================================================================
567// tell() - Returns the byte offset of the file descriptor.
568
569int tell(int fdesc)
570{
571 struct iob * io;
572
573 if ((io = iob_from_fdesc(fdesc)) == NULL)
574 return 0;
575
576 return io->i_offset;
577}
578
579//==========================================================================
580// read() - Read up to 'count' bytes of data from the file descriptor
581// into the buffer pointed to by buf.
582
583int read(int fdesc, char * buf, int count)
584{
585 struct iob * io;
586
587 if ((io = iob_from_fdesc(fdesc)) == NULL)
588 return (-1);
589
590 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
591 count = io->i_filesize - io->i_offset;
592
593 if (count <= 0)
594 return 0; // end of file
595
596 bcopy(io->i_buf + io->i_offset, buf, count);
597
598 io->i_offset += count;
599
600 return count;
601}
602
603//==========================================================================
604// file_size() - Returns the size of the file described by the file
605// descriptor.
606
607int file_size(int fdesc)
608{
609 struct iob * io;
610
611 if ((io = iob_from_fdesc(fdesc)) == 0)
612 return 0;
613
614 return io->i_filesize;
615}
616
617//==========================================================================
618
619struct dirstuff * vol_opendir(BVRef bvr, const char * path)
620{
621 struct dirstuff * dirp = 0;
622
623 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
624 if (dirp == NULL)
625 goto error;
626
627 dirp->dir_path = newString(path);
628 if (dirp->dir_path == NULL)
629 goto error;
630
631 dirp->dir_bvr = bvr;
632
633 return dirp;
634
635error:
636 closedir(dirp);
637 return NULL;
638}
639
640//==========================================================================
641
642struct dirstuff * opendir(const char * path)
643{
644 struct dirstuff * dirp = 0;
645 const char * dirPath;
646 BVRef bvr;
647
648 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
649 goto error;
650
651 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
652 if (dirp == NULL)
653 goto error;
654
655 dirp->dir_path = newString(dirPath);
656 if (dirp->dir_path == NULL)
657 goto error;
658
659 dirp->dir_bvr = bvr;
660
661 return dirp;
662
663error:
664 closedir(dirp);
665 return NULL;
666}
667
668//==========================================================================
669
670int closedir(struct dirstuff * dirp)
671{
672 if (dirp) {
673 if (dirp->dir_path) free(dirp->dir_path);
674 free(dirp);
675 }
676 return 0;
677}
678
679//==========================================================================
680
681int readdir(struct dirstuff * dirp, const char ** name, long * flags,
682 long * time)
683{
684 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
685 /* dirPath */ dirp->dir_path,
686 /* dirIndex */ &dirp->dir_index,
687 /* dirEntry */ (char **)name, flags, time,
688 0, 0);
689}
690
691//==========================================================================
692
693int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
694 long * time, FinderInfo *finderInfo, long *infoValid)
695{
696 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
697 /* dirPath */ dirp->dir_path,
698 /* dirIndex */ &dirp->dir_index,
699 /* dirEntry */ (char **)name,
700 flags, time,
701 finderInfo, infoValid);
702}
703
704//==========================================================================
705
706const char * systemConfigDir()
707{
708 if (gBootFileType == kNetworkDeviceType)
709return "";
710 return "/Library/Preferences/SystemConfiguration";
711}
712
713//==========================================================================
714
715int gBootFileType;
716
717void scanBootVolumes( int biosdev, int * count )
718{
719 BVRef bvr = 0;
720
721 bvr = diskScanBootVolumes(biosdev, count);
722 if (bvr == NULL)
723 {
724 bvr = nbpScanBootVolumes(biosdev, count);
725 if (bvr != NULL)
726 {
727 gBootFileType = kNetworkDeviceType;
728 }
729 }
730 else
731 {
732 gBootFileType = kBlockDeviceType;
733 }
734}
735
736//==========================================================================
737
738void scanDisks(int biosdev, int *count)
739{
740 #define MAX_HDD_COUNT 32
741 int bvCount;
742 int hd = 0;
743
744 // Testing up to MAX_HDD_COUNT hard drives.
745while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
746{
747 bvCount = 0;
748 scanBootVolumes(0x80 + hd, &bvCount);
749 hd++;
750}
751
752 // Also scanning CD/DVD drive.
753if (biosDevIsCDROM(gBIOSDev))
754{
755 bvCount = 0;
756 scanBootVolumes(gBIOSDev, &bvCount);
757}
758}
759
760//==========================================================================
761
762BVRef selectBootVolume( BVRef chain )
763{
764 bool filteredChain = FALSE;
765 bool foundPrimary = FALSE;
766 BVRef bvr, bvr1 = 0, bvr2 = 0;
767
768if (chain->filtered) filteredChain = TRUE;
769
770if (multiboot_partition_set)
771for ( bvr = chain; bvr; bvr = bvr->next )
772if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
773return bvr;
774
775/*
776 * Checking "Default Partition" key in system configuration - use format: hd(x,y) -
777 * to override the default selection.
778 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
779 */
780 const char * val;
781 char testStr[64];
782 int cnt;
783
784 if (getValueForKey("Default Partition", &val, &cnt, &bootInfo->bootConfig) && cnt >= 7 && filteredChain)
785 {
786 for ( bvr = chain; bvr; bvr = bvr->next )
787 {
788 *testStr = '\0';
789 if ( bvr->biosdev >= 0x80 && bvr->biosdev < 0x100
790 && ( bvr->flags & ( kBVFlagSystemVolume|kBVFlagForeignBoot ) ) )
791 {
792 sprintf(testStr, "hd(%d,%d)", bvr->biosdev - 0x80, bvr->part_no);
793 if (strcmp(testStr, val) == 0)
794 return bvr;
795 }
796 }
797 }
798
799/*
800 * Scannig the volume chain backwards and trying to find
801 * a HFS+ volume with valid boot record signature.
802 * If not found any active partition then we will
803 * select this volume as the boot volume.
804 */
805 for ( bvr = chain; bvr; bvr = bvr->next )
806 {
807 if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = TRUE;
808 // zhell -- Undo a regression that was introduced from r491 to 492.
809 // if gBIOSBootVolume is set already, no change is required
810 if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
811 && gBIOSBootVolume
812 && (!filteredChain || (filteredChain && bvr->visible))
813 && bvr->biosdev == gBIOSDev )
814 bvr2 = bvr;
815 // zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
816 // from r491,
817 if ( bvr->flags & kBVFlagBootable
818 && ! gBIOSBootVolume
819 && bvr->biosdev == gBIOSDev )
820 bvr2 = bvr;
821 }
822
823
824/*
825 * Use the standrad method for selecting the boot volume.
826 */
827if (foundPrimary)
828{
829for ( bvr = chain; bvr; bvr = bvr->next )
830{
831if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
832if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
833}
834 }
835
836 bvr = bvr2 ? bvr2 :
837 bvr1 ? bvr1 : chain;
838
839 return bvr;
840}
841
842//==========================================================================
843
844#define LP '('
845#define RP ')'
846int gBIOSDev;
847
848/*!
849 This is like boot2's gBootVolume except it is for the internal use of
850 libsaio to track which volume an unqualified path should be relative to.
851 This replaces bootInfo->kernDev as the carrier of this information.
852 */
853static BVRef gRootVolume;
854
855void setRootVolume(BVRef volume)
856{
857 gRootVolume = volume;
858 // Veto non-native FS. Basically that means don't allow the root volume to
859 // be set to a volume we can't read files from.
860 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
861 gRootVolume = NULL;
862}
863
864void setBootGlobals(BVRef chain)
865{
866 // Record default boot device.
867 gBootVolume = selectBootVolume(chain);
868
869 // turbo - Save the ORIGINAL boot volume too for loading our mkext
870 if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
871
872 setRootVolume(gBootVolume);
873}
874
875/*!
876 Extracts the volume selector from the pathname, returns the selected
877 BVRef, and sets *outPath to the remainder of the path.
878 If the path did not include a volume selector then the current volume
879 is used. When called with a volume selector the current volume
880 is changed to the selected volume unless the volume selector is
881 that of a ramdisk.
882 */
883BVRef getBootVolumeRef( const char * path, const char ** outPath )
884{
885 const char * cp;
886 BVRef bvr = gRootVolume;
887 int biosdev = gBIOSDev;
888
889 // Search for left parenthesis in the path specification.
890
891 for (cp = path; *cp; cp++) {
892 if (*cp == LP || *cp == '/') break;
893 }
894
895 if (*cp != LP) // no left paren found
896 {
897 // Path is using the implicit current device so if there is
898 // no current device, then we must fail.
899 cp = path;
900 if ( gRootVolume == NULL )
901 return NULL;
902 }
903 else if ((cp - path) == 2) // found "xx("
904 {
905 const struct devsw * dp;
906 const char * xp = path;
907 int i;
908 int unit = -1;
909 int part = -1;
910
911 cp++;
912
913 // Check the 2 character device name pointed by 'xp'.
914
915 for (dp = devsw; dp->name; dp++)
916 {
917 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
918 break; // found matching entry
919 }
920 if (dp->name == NULL)
921 {
922 error("Unknown device '%c%c'\n", xp[0], xp[1]);
923 return NULL;
924 }
925
926 // Extract the optional unit number from the specification.
927 // hd(unit) or hd(unit, part).
928
929 i = 0;
930 while (*cp >= '0' && *cp <= '9')
931 {
932 i = i * 10 + *cp++ - '0';
933 unit = i;
934 }
935
936 // Unit is no longer optional and never really was.
937 // If the user failed to specify it then the unit number from the previous kernDev
938 // would have been used which makes little sense anyway.
939 // For example, if the user did fd()/foobar and the current root device was the
940 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
941 if(unit == -1)
942 return NULL;
943
944 // Extract the optional partition number from the specification.
945
946 if (*cp == ',')
947 part = atoi(++cp);
948
949 // If part is not specified part will be -1 whereas before it would have been
950 // whatever the last partition was which makes about zero sense if the device
951 // has been switched.
952
953 // Skip past the right paren.
954
955 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
956 if (*cp == RP) cp++;
957
958 biosdev = dp->biosdev + unit;
959
960 // turbo - bt(0,0) hook
961 if (biosdev == 0x101)
962 {
963 // zef - use the ramdisk if available and the alias is active.
964 if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
965 bvr = gRAMDiskVolume;
966 else
967 bvr = gBIOSBootVolume;
968 }
969 else
970 {
971 bvr = newBootVolumeRef(biosdev, part);
972 }
973
974 if(bvr == NULL)
975 return NULL;
976 }
977 else
978 {
979 // Bad device specifier, skip past the right paren.
980
981 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
982 if (*cp == RP) cp++;
983 // If gRootVolume was NULL, then bvr will be NULL as well which
984 // should be caught by the caller.
985 }
986
987 // Returns the file path following the device spec.
988 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
989
990 *outPath = cp;
991
992 return bvr;
993}
994
995//==========================================================================
996
997// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
998// which caches the information. So it's only allocated on the first run.
999static BVRef newBootVolumeRef( int biosdev, int partno )
1000{
1001 BVRef bvr, bvr1, bvrChain;
1002
1003 // Fetch the volume list from the device.
1004
1005 scanBootVolumes( biosdev, NULL );
1006 bvrChain = getBVChainForBIOSDev(biosdev);
1007
1008 // Look for a perfect match based on device and partition number.
1009
1010 for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1011 {
1012 if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1013
1014 bvr1 = bvr;
1015 if ( bvr->part_no == partno ) break;
1016 }
1017
1018 return bvr ? bvr : bvr1;
1019}
1020

Archive Download this file

Revision: 122