Chameleon

Chameleon Svn Source Tree

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