Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/trunkGraphicsEnablerModules/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
62#include "libsaio.h"
63#include "boot.h"
64#include "bootstruct.h"
65#include "disk.h"
66#include "ramdisk.h"
67#include "xml.h"
68
69#include <libkern/crypto/md5.h>
70//#include <uuid/uuid.h>
71
72#if 0 /* No OS X release has ever included this. */
73#include <Kernel/uuid/namespace.h>
74#else
75// from our uuid/namespace.h (UFS and HFS uuids can live in the same space?)
76static unsigned char kFSUUIDNamespaceSHA1[] = {0xB3,0xE2,0x0F,0x39,0xF2,0x92,0x11,0xD6,0x97,0xA4,0x00,0x30,0x65,0x43,0xEC,0xAC};
77#endif
78
79extern int multiboot_partition;
80extern int multiboot_partition_set;
81extern int multiboot_skip_partition;
82extern int multiboot_skip_partition_set;
83
84struct devsw {
85 const char * name;
86 // size increased from char to short to handle non-BIOS internal devices
87 unsigned short biosdev;
88 int type;
89};
90
91// Device entries must be ordered by bios device numbers.
92static struct devsw devsw[] =
93{
94 { "hd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_HD */
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// Pseudo BIOS devices
102enum {
103kPseudoBIOSDevRAMDisk = 0x100,
104kPseudoBIOSDevBooter = 0x101
105};
106
107/*
108 * Max number of file descriptors.
109 */
110#define NFILES 6
111
112static struct iob iob[NFILES];
113
114void * gFSLoadAddress = 0;
115
116// Turbo - save what we think is our original BIOS boot volume if we have one 0xab
117BVRef gBIOSBootVolume = NULL;
118BVRef gBootVolume;
119
120//static BVRef getBootVolumeRef( const char * path, const char ** outPath );
121static BVRef newBootVolumeRef( int biosdev, int partno );
122
123//==========================================================================
124// LoadVolumeFile - LOW-LEVEL FILESYSTEM FUNCTION.
125// Load the specified file from the specified volume
126// to the load buffer at LOAD_ADDR.
127// If the file is fat, load only the i386 portion.
128
129long LoadVolumeFile(BVRef bvr, const char *filePath)
130{
131 long fileSize;
132
133 // Read file into load buffer. The data in the load buffer will be
134 // overwritten by the next LoadFile() call.
135
136 gFSLoadAddress = (void *) LOAD_ADDR;
137
138 fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
139
140 // Return the size of the file, or -1 if load failed.
141
142 return fileSize;
143}
144
145//==========================================================================
146// LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
147// Load the specified file to the load buffer at LOAD_ADDR.
148// If the file is fat, load only the i386 portion.
149
150long LoadFile(const char * fileSpec)
151{
152 const char * filePath;
153 BVRef bvr;
154
155 // Resolve the boot volume from the file spec.
156
157 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
158 return -1;
159
160 return LoadVolumeFile(bvr, filePath);
161}
162
163long ReadFileAtOffset(const char * fileSpec, void *buffer, uint64_t offset, uint64_t length)
164{
165 const char *filePath;
166 BVRef bvr;
167
168 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
169 return -1;
170
171 if (bvr->fs_readfile == NULL)
172 return -1;
173
174 return bvr->fs_readfile(bvr, (char *)filePath, buffer, offset, length);
175}
176
177long LoadThinFatFile(const char *fileSpec, void **binary)
178{
179 const char *filePath;
180 FSReadFile readFile;
181 BVRef bvr;
182 unsigned long length, length2;
183
184 // Resolve the boot volume from the file spec.
185
186 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
187 return -1;
188
189 *binary = (void *)kLoadAddr;
190
191 // Read file into load buffer. The data in the load buffer will be
192 // overwritten by the next LoadFile() call.
193
194 gFSLoadAddress = (void *) LOAD_ADDR;
195
196 readFile = bvr->fs_readfile;
197
198 if (readFile != NULL) {
199 // Read the first 4096 bytes (fat header)
200 length = readFile(bvr, (char *)filePath, *binary, 0, 0x1000);
201 if (length > 0) {
202 if (ThinFatFile(binary, &length) == 0) {
203if (length == 0)
204return 0;
205 // We found a fat binary; read only the thin part
206 length = readFile(bvr, (char *)filePath,
207 (void *)kLoadAddr, (unsigned long)(*binary) - kLoadAddr, length);
208 *binary = (void *)kLoadAddr;
209 } else {
210 // Not a fat binary; read the rest of the file
211 length2 = readFile(bvr, (char *)filePath, (void *)(kLoadAddr + length), length, 0);
212 if (length2 == -1) return -1;
213 length += length2;
214 }
215 }
216 } else {
217 length = bvr->fs_loadfile(bvr, (char *)filePath);
218 if (length > 0) {
219 ThinFatFile(binary, &length);
220 }
221 }
222
223 return length;
224}
225
226#if UNUSED
227long GetFSUUID(char *spec, char *uuidStr)
228{
229 BVRef bvr;
230 long rval = -1;
231 const char *devSpec;
232
233 if ((bvr = getBootVolumeRef(spec, &devSpec)) == NULL)
234 return -1;
235
236 if(bvr->fs_getuuid)
237 rval = bvr->fs_getuuid(bvr, uuidStr);
238
239 return rval;
240}
241#endif
242
243// filesystem-specific getUUID functions call this shared string generator
244long CreateUUIDString(uint8_t uubytes[], int nbytes, char *uuidStr)
245{
246 unsigned fmtbase, fmtidx, i;
247 uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 };
248 char *p = uuidStr;
249 MD5_CTX md5c;
250 uint8_t mdresult[16];
251
252 bzero(mdresult, sizeof(mdresult));
253
254 // just like AppleFileSystemDriver
255 MD5Init(&md5c);
256 MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1));
257 MD5Update(&md5c, uubytes, nbytes);
258 MD5Final(mdresult, &md5c);
259
260 // this UUID has been made version 3 style (i.e. via namespace)
261 // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte)
262 mdresult[6] = 0x30 | ( mdresult[6] & 0x0F );
263 mdresult[8] = 0x80 | ( mdresult[8] & 0x3F );
264
265
266 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
267 i = 0; fmtbase = 0;
268 for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) {
269 for(i=0; i < uuidfmt[fmtidx]; i++) {
270 uint8_t byte = mdresult[fmtbase+i];
271 char nib;
272
273 nib = byte >> 4;
274 *p = nib + '0'; // 0x4 -> '4'
275 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
276 p++;
277
278 nib = byte & 0xf;
279 *p = nib + '0'; // 0x4 -> '4'
280 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
281 p++;
282
283 }
284 fmtbase += i;
285 if(fmtidx < sizeof(uuidfmt)-1)
286 *(p++) = '-';
287 else
288 *p = '\0';
289 }
290
291 return 0;
292}
293
294
295//==========================================================================
296// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
297// Fetch the next directory entry for the given directory.
298
299long GetDirEntry(const char * dirSpec, long long * dirIndex, const char ** name,
300 long * flags, long * time)
301{
302 const char * dirPath;
303 BVRef bvr;
304
305 // Resolve the boot volume from the dir spec.
306
307 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
308 return -1;
309
310 // Return 0 on success, or -1 if there are no additional entries.
311
312 return bvr->fs_getdirentry( bvr,
313 /* dirPath */ (char *)dirPath,
314 /* dirIndex */ dirIndex,
315 /* dirEntry */ (char **)name, flags, time, 0, 0 );
316}
317
318//==========================================================================
319// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
320// Get attributes for the specified file.
321
322static char* gMakeDirSpec;
323
324long GetFileInfo(const char * dirSpec, const char * name,
325 long * flags, long * time)
326{
327 long long index = 0;
328 const char * entryName;
329
330 if (gMakeDirSpec == 0)
331 gMakeDirSpec = (char *)malloc(1024);
332
333 if (!dirSpec) {
334 long idx, len;
335
336 len = strlen(name);
337
338 for (idx = len; idx && (name[idx] != '/' && name[idx] != '\\'); idx--) {}
339 if (idx == 0) {
340 if(name[idx] == '/' || name[idx] == '\\') ++name; // todo: ensure other functions handel \ properly
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
810BVRef selectBootVolume( BVRef chain )
811{
812bool filteredChain = false;
813bool foundPrimary = false;
814BVRef bvr, bvr1 = 0, bvr2 = 0;
815
816if (chain->filtered) filteredChain = true;
817
818if (multiboot_partition_set)
819for ( bvr = chain; bvr; bvr = bvr->next )
820if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
821return bvr;
822
823/*
824 * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
825 * to override the default selection.
826 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
827 */
828char *val = XMLDecode(getStringForKey(kDefaultPartition, &bootInfo->chameleonConfig));
829 if (val) {
830 for ( bvr = chain; bvr; bvr = bvr->next ) {
831 if (matchVolumeToString(bvr, val, false)) {
832 free(val);
833 return bvr;
834 }
835 }
836 free(val);
837 }
838
839/*
840 * Scannig the volume chain backwards and trying to find
841 * a HFS+ volume with valid boot record signature.
842 * If not found any active partition then we will
843 * select this volume as the boot volume.
844 */
845for ( bvr = chain; bvr; bvr = bvr->next )
846{
847 if (multiboot_skip_partition_set) {
848 if (bvr->part_no == multiboot_skip_partition) continue;
849 }
850if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = true;
851// zhell -- Undo a regression that was introduced from r491 to 492.
852// if gBIOSBootVolume is set already, no change is required
853if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
854&& gBIOSBootVolume
855&& (!filteredChain || (filteredChain && bvr->visible))
856&& bvr->biosdev == gBIOSDev )
857bvr2 = bvr;
858// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
859// from r491,
860if ( bvr->flags & kBVFlagBootable
861&& ! gBIOSBootVolume
862&& bvr->biosdev == gBIOSDev )
863bvr2 = bvr;
864}
865
866
867/*
868 * Use the standrad method for selecting the boot volume.
869 */
870if (foundPrimary)
871{
872for ( bvr = chain; bvr; bvr = bvr->next )
873{
874if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
875if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
876}
877}
878
879bvr = bvr2 ? bvr2 :
880bvr1 ? bvr1 : chain;
881
882return bvr;
883}
884
885//==========================================================================
886
887#define LP '('
888#define RP ')'
889int gBIOSDev;
890
891/*!
892 This is like boot2's gBootVolume except it is for the internal use of
893 libsaio to track which volume an unqualified path should be relative to.
894 This replaces bootInfo->kernDev as the carrier of this information.
895 */
896static BVRef gRootVolume;
897
898void setRootVolume(BVRef volume)
899{
900 gRootVolume = volume;
901 // Veto non-native FS. Basically that means don't allow the root volume to
902 // be set to a volume we can't read files from.
903 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
904 gRootVolume = NULL;
905}
906
907void setBootGlobals(BVRef chain)
908{
909 // Record default boot device.
910 gBootVolume = selectBootVolume(chain);
911
912 // turbo - Save the ORIGINAL boot volume too for loading our mkext
913 if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
914
915 setRootVolume(gBootVolume);
916}
917
918/*!
919 Extracts the volume selector from the pathname, returns the selected
920 BVRef, and sets *outPath to the remainder of the path.
921 If the path did not include a volume selector then the current volume
922 is used. When called with a volume selector the current volume
923 is changed to the selected volume unless the volume selector is
924 that of a ramdisk.
925 */
926BVRef getBootVolumeRef( const char * path, const char ** outPath )
927{
928 const char * cp;
929 BVRef bvr = gRootVolume;
930 int biosdev = gBIOSDev;
931
932 // Search for left parenthesis in the path specification.
933
934 for (cp = path; *cp; cp++) {
935 if (*cp == LP || *cp == '/') break;
936 }
937
938 if (*cp != LP) // no left paren found
939 {
940 // Path is using the implicit current device so if there is
941 // no current device, then we must fail.
942 cp = path;
943 if ( gRootVolume == NULL )
944 return NULL;
945 }
946 else if ((cp - path) == 2) // found "xx("
947 {
948 const struct devsw * dp;
949 const char * xp = path;
950 int i;
951 int unit = -1;
952 int part = -1;
953
954 cp++;
955
956 // Check the 2 character device name pointed by 'xp'.
957
958 for (dp = devsw; dp->name; dp++)
959 {
960 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
961 break; // found matching entry
962 }
963 if (dp->name == NULL)
964 {
965 error("Unknown device '%c%c'\n", xp[0], xp[1]);
966 return NULL;
967 }
968
969 // Extract the optional unit number from the specification.
970 // hd(unit) or hd(unit, part).
971
972 i = 0;
973 while (*cp >= '0' && *cp <= '9')
974 {
975 i = i * 10 + *cp++ - '0';
976 unit = i;
977 }
978
979 // Unit is no longer optional and never really was.
980 // If the user failed to specify it then the unit number from the previous kernDev
981 // would have been used which makes little sense anyway.
982 // For example, if the user did fd()/foobar and the current root device was the
983 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
984 if(unit == -1)
985 return NULL;
986
987 // Extract the optional partition number from the specification.
988
989 if (*cp == ',')
990 part = atoi(++cp);
991
992 // If part is not specified part will be -1 whereas before it would have been
993 // whatever the last partition was which makes about zero sense if the device
994 // has been switched.
995
996 // Skip past the right paren.
997
998 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
999 if (*cp == RP) cp++;
1000
1001 biosdev = dp->biosdev + unit;
1002 bvr = newBootVolumeRef(biosdev, part);
1003
1004 if(bvr == NULL)
1005 return NULL;
1006 }
1007 else
1008 {
1009 // Bad device specifier, skip past the right paren.
1010
1011 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
1012 if (*cp == RP) cp++;
1013 // If gRootVolume was NULL, then bvr will be NULL as well which
1014 // should be caught by the caller.
1015 }
1016
1017 // Returns the file path following the device spec.
1018 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1019
1020 *outPath = cp;
1021
1022 return bvr;
1023}
1024
1025//==========================================================================
1026// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1027// which caches the information. So it's only allocated on the first run.
1028static BVRef newBootVolumeRef( int biosdev, int partno )
1029{
1030BVRef bvr, bvr1, bvrChain;
1031
1032bvr = bvr1 = NULL;
1033
1034 // Try resolving "rd" and "bt" devices first.
1035if (biosdev == kPseudoBIOSDevRAMDisk)
1036{
1037if (gRAMDiskVolume)
1038 bvr1 = gRAMDiskVolume;
1039}
1040else if (biosdev == kPseudoBIOSDevBooter)
1041{
1042if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
1043bvr1 = gRAMDiskVolume;
1044else
1045bvr1 = gBIOSBootVolume;
1046}
1047else
1048{
1049// Fetch the volume list from the device.
1050
1051scanBootVolumes( biosdev, NULL );
1052bvrChain = getBVChainForBIOSDev(biosdev);
1053
1054// Look for a perfect match based on device and partition number.
1055
1056for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1057{
1058if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1059
1060bvr1 = bvr;
1061if ( bvr->part_no == partno ) break;
1062}
1063}
1064
1065return bvr ? bvr : bvr1;
1066}
1067
1068//==========================================================================
1069// getDeviceDescription() - Extracts unit number and partition number
1070// from bvr structure into "dw(u,p)" format.
1071// Returns length of the out string
1072int getDeviceDescription(BVRef bvr, char *str)
1073{
1074 if(!str)
1075 return 0;
1076
1077*str = '\0';
1078
1079if (bvr)
1080{
1081 const struct devsw *dp = devsw;
1082while(dp->name && bvr->biosdev >= dp->biosdev)
1083 dp++;
1084
1085dp--;
1086if (dp->name)
1087 return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1088}
1089
1090return 0;
1091}
1092

Archive Download this file

Revision: 1146