Chameleon

Chameleon Svn Source Tree

Root/trunk/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 "boot.h"
65#include "bootstruct.h"
66#include "ramdisk.h"
67#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
68# include <Kernel/libkern/crypto/md5.h>
69#else
70# include <sys/md5.h>
71#endif
72#include <uuid/uuid.h>
73#if 0 /* No OS X release has ever included this. */
74#include <Kernel/uuid/namespace.h>
75#else
76/* copied from uuid/namespace.h, just like BootX's fs.c does. */
77UUID_DEFINE( kFSUUIDNamespaceSHA1, 0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC );
78#endif
79
80extern int multiboot_partition;
81extern int multiboot_partition_set;
82
83struct devsw {
84 const char * name;
85 // size increased from char to short to handle non-BIOS internal devices
86 unsigned short biosdev;
87 int type;
88};
89
90// Device entries must be ordered by bios device numbers.
91static struct devsw devsw[] =
92{
93 { "hd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_HD */
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 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 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{
434struct iob*io;
435intfdesc;
436inti;
437
438if (bvr == NULL) {
439return -1;
440}
441
442fdesc = GetFreeFd();
443io = &iob[fdesc];
444bzero(io, sizeof(*io));
445
446// Mark the descriptor as taken.
447io->i_flgs = F_ALLOC;
448
449// Find the next available memory block in the download buffer.
450io->i_buf = (char *) LOAD_ADDR;
451for (i = 0; i < NFILES; i++) {
452if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) {
453continue;
454}
455io->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.
459gFSLoadAddress = io->i_buf;
460io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
461if (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 }
532return -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;
765bool 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) or the volume UUID -
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(kDefaultPartition, &val, &cnt, &bootInfo->bootConfig) && cnt >= 7 && filteredChain)
785 {
786 for ( bvr = chain; bvr; bvr = bvr->next )
787 {
788 if ( bvr->biosdev >= 0x80 && bvr->biosdev < 0x100
789 && ( bvr->flags & ( kBVFlagSystemVolume|kBVFlagForeignBoot ) ) )
790 {
791 // Trying to match hd(x,y) format.
792 sprintf(testStr, "hd(%d,%d)", bvr->biosdev - 0x80, bvr->part_no);
793 if (strcmp(testStr, val) == 0)
794 return bvr;
795
796 // Trying to match volume UUID.
797 if (bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0 && strcmp(testStr, val) == 0)
798 return bvr;
799 }
800 }
801 }
802
803/*
804 * Scannig the volume chain backwards and trying to find
805 * a HFS+ volume with valid boot record signature.
806 * If not found any active partition then we will
807 * select this volume as the boot volume.
808 */
809 for ( bvr = chain; bvr; bvr = bvr->next )
810 {
811 if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = true;
812 // zhell -- Undo a regression that was introduced from r491 to 492.
813 // if gBIOSBootVolume is set already, no change is required
814 if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
815 && gBIOSBootVolume
816 && (!filteredChain || (filteredChain && bvr->visible))
817 && bvr->biosdev == gBIOSDev )
818 bvr2 = bvr;
819 // zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
820 // from r491,
821 if ( bvr->flags & kBVFlagBootable
822 && ! gBIOSBootVolume
823 && bvr->biosdev == gBIOSDev )
824 bvr2 = bvr;
825 }
826
827
828/*
829 * Use the standrad method for selecting the boot volume.
830 */
831if (foundPrimary)
832{
833for ( bvr = chain; bvr; bvr = bvr->next )
834{
835if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
836if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
837}
838 }
839
840 bvr = bvr2 ? bvr2 :
841 bvr1 ? bvr1 : chain;
842
843 return bvr;
844}
845
846//==========================================================================
847
848#define LP '('
849#define RP ')'
850int gBIOSDev;
851
852/*!
853 This is like boot2's gBootVolume except it is for the internal use of
854 libsaio to track which volume an unqualified path should be relative to.
855 This replaces bootInfo->kernDev as the carrier of this information.
856 */
857static BVRef gRootVolume;
858
859void setRootVolume(BVRef volume)
860{
861 gRootVolume = volume;
862 // Veto non-native FS. Basically that means don't allow the root volume to
863 // be set to a volume we can't read files from.
864 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
865 gRootVolume = NULL;
866}
867
868void setBootGlobals(BVRef chain)
869{
870 // Record default boot device.
871 gBootVolume = selectBootVolume(chain);
872
873 // turbo - Save the ORIGINAL boot volume too for loading our mkext
874 if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
875
876 setRootVolume(gBootVolume);
877}
878
879/*!
880 Extracts the volume selector from the pathname, returns the selected
881 BVRef, and sets *outPath to the remainder of the path.
882 If the path did not include a volume selector then the current volume
883 is used. When called with a volume selector the current volume
884 is changed to the selected volume unless the volume selector is
885 that of a ramdisk.
886 */
887BVRef getBootVolumeRef( const char * path, const char ** outPath )
888{
889 const char * cp;
890 BVRef bvr = gRootVolume;
891 int biosdev = gBIOSDev;
892
893 // Search for left parenthesis in the path specification.
894
895 for (cp = path; *cp; cp++) {
896 if (*cp == LP || *cp == '/') break;
897 }
898
899 if (*cp != LP) // no left paren found
900 {
901 // Path is using the implicit current device so if there is
902 // no current device, then we must fail.
903 cp = path;
904 if ( gRootVolume == NULL )
905 return NULL;
906 }
907 else if ((cp - path) == 2) // found "xx("
908 {
909 const struct devsw * dp;
910 const char * xp = path;
911 int i;
912 int unit = -1;
913 int part = -1;
914
915 cp++;
916
917 // Check the 2 character device name pointed by 'xp'.
918
919 for (dp = devsw; dp->name; dp++)
920 {
921 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
922 break; // found matching entry
923 }
924 if (dp->name == NULL)
925 {
926 error("Unknown device '%c%c'\n", xp[0], xp[1]);
927 return NULL;
928 }
929
930 // Extract the optional unit number from the specification.
931 // hd(unit) or hd(unit, part).
932
933 i = 0;
934 while (*cp >= '0' && *cp <= '9')
935 {
936 i = i * 10 + *cp++ - '0';
937 unit = i;
938 }
939
940 // Unit is no longer optional and never really was.
941 // If the user failed to specify it then the unit number from the previous kernDev
942 // would have been used which makes little sense anyway.
943 // For example, if the user did fd()/foobar and the current root device was the
944 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
945 if(unit == -1)
946 return NULL;
947
948 // Extract the optional partition number from the specification.
949
950 if (*cp == ',')
951 part = atoi(++cp);
952
953 // If part is not specified part will be -1 whereas before it would have been
954 // whatever the last partition was which makes about zero sense if the device
955 // has been switched.
956
957 // Skip past the right paren.
958
959 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
960 if (*cp == RP) cp++;
961
962 biosdev = dp->biosdev + unit;
963
964 // turbo - bt(0,0) hook
965 if (biosdev == 0x101)
966 {
967 // zef - use the ramdisk if available and the alias is active.
968 if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
969 bvr = gRAMDiskVolume;
970 else
971 bvr = gBIOSBootVolume;
972 }
973 else
974 {
975 bvr = newBootVolumeRef(biosdev, part);
976 }
977
978 if(bvr == NULL)
979 return NULL;
980 }
981 else
982 {
983 // Bad device specifier, skip past the right paren.
984
985 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
986 if (*cp == RP) cp++;
987 // If gRootVolume was NULL, then bvr will be NULL as well which
988 // should be caught by the caller.
989 }
990
991 // Returns the file path following the device spec.
992 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
993
994 *outPath = cp;
995
996 return bvr;
997}
998
999//==========================================================================
1000
1001// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1002// which caches the information. So it's only allocated on the first run.
1003static BVRef newBootVolumeRef( int biosdev, int partno )
1004{
1005 BVRef bvr, bvr1, bvrChain;
1006
1007 // Fetch the volume list from the device.
1008
1009 scanBootVolumes( biosdev, NULL );
1010 bvrChain = getBVChainForBIOSDev(biosdev);
1011
1012 // Look for a perfect match based on device and partition number.
1013
1014 for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1015 {
1016 if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1017
1018 bvr1 = bvr;
1019 if ( bvr->part_no == partno ) break;
1020 }
1021
1022 return bvr ? bvr : bvr1;
1023}
1024
1025int getDeviceStringFromBVR(const BVRef bvr, char *str)
1026{
1027 const struct devsw *dp;
1028
1029 if (bvr)
1030 {
1031 *str = '\0';
1032
1033 for (dp = devsw; dp->name && bvr->biosdev >= dp->biosdev; dp++);
1034 dp--;
1035 if (dp->name) sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1036
1037 return true;
1038 }
1039
1040 return false;
1041}
1042

Archive Download this file

Revision: 187