Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Modules/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 gMakeDirSpec[idx] = '\0';
344 } else {
345 idx++;
346 strncpy(gMakeDirSpec, name, idx);
347 name += idx;
348 }
349 dirSpec = gMakeDirSpec;
350 }
351
352 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
353 {
354 if (strcmp(entryName, name) == 0)
355 return 0; // success
356 }
357 return -1; // file not found
358}
359
360long GetFileBlock(const char *fileSpec, unsigned long long *firstBlock)
361{
362 const char * filePath;
363 BVRef bvr;
364
365 // Resolve the boot volume from the file spec.
366
367 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) {
368 printf("Boot volume for '%s' is bogus\n", fileSpec);
369 return -1;
370 }
371
372 return bvr->fs_getfileblock(bvr, (char *)filePath, firstBlock);
373}
374
375//==========================================================================
376// GetFreeFD()
377
378static int GetFreeFd(void)
379{
380intfd;
381
382// Locate a free descriptor slot.
383for (fd = 0; fd < NFILES; fd++) {
384if (iob[fd].i_flgs == 0) {
385return fd;
386 }
387}
388stop("Out of file descriptors");
389// not reached
390return -1;
391}
392
393//==========================================================================
394// iob_from_fdesc()
395//
396// Return a pointer to an allocated 'iob' based on the file descriptor
397// provided. Returns NULL if the file descriptor given is invalid.
398
399static struct iob * iob_from_fdesc(int fdesc)
400{
401 register struct iob * io;
402
403 if (fdesc < 0 || fdesc >= NFILES ||
404 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
405 return NULL;
406 else
407 return io;
408}
409
410//==========================================================================
411// openmem()
412
413int openmem(char * buf, int len)
414{
415 int fdesc;
416 struct iob * io;
417
418 fdesc = GetFreeFd();
419 io = &iob[fdesc];
420 bzero(io, sizeof(*io));
421
422 // Mark the descriptor as taken. Set the F_MEM flag to indicate
423 // that the file buffer is provided by the caller.
424
425 io->i_flgs = F_ALLOC | F_MEM;
426 io->i_buf = buf;
427 io->i_filesize = len;
428
429 return fdesc;
430}
431
432//==========================================================================
433// open() - Open the file specified by 'path' for reading.
434
435static int open_bvr(BVRef bvr, const char *filePath, int flags)
436{
437struct iob*io;
438intfdesc;
439inti;
440
441if (bvr == NULL) {
442return -1;
443}
444
445fdesc = GetFreeFd();
446io = &iob[fdesc];
447bzero(io, sizeof(*io));
448
449// Mark the descriptor as taken.
450io->i_flgs = F_ALLOC;
451
452// Find the next available memory block in the download buffer.
453io->i_buf = (char *) LOAD_ADDR;
454for (i = 0; i < NFILES; i++) {
455if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) {
456continue;
457}
458io->i_buf = MAX(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
459}
460
461// Load entire file into memory. Unnecessary open() calls must be avoided.
462gFSLoadAddress = io->i_buf;
463io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
464if (io->i_filesize < 0) {
465close(fdesc);
466return -1;
467}
468return fdesc;
469}
470
471int open(const char *path, int flags)
472{
473const char*filepath;
474BVRefbvr;
475
476// Resolve the boot volume from the file spec.
477if ((bvr = getBootVolumeRef(path, &filepath)) != NULL) {
478return open_bvr(bvr, filepath, flags);
479}
480return -1;
481}
482
483int open_bvdev(const char *bvd, const char *path, int flags)
484{
485 const struct devsw*dp;
486const char*cp;
487BVRefbvr;
488inti;
489intlen;
490intunit;
491intpartition;
492
493if ((i = open(path, flags)) >= 0) {
494return i;
495}
496
497if (bvd == NULL || (len = strlen(bvd)) < 2) {
498return -1;
499}
500
501for (dp=devsw; dp->name; dp++) {
502if (bvd[0] == dp->name[0] && bvd[1] == dp->name[1]) {
503unit = 0;
504partition = 0;
505/* get optional unit and partition */
506if (len >= 5 && bvd[2] == '(') { /* min must be present xx(0) */
507cp = &bvd[3];
508i = 0;
509while ((cp - path) < len && isdigit(*cp)) {
510i = i * 10 + *cp++ - '0';
511unit = i;
512}
513if (*cp++ == ',') {
514i = 0;
515while ((cp - path) < len && isdigit(*cp)) {
516i = i * 10 + *cp++ - '0';
517partition = i;
518}
519}
520}
521bvr = newBootVolumeRef(dp->biosdev + unit, partition);
522return open_bvr(bvr, path, flags);
523}
524 }
525return -1;
526}
527
528//==========================================================================
529// close() - Close a file descriptor.
530
531int close(int fdesc)
532{
533 struct iob * io;
534
535 if ((io = iob_from_fdesc(fdesc)) == NULL)
536 return (-1);
537
538 io->i_flgs = 0;
539
540 return 0;
541}
542
543//==========================================================================
544// lseek() - Reposition the byte offset of the file descriptor from the
545// beginning of the file. Returns the relocated offset.
546
547int b_lseek(int fdesc, int offset, int ptr)
548{
549 struct iob * io;
550
551 if ((io = iob_from_fdesc(fdesc)) == NULL)
552 return (-1);
553
554 io->i_offset = offset;
555
556 return offset;
557}
558
559//==========================================================================
560// tell() - Returns the byte offset of the file descriptor.
561
562int tell(int fdesc)
563{
564 struct iob * io;
565
566 if ((io = iob_from_fdesc(fdesc)) == NULL)
567 return 0;
568
569 return io->i_offset;
570}
571
572//==========================================================================
573// read() - Read up to 'count' bytes of data from the file descriptor
574// into the buffer pointed to by buf.
575
576int read(int fdesc, char * buf, int count)
577{
578 struct iob * io;
579
580 if ((io = iob_from_fdesc(fdesc)) == NULL)
581 return (-1);
582
583 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
584 count = io->i_filesize - io->i_offset;
585
586 if (count <= 0)
587 return 0; // end of file
588
589 bcopy(io->i_buf + io->i_offset, buf, count);
590
591 io->i_offset += count;
592
593 return count;
594}
595
596//==========================================================================
597// write() - Write up to 'count' bytes of data to the file descriptor
598// from the buffer pointed to by buf.
599
600int write(int fdesc, const char * buf, int count)
601{
602 struct iob * io;
603
604 if ((io = iob_from_fdesc(fdesc)) == NULL)
605 return (-1);
606
607 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
608 count = io->i_filesize - io->i_offset;
609
610 if (count <= 0)
611 return 0; // end of file
612
613 bcopy(buf, io->i_buf + io->i_offset, count);
614
615 io->i_offset += count;
616
617 return count;
618}
619
620int writebyte(int fdesc, char value)
621{
622 struct iob * io;
623
624 if ((io = iob_from_fdesc(fdesc)) == NULL)
625 return (-1);
626
627 if ((io->i_offset + 1) > (unsigned int)io->i_filesize)
628 return 0; // end of file
629
630 io->i_buf[io->i_offset++] = value;
631
632 return 1;
633}
634
635int writeint(int fdesc, int value)
636{
637 struct iob * io;
638
639 if ((io = iob_from_fdesc(fdesc)) == NULL)
640 return (-1);
641
642 if ((io->i_offset + 4) > (unsigned int)io->i_filesize)
643 return 0; // end of file
644
645 bcopy(&value, io->i_buf + io->i_offset, 4);
646
647 io->i_offset += 4;
648
649 return 4;
650}
651
652//==========================================================================
653// file_size() - Returns the size of the file described by the file
654// descriptor.
655
656int file_size(int fdesc)
657{
658 struct iob * io;
659
660 if ((io = iob_from_fdesc(fdesc)) == 0)
661 return 0;
662
663 return io->i_filesize;
664}
665
666//==========================================================================
667
668struct dirstuff * vol_opendir(BVRef bvr, const char * path)
669{
670 struct dirstuff * dirp = 0;
671
672 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
673 if (dirp == NULL)
674 goto error;
675
676 dirp->dir_path = newString(path);
677 if (dirp->dir_path == NULL)
678 goto error;
679
680 dirp->dir_bvr = bvr;
681
682 return dirp;
683
684error:
685 closedir(dirp);
686 return NULL;
687}
688
689//==========================================================================
690
691struct dirstuff * opendir(const char * path)
692{
693 struct dirstuff * dirp = 0;
694 const char * dirPath;
695 BVRef bvr;
696
697 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
698 goto error;
699
700 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
701 if (dirp == NULL)
702 goto error;
703
704 dirp->dir_path = newString(dirPath);
705 if (dirp->dir_path == NULL)
706 goto error;
707
708 dirp->dir_bvr = bvr;
709
710 return dirp;
711
712error:
713 closedir(dirp);
714 return NULL;
715}
716
717//==========================================================================
718
719int closedir(struct dirstuff * dirp)
720{
721 if (dirp) {
722 if (dirp->dir_path) free(dirp->dir_path);
723 free(dirp);
724 }
725 return 0;
726}
727
728//==========================================================================
729
730int readdir(struct dirstuff * dirp, const char ** name, long * flags,
731 long * time)
732{
733 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
734 /* dirPath */ dirp->dir_path,
735 /* dirIndex */ &dirp->dir_index,
736 /* dirEntry */ (char **)name, flags, time,
737 0, 0);
738}
739
740//==========================================================================
741
742int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
743 long * time, FinderInfo *finderInfo, long *infoValid)
744{
745 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
746 /* dirPath */ dirp->dir_path,
747 /* dirIndex */ &dirp->dir_index,
748 /* dirEntry */ (char **)name,
749 flags, time,
750 finderInfo, infoValid);
751}
752
753//==========================================================================
754
755const char * systemConfigDir()
756{
757 if (gBootFileType == kNetworkDeviceType)
758return "";
759 return "/Library/Preferences/SystemConfiguration";
760}
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 bvr = nbpScanBootVolumes(biosdev, count);
774 if (bvr != NULL)
775 {
776 gBootFileType = kNetworkDeviceType;
777 }
778 }
779 else
780 {
781 gBootFileType = kBlockDeviceType;
782 }
783}
784
785//==========================================================================
786
787void scanDisks(int biosdev, int *count)
788{
789 #define MAX_HDD_COUNT 32
790 int bvCount;
791 int hd = 0;
792
793 // Testing up to MAX_HDD_COUNT hard drives.
794while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
795{
796 bvCount = 0;
797 scanBootVolumes(0x80 + hd, &bvCount);
798 hd++;
799}
800
801 // Also scanning CD/DVD drive.
802if (biosDevIsCDROM(gBIOSDev))
803{
804 bvCount = 0;
805 scanBootVolumes(gBIOSDev, &bvCount);
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->chameleonConfig));
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{
848 if (multiboot_skip_partition_set) {
849 if (bvr->part_no == multiboot_skip_partition) continue;
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.
1036if (biosdev == kPseudoBIOSDevRAMDisk)
1037{
1038if (gRAMDiskVolume)
1039 bvr1 = gRAMDiskVolume;
1040}
1041else if (biosdev == kPseudoBIOSDevBooter)
1042{
1043if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
1044bvr1 = gRAMDiskVolume;
1045else
1046bvr1 = gBIOSBootVolume;
1047}
1048else
1049{
1050// Fetch the volume list from the device.
1051
1052scanBootVolumes( biosdev, NULL );
1053bvrChain = getBVChainForBIOSDev(biosdev);
1054
1055// Look for a perfect match based on device and partition number.
1056
1057for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1058{
1059if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1060
1061bvr1 = bvr;
1062if ( bvr->part_no == partno ) break;
1063}
1064}
1065
1066return bvr ? bvr : bvr1;
1067}
1068
1069//==========================================================================
1070// getDeviceDescription() - Extracts unit number and partition number
1071// from bvr structure into "dw(u,p)" format.
1072// Returns length of the out string
1073int getDeviceDescription(BVRef bvr, char *str)
1074{
1075 if(!str)
1076 return 0;
1077
1078*str = '\0';
1079
1080if (bvr)
1081{
1082 const struct devsw *dp = devsw;
1083while(dp->name && bvr->biosdev >= dp->biosdev)
1084 dp++;
1085
1086dp--;
1087if (dp->name)
1088 return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1089}
1090
1091return 0;
1092}
1093

Archive Download this file

Revision: 1826