Chameleon

Chameleon Svn Source Tree

Root/branches/i386/libsaio/sys.c

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

Archive Download this file

Revision: 162