Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 789