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//==========================================================================
406// openmem()
407
408int openmem(char * buf, int len)
409{
410 int fdesc;
411 struct iob * io;
412
413 fdesc = GetFreeFd();
414 io = &iob[fdesc];
415 bzero(io, sizeof(*io));
416
417 // Mark the descriptor as taken. Set the F_MEM flag to indicate
418 // that the file buffer is provided by the caller.
419
420 io->i_flgs = F_ALLOC | F_MEM;
421 io->i_buf = buf;
422 io->i_filesize = len;
423
424 return fdesc;
425}
426
427//==========================================================================
428// open() - Open the file specified by 'path' for reading.
429
430static int open_bvr(BVRef bvr, const char *filePath, int flags)
431{
432struct iob*io;
433intfdesc;
434inti;
435
436if (bvr == NULL) {
437return -1;
438}
439
440fdesc = GetFreeFd();
441io = &iob[fdesc];
442bzero(io, sizeof(*io));
443
444// Mark the descriptor as taken.
445io->i_flgs = F_ALLOC;
446
447// Find the next available memory block in the download buffer.
448io->i_buf = (char *) LOAD_ADDR;
449for (i = 0; i < NFILES; i++) {
450if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) {
451continue;
452}
453io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
454}
455
456// Load entire file into memory. Unnecessary open() calls must be avoided.
457gFSLoadAddress = io->i_buf;
458io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
459if (io->i_filesize < 0) {
460close(fdesc);
461return -1;
462}
463return fdesc;
464}
465
466int open(const char *path, int flags)
467{
468const char*filepath;
469BVRefbvr;
470
471// Resolve the boot volume from the file spec.
472if ((bvr = getBootVolumeRef(path, &filepath)) != NULL) {
473return open_bvr(bvr, filepath, flags);
474}
475return -1;
476}
477
478int open_bvdev(const char *bvd, const char *path, int flags)
479{
480 const struct devsw*dp;
481const char*cp;
482BVRefbvr;
483inti;
484intlen;
485intunit;
486intpartition;
487
488if ((i = open(path, flags)) >= 0) {
489return i;
490}
491
492if (bvd == NULL || (len = strlen(bvd)) < 2) {
493return -1;
494}
495
496for (dp=devsw; dp->name; dp++) {
497if (bvd[0] == dp->name[0] && bvd[1] == dp->name[1]) {
498unit = 0;
499partition = 0;
500/* get optional unit and partition */
501if (len >= 5 && bvd[2] == '(') { /* min must be present xx(0) */
502cp = &bvd[3];
503i = 0;
504while ((cp - path) < len && isdigit(*cp)) {
505i = i * 10 + *cp++ - '0';
506unit = i;
507}
508if (*cp++ == ',') {
509i = 0;
510while ((cp - path) < len && isdigit(*cp)) {
511i = i * 10 + *cp++ - '0';
512partition = i;
513}
514}
515}
516// turbo - bt(0,0) hook
517if ((dp->biosdev + unit) == 0x101) {
518// zef - use the ramdisk if available and the alias is active.
519if (gRAMDiskVolume != NULL && gRAMDiskBTAliased) {
520bvr = gRAMDiskVolume;
521} else {
522bvr = gBIOSBootVolume;
523}
524} else {
525bvr = newBootVolumeRef(dp->biosdev + unit, partition);
526}
527return open_bvr(bvr, path, flags);
528}
529 }
530return -1;
531}
532
533//==========================================================================
534// close() - Close a file descriptor.
535
536int close(int fdesc)
537{
538 struct iob * io;
539
540 if ((io = iob_from_fdesc(fdesc)) == NULL)
541 return (-1);
542
543 io->i_flgs = 0;
544
545 return 0;
546}
547
548//==========================================================================
549// lseek() - Reposition the byte offset of the file descriptor from the
550// beginning of the file. Returns the relocated offset.
551
552int b_lseek(int fdesc, int offset, int ptr)
553{
554 struct iob * io;
555
556 if ((io = iob_from_fdesc(fdesc)) == NULL)
557 return (-1);
558
559 io->i_offset = offset;
560
561 return offset;
562}
563
564//==========================================================================
565// tell() - Returns the byte offset of the file descriptor.
566
567int tell(int fdesc)
568{
569 struct iob * io;
570
571 if ((io = iob_from_fdesc(fdesc)) == NULL)
572 return 0;
573
574 return io->i_offset;
575}
576
577//==========================================================================
578// read() - Read up to 'count' bytes of data from the file descriptor
579// into the buffer pointed to by buf.
580
581int read(int fdesc, char * buf, int count)
582{
583 struct iob * io;
584
585 if ((io = iob_from_fdesc(fdesc)) == NULL)
586 return (-1);
587
588 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
589 count = io->i_filesize - io->i_offset;
590
591 if (count <= 0)
592 return 0; // end of file
593
594 bcopy(io->i_buf + io->i_offset, buf, count);
595
596 io->i_offset += count;
597
598 return count;
599}
600
601//==========================================================================
602// write() - Write up to 'count' bytes of data to the file descriptor
603// from the buffer pointed to by buf.
604
605int write(int fdesc, const char * buf, int count)
606{
607 struct iob * io;
608
609 if ((io = iob_from_fdesc(fdesc)) == NULL)
610 return (-1);
611
612 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
613 count = io->i_filesize - io->i_offset;
614
615 if (count <= 0)
616 return 0; // end of file
617
618 bcopy(buf, io->i_buf + io->i_offset, count);
619
620 io->i_offset += count;
621
622 return count;
623}
624
625int writebyte(int fdesc, char value)
626{
627 struct iob * io;
628
629 if ((io = iob_from_fdesc(fdesc)) == NULL)
630 return (-1);
631
632 if ((io->i_offset + 1) > (unsigned int)io->i_filesize)
633 return 0; // end of file
634
635 io->i_buf[io->i_offset++] = value;
636
637 return 1;
638}
639
640int writeint(int fdesc, int value)
641{
642 struct iob * io;
643
644 if ((io = iob_from_fdesc(fdesc)) == NULL)
645 return (-1);
646
647 if ((io->i_offset + 4) > (unsigned int)io->i_filesize)
648 return 0; // end of file
649
650 bcopy(&value, io->i_buf + io->i_offset, 4);
651
652 io->i_offset += 4;
653
654 return 4;
655}
656
657//==========================================================================
658// file_size() - Returns the size of the file described by the file
659// descriptor.
660
661int file_size(int fdesc)
662{
663 struct iob * io;
664
665 if ((io = iob_from_fdesc(fdesc)) == 0)
666 return 0;
667
668 return io->i_filesize;
669}
670
671//==========================================================================
672
673struct dirstuff * vol_opendir(BVRef bvr, const char * path)
674{
675 struct dirstuff * dirp = 0;
676
677 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
678 if (dirp == NULL)
679 goto error;
680
681 dirp->dir_path = newString(path);
682 if (dirp->dir_path == NULL)
683 goto error;
684
685 dirp->dir_bvr = bvr;
686
687 return dirp;
688
689error:
690 closedir(dirp);
691 return NULL;
692}
693
694//==========================================================================
695
696struct dirstuff * opendir(const char * path)
697{
698 struct dirstuff * dirp = 0;
699 const char * dirPath;
700 BVRef bvr;
701
702 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
703 goto error;
704
705 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
706 if (dirp == NULL)
707 goto error;
708
709 dirp->dir_path = newString(dirPath);
710 if (dirp->dir_path == NULL)
711 goto error;
712
713 dirp->dir_bvr = bvr;
714
715 return dirp;
716
717error:
718 closedir(dirp);
719 return NULL;
720}
721
722//==========================================================================
723
724int closedir(struct dirstuff * dirp)
725{
726 if (dirp) {
727 if (dirp->dir_path) free(dirp->dir_path);
728 free(dirp);
729 }
730 return 0;
731}
732
733//==========================================================================
734
735int readdir(struct dirstuff * dirp, const char ** name, long * flags,
736 long * time)
737{
738 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
739 /* dirPath */ dirp->dir_path,
740 /* dirIndex */ &dirp->dir_index,
741 /* dirEntry */ (char **)name, flags, time,
742 0, 0);
743}
744
745//==========================================================================
746
747int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
748 long * time, FinderInfo *finderInfo, long *infoValid)
749{
750 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
751 /* dirPath */ dirp->dir_path,
752 /* dirIndex */ &dirp->dir_index,
753 /* dirEntry */ (char **)name,
754 flags, time,
755 finderInfo, infoValid);
756}
757
758//==========================================================================
759
760const char * systemConfigDir()
761{
762 if (gBootFileType == kNetworkDeviceType)
763return "";
764 return "/Library/Preferences/SystemConfiguration";
765}
766
767//==========================================================================
768
769int gBootFileType;
770
771void scanBootVolumes( int biosdev, int * count )
772{
773 BVRef bvr = 0;
774
775 bvr = diskScanBootVolumes(biosdev, count);
776 if (bvr == NULL)
777 {
778 bvr = nbpScanBootVolumes(biosdev, count);
779 if (bvr != NULL)
780 {
781 gBootFileType = kNetworkDeviceType;
782 }
783 }
784 else
785 {
786 gBootFileType = kBlockDeviceType;
787 }
788}
789
790//==========================================================================
791
792void scanDisks(int biosdev, int *count)
793{
794 #define MAX_HDD_COUNT 32
795 int bvCount;
796 int hd = 0;
797
798 // Testing up to MAX_HDD_COUNT hard drives.
799while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
800{
801 bvCount = 0;
802 scanBootVolumes(0x80 + hd, &bvCount);
803 hd++;
804}
805
806 // Also scanning CD/DVD drive.
807if (biosDevIsCDROM(gBIOSDev))
808{
809 bvCount = 0;
810 scanBootVolumes(gBIOSDev, &bvCount);
811}
812}
813
814//==========================================================================
815
816BVRef selectBootVolume( BVRef chain )
817{
818bool filteredChain = false;
819bool foundPrimary = false;
820BVRef bvr, bvr1 = 0, bvr2 = 0;
821
822if (chain->filtered) filteredChain = true;
823
824if (multiboot_partition_set)
825for ( bvr = chain; bvr; bvr = bvr->next )
826if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
827return bvr;
828
829/*
830 * Checking "Default Partition" key in system configuration - use format: hd(x,y) or the volume UUID -
831 * to override the default selection.
832 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
833 */
834const char * val;
835char testStr[64];
836int cnt;
837
838if (getValueForKey(kDefaultPartition, &val, &cnt, &bootInfo->bootConfig) && cnt >= 7 && filteredChain)
839{
840for ( bvr = chain; bvr; bvr = bvr->next )
841{
842if ( bvr->biosdev >= 0x80 && bvr->biosdev < 0x100
843&& ( bvr->flags & ( kBVFlagSystemVolume|kBVFlagForeignBoot ) ) )
844{
845// Trying to match hd(x,y) format.
846sprintf(testStr, "hd(%d,%d)", bvr->biosdev - 0x80, bvr->part_no);
847if (strcmp(testStr, val) == 0)
848return bvr;
849
850// Trying to match volume UUID.
851if (bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0 && strcmp(testStr, val) == 0)
852return bvr;
853}
854}
855}
856
857/*
858 * Scannig the volume chain backwards and trying to find
859 * a HFS+ volume with valid boot record signature.
860 * If not found any active partition then we will
861 * select this volume as the boot volume.
862 */
863for ( bvr = chain; bvr; bvr = bvr->next )
864{
865if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = true;
866// zhell -- Undo a regression that was introduced from r491 to 492.
867// if gBIOSBootVolume is set already, no change is required
868if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
869&& gBIOSBootVolume
870&& (!filteredChain || (filteredChain && bvr->visible))
871&& bvr->biosdev == gBIOSDev )
872bvr2 = bvr;
873// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
874// from r491,
875if ( bvr->flags & kBVFlagBootable
876&& ! gBIOSBootVolume
877&& bvr->biosdev == gBIOSDev )
878bvr2 = bvr;
879}
880
881
882/*
883 * Use the standrad method for selecting the boot volume.
884 */
885if (foundPrimary)
886{
887for ( bvr = chain; bvr; bvr = bvr->next )
888{
889if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
890if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
891}
892}
893
894bvr = bvr2 ? bvr2 :
895bvr1 ? bvr1 : chain;
896
897return bvr;
898}
899
900//==========================================================================
901
902#define LP '('
903#define RP ')'
904int gBIOSDev;
905
906/*!
907 This is like boot2's gBootVolume except it is for the internal use of
908 libsaio to track which volume an unqualified path should be relative to.
909 This replaces bootInfo->kernDev as the carrier of this information.
910 */
911static BVRef gRootVolume;
912
913void setRootVolume(BVRef volume)
914{
915 gRootVolume = volume;
916 // Veto non-native FS. Basically that means don't allow the root volume to
917 // be set to a volume we can't read files from.
918 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
919 gRootVolume = NULL;
920}
921
922void setBootGlobals(BVRef chain)
923{
924 // Record default boot device.
925 gBootVolume = selectBootVolume(chain);
926
927 // turbo - Save the ORIGINAL boot volume too for loading our mkext
928 if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
929
930 setRootVolume(gBootVolume);
931}
932
933/*!
934 Extracts the volume selector from the pathname, returns the selected
935 BVRef, and sets *outPath to the remainder of the path.
936 If the path did not include a volume selector then the current volume
937 is used. When called with a volume selector the current volume
938 is changed to the selected volume unless the volume selector is
939 that of a ramdisk.
940 */
941BVRef getBootVolumeRef( const char * path, const char ** outPath )
942{
943 const char * cp;
944 BVRef bvr = gRootVolume;
945 int biosdev = gBIOSDev;
946
947 // Search for left parenthesis in the path specification.
948
949 for (cp = path; *cp; cp++) {
950 if (*cp == LP || *cp == '/') break;
951 }
952
953 if (*cp != LP) // no left paren found
954 {
955 // Path is using the implicit current device so if there is
956 // no current device, then we must fail.
957 cp = path;
958 if ( gRootVolume == NULL )
959 return NULL;
960 }
961 else if ((cp - path) == 2) // found "xx("
962 {
963 const struct devsw * dp;
964 const char * xp = path;
965 int i;
966 int unit = -1;
967 int part = -1;
968
969 cp++;
970
971 // Check the 2 character device name pointed by 'xp'.
972
973 for (dp = devsw; dp->name; dp++)
974 {
975 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
976 break; // found matching entry
977 }
978 if (dp->name == NULL)
979 {
980 error("Unknown device '%c%c'\n", xp[0], xp[1]);
981 return NULL;
982 }
983
984 // Extract the optional unit number from the specification.
985 // hd(unit) or hd(unit, part).
986
987 i = 0;
988 while (*cp >= '0' && *cp <= '9')
989 {
990 i = i * 10 + *cp++ - '0';
991 unit = i;
992 }
993
994 // Unit is no longer optional and never really was.
995 // If the user failed to specify it then the unit number from the previous kernDev
996 // would have been used which makes little sense anyway.
997 // For example, if the user did fd()/foobar and the current root device was the
998 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
999 if(unit == -1)
1000 return NULL;
1001
1002 // Extract the optional partition number from the specification.
1003
1004 if (*cp == ',')
1005 part = atoi(++cp);
1006
1007 // If part is not specified part will be -1 whereas before it would have been
1008 // whatever the last partition was which makes about zero sense if the device
1009 // has been switched.
1010
1011 // Skip past the right paren.
1012
1013 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
1014 if (*cp == RP) cp++;
1015
1016 biosdev = dp->biosdev + unit;
1017
1018 // turbo - bt(0,0) hook
1019 if (biosdev == 0x101)
1020 {
1021 // zef - use the ramdisk if available and the alias is active.
1022 if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
1023 bvr = gRAMDiskVolume;
1024 else
1025 bvr = gBIOSBootVolume;
1026 }
1027 else
1028 {
1029 bvr = newBootVolumeRef(biosdev, part);
1030 }
1031
1032 if(bvr == NULL)
1033 return NULL;
1034 }
1035 else
1036 {
1037 // Bad device specifier, skip past the right paren.
1038
1039 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
1040 if (*cp == RP) cp++;
1041 // If gRootVolume was NULL, then bvr will be NULL as well which
1042 // should be caught by the caller.
1043 }
1044
1045 // Returns the file path following the device spec.
1046 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1047
1048 *outPath = cp;
1049
1050 return bvr;
1051}
1052
1053//==========================================================================
1054
1055// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1056// which caches the information. So it's only allocated on the first run.
1057static BVRef newBootVolumeRef( int biosdev, int partno )
1058{
1059 BVRef bvr, bvr1, bvrChain;
1060
1061 // Fetch the volume list from the device.
1062
1063 scanBootVolumes( biosdev, NULL );
1064 bvrChain = getBVChainForBIOSDev(biosdev);
1065
1066 // Look for a perfect match based on device and partition number.
1067
1068 for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1069 {
1070 if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1071
1072 bvr1 = bvr;
1073 if ( bvr->part_no == partno ) break;
1074 }
1075
1076 return bvr ? bvr : bvr1;
1077}
1078
1079int getDeviceStringFromBVR(const BVRef bvr, char *str)
1080{
1081const struct devsw *dp;
1082
1083if (bvr)
1084{
1085*str = '\0';
1086
1087 for (dp = devsw; dp->name && bvr->biosdev >= dp->biosdev; dp++);
1088 dp--;
1089 if (dp->name) sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1090
1091 return true;
1092}
1093
1094return false;
1095}
1096

Archive Download this file

Revision: 192