Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Trunk/i386/libsaio/sys.c

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Mach Operating System
26 * Copyright (c) 1990 Carnegie-Mellon University
27 * Copyright (c) 1989 Carnegie-Mellon University
28 * Copyright (c) 1988 Carnegie-Mellon University
29 * Copyright (c) 1987 Carnegie-Mellon University
30 * All rights reserved. The CMU software License Agreement specifies
31 * the terms and conditions for use and redistribution.
32 *
33 */
34/*
35 * HISTORY
36 * Revision 2.3 88/08/08 13:47:07 rvb
37 * Allocate buffers dynamically vs statically.
38 * Now b[i] and i_fs and i_buf, are allocated dynamically.
39 * boot_calloc(size) allocates and zeros a buffer rounded to a NPG
40 * boundary.
41 * Generalize boot spec to allow, xx()/mach, xx(n,[a..h])/mach,
42 * xx([a..h])/mach, ...
43 * Also default "xx" if unspecified and alloc just "/mach",
44 * where everything is defaulted
45 * Add routine, ptol(), to parse partition letters.
46 *
47 */
48
49/*
50 * Copyright (c) 1982, 1986 Regents of the University of California.
51 * All rights reserved. The Berkeley software License Agreement
52 * specifies the terms and conditions for redistribution.
53 *
54 *@(#)sys.c7.1 (Berkeley) 6/5/86
55 */
56
57/* Copyright 2007 VMware Inc.
58 "Preboot" ramdisk support added by David Elliott
59 */
60
61
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 gMakeDirSpec[idx] = '\0'; // ISSUE: http://forge.voodooprojects.org/p/chameleon/issues/270/
348 name += idx;
349 }
350 dirSpec = gMakeDirSpec;
351 }
352
353 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
354 {
355 if (strcmp(entryName, name) == 0)
356 return 0; // success
357 }
358 return -1; // file not found
359}
360
361long GetFileBlock(const char *fileSpec, unsigned long long *firstBlock)
362{
363 const char * filePath;
364 BVRef bvr;
365
366 // Resolve the boot volume from the file spec.
367
368 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) {
369 printf("Boot volume for '%s' is bogus\n", fileSpec);
370 return -1;
371 }
372
373 return bvr->fs_getfileblock(bvr, (char *)filePath, firstBlock);
374}
375
376//==========================================================================
377// GetFreeFD()
378
379static int GetFreeFd(void)
380{
381intfd;
382
383// Locate a free descriptor slot.
384for (fd = 0; fd < NFILES; fd++) {
385if (iob[fd].i_flgs == 0) {
386return fd;
387 }
388}
389stop("Out of file descriptors");
390// not reached
391return -1;
392}
393
394//==========================================================================
395// iob_from_fdesc()
396//
397// Return a pointer to an allocated 'iob' based on the file descriptor
398// provided. Returns NULL if the file descriptor given is invalid.
399
400static struct iob * iob_from_fdesc(int fdesc)
401{
402 register struct iob * io;
403
404 if (fdesc < 0 || fdesc >= NFILES ||
405 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
406 return NULL;
407 else
408 return io;
409}
410
411//==========================================================================
412// openmem()
413
414int openmem(char * buf, int len)
415{
416 int fdesc;
417 struct iob * io;
418
419 fdesc = GetFreeFd();
420 io = &iob[fdesc];
421 bzero(io, sizeof(*io));
422
423 // Mark the descriptor as taken. Set the F_MEM flag to indicate
424 // that the file buffer is provided by the caller.
425
426 io->i_flgs = F_ALLOC | F_MEM;
427 io->i_buf = buf;
428 io->i_filesize = len;
429
430 return fdesc;
431}
432
433//==========================================================================
434// open() - Open the file specified by 'path' for reading.
435
436static int open_bvr(BVRef bvr, const char *filePath, int flags)
437{
438struct iob*io;
439intfdesc;
440inti;
441
442if (bvr == NULL) {
443return -1;
444}
445
446fdesc = GetFreeFd();
447io = &iob[fdesc];
448bzero(io, sizeof(*io));
449
450// Mark the descriptor as taken.
451io->i_flgs = F_ALLOC;
452
453// Find the next available memory block in the download buffer.
454io->i_buf = (char *) LOAD_ADDR;
455for (i = 0; i < NFILES; i++) {
456if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) {
457continue;
458}
459io->i_buf = MAX(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
460}
461
462// Load entire file into memory. Unnecessary open() calls must be avoided.
463gFSLoadAddress = io->i_buf;
464io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
465if (io->i_filesize < 0) {
466close(fdesc);
467return -1;
468}
469return fdesc;
470}
471
472int open(const char *path, int flags)
473{
474const char*filepath;
475BVRefbvr;
476
477// Resolve the boot volume from the file spec.
478if ((bvr = getBootVolumeRef(path, &filepath)) != NULL) {
479return open_bvr(bvr, filepath, flags);
480}
481return -1;
482}
483
484int open_bvdev(const char *bvd, const char *path, int flags)
485{
486 const struct devsw*dp;
487const char*cp;
488BVRefbvr;
489inti;
490intlen;
491intunit;
492intpartition;
493
494if ((i = open(path, flags)) >= 0) {
495return i;
496}
497
498if (bvd == NULL || (len = strlen(bvd)) < 2) {
499return -1;
500}
501
502for (dp=devsw; dp->name; dp++) {
503if (bvd[0] == dp->name[0] && bvd[1] == dp->name[1]) {
504unit = 0;
505partition = 0;
506/* get optional unit and partition */
507if (len >= 5 && bvd[2] == '(') { /* min must be present xx(0) */
508cp = &bvd[3];
509i = 0;
510while ((cp - path) < len && isdigit(*cp)) {
511i = i * 10 + *cp++ - '0';
512unit = i;
513}
514if (*cp++ == ',') {
515i = 0;
516while ((cp - path) < len && isdigit(*cp)) {
517i = i * 10 + *cp++ - '0';
518partition = i;
519}
520}
521}
522bvr = newBootVolumeRef(dp->biosdev + unit, partition);
523return open_bvr(bvr, path, flags);
524}
525 }
526return -1;
527}
528
529//==========================================================================
530// close() - Close a file descriptor.
531
532int close(int fdesc)
533{
534 struct iob * io;
535
536 if ((io = iob_from_fdesc(fdesc)) == NULL)
537 return (-1);
538
539 io->i_flgs = 0;
540
541 return 0;
542}
543
544//==========================================================================
545// lseek() - Reposition the byte offset of the file descriptor from the
546// beginning of the file. Returns the relocated offset.
547
548int b_lseek(int fdesc, int offset, int ptr)
549{
550 struct iob * io;
551
552 if ((io = iob_from_fdesc(fdesc)) == NULL)
553 return (-1);
554
555 io->i_offset = offset;
556
557 return offset;
558}
559
560//==========================================================================
561// tell() - Returns the byte offset of the file descriptor.
562
563int tell(int fdesc)
564{
565 struct iob * io;
566
567 if ((io = iob_from_fdesc(fdesc)) == NULL)
568 return 0;
569
570 return io->i_offset;
571}
572
573//==========================================================================
574// read() - Read up to 'count' bytes of data from the file descriptor
575// into the buffer pointed to by buf.
576
577int read(int fdesc, char * buf, int count)
578{
579 struct iob * io;
580
581 if ((io = iob_from_fdesc(fdesc)) == NULL)
582 return (-1);
583
584 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
585 count = io->i_filesize - io->i_offset;
586
587 if (count <= 0)
588 return 0; // end of file
589
590 bcopy(io->i_buf + io->i_offset, buf, count);
591
592 io->i_offset += count;
593
594 return count;
595}
596
597//==========================================================================
598// write() - Write up to 'count' bytes of data to the file descriptor
599// from the buffer pointed to by buf.
600
601int write(int fdesc, const char * buf, int count)
602{
603 struct iob * io;
604
605 if ((io = iob_from_fdesc(fdesc)) == NULL)
606 return (-1);
607
608 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
609 count = io->i_filesize - io->i_offset;
610
611 if (count <= 0)
612 return 0; // end of file
613
614 bcopy(buf, io->i_buf + io->i_offset, count);
615
616 io->i_offset += count;
617
618 return count;
619}
620
621int writebyte(int fdesc, char value)
622{
623 struct iob * io;
624
625 if ((io = iob_from_fdesc(fdesc)) == NULL)
626 return (-1);
627
628 if ((io->i_offset + 1) > (unsigned int)io->i_filesize)
629 return 0; // end of file
630
631 io->i_buf[io->i_offset++] = value;
632
633 return 1;
634}
635
636int writeint(int fdesc, int value)
637{
638 struct iob * io;
639
640 if ((io = iob_from_fdesc(fdesc)) == NULL)
641 return (-1);
642
643 if ((io->i_offset + 4) > (unsigned int)io->i_filesize)
644 return 0; // end of file
645
646 bcopy(&value, io->i_buf + io->i_offset, 4);
647
648 io->i_offset += 4;
649
650 return 4;
651}
652
653//==========================================================================
654// file_size() - Returns the size of the file described by the file
655// descriptor.
656
657int file_size(int fdesc)
658{
659 struct iob * io;
660
661 if ((io = iob_from_fdesc(fdesc)) == 0)
662 return 0;
663
664 return io->i_filesize;
665}
666
667//==========================================================================
668
669struct dirstuff * vol_opendir(BVRef bvr, const char * path)
670{
671 struct dirstuff * dirp = 0;
672
673 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
674 if (dirp == NULL)
675 goto error;
676
677 dirp->dir_path = newString(path);
678 if (dirp->dir_path == NULL)
679 goto error;
680
681 dirp->dir_bvr = bvr;
682
683 return dirp;
684
685error:
686 closedir(dirp);
687 return NULL;
688}
689
690//==========================================================================
691
692struct dirstuff * opendir(const char * path)
693{
694 struct dirstuff * dirp = 0;
695 const char * dirPath;
696 BVRef bvr;
697
698 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
699 goto error;
700
701 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
702 if (dirp == NULL)
703 goto error;
704
705 dirp->dir_path = newString(dirPath);
706 if (dirp->dir_path == NULL)
707 goto error;
708
709 dirp->dir_bvr = bvr;
710
711 return dirp;
712
713error:
714 closedir(dirp);
715 return NULL;
716}
717
718//==========================================================================
719
720int closedir(struct dirstuff * dirp)
721{
722 if (dirp) {
723 if (dirp->dir_path) free(dirp->dir_path);
724 free(dirp);
725 }
726 return 0;
727}
728
729//==========================================================================
730
731int readdir(struct dirstuff * dirp, const char ** name, long * flags,
732 long * time)
733{
734 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
735 /* dirPath */ dirp->dir_path,
736 /* dirIndex */ &dirp->dir_index,
737 /* dirEntry */ (char **)name, flags, time,
738 0, 0);
739}
740
741//==========================================================================
742
743int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
744 long * time, FinderInfo *finderInfo, long *infoValid)
745{
746 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
747 /* dirPath */ dirp->dir_path,
748 /* dirIndex */ &dirp->dir_index,
749 /* dirEntry */ (char **)name,
750 flags, time,
751 finderInfo, infoValid);
752}
753
754//==========================================================================
755
756const char * systemConfigDir()
757{
758 if (gBootFileType == kNetworkDeviceType)
759return "";
760 return "/Library/Preferences/SystemConfiguration";
761}
762
763//==========================================================================
764
765int gBootFileType;
766
767void scanBootVolumes( int biosdev, int * count )
768{
769 BVRef bvr = 0;
770
771 bvr = diskScanBootVolumes(biosdev, count);
772 if (bvr == NULL)
773 {
774 bvr = nbpScanBootVolumes(biosdev, count);
775 if (bvr != NULL)
776 {
777 gBootFileType = kNetworkDeviceType;
778 }
779 }
780 else
781 {
782 gBootFileType = kBlockDeviceType;
783 }
784}
785
786//==========================================================================
787
788void scanDisks(int biosdev, int *count)
789{
790 #define MAX_HDD_COUNT 32
791 int bvCount;
792 int hd = 0;
793
794 // Testing up to MAX_HDD_COUNT hard drives.
795while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
796{
797 bvCount = 0;
798 scanBootVolumes(0x80 + hd, &bvCount);
799 hd++;
800}
801
802// Also scanning CD/DVD drive.
803if (biosDevIsCDROM(gBIOSDev))
804{
805bvCount = 0;
806scanBootVolumes(gBIOSDev, &bvCount);
807}
808}
809
810//==========================================================================
811
812BVRef selectBootVolume( BVRef chain )
813{
814bool filteredChain = false;
815bool foundPrimary = false;
816BVRef bvr, bvr1 = 0, bvr2 = 0;
817
818if (chain->filtered) filteredChain = true;
819
820if (multiboot_partition_set)
821for ( bvr = chain; bvr; bvr = bvr->next )
822if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
823return bvr;
824
825/*
826 * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
827 * to override the default selection.
828 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
829 */
830char *val = XMLDecode(getStringForKey(kDefaultPartition, &bootInfo->chameleonConfig));
831 if (val) {
832 for ( bvr = chain; bvr; bvr = bvr->next ) {
833 if (matchVolumeToString(bvr, val, false)) {
834 free(val);
835 return bvr;
836 }
837 }
838 free(val);
839 }
840
841/*
842 * Scannig the volume chain backwards and trying to find
843 * a HFS+ volume with valid boot record signature.
844 * If not found any active partition then we will
845 * select this volume as the boot volume.
846 */
847for ( bvr = chain; bvr; bvr = bvr->next )
848{
849 if (multiboot_skip_partition_set) {
850 if (bvr->part_no == multiboot_skip_partition) continue;
851 }
852if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = true;
853// zhell -- Undo a regression that was introduced from r491 to 492.
854// if gBIOSBootVolume is set already, no change is required
855if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
856&& gBIOSBootVolume
857&& (!filteredChain || (filteredChain && bvr->visible))
858&& bvr->biosdev == gBIOSDev )
859bvr2 = bvr;
860// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
861// from r491,
862if ( bvr->flags & kBVFlagBootable
863&& ! gBIOSBootVolume
864&& bvr->biosdev == gBIOSDev )
865bvr2 = bvr;
866}
867
868
869/*
870 * Use the standrad method for selecting the boot volume.
871 */
872if (foundPrimary)
873{
874for ( bvr = chain; bvr; bvr = bvr->next )
875{
876if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
877if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
878}
879}
880
881bvr = bvr2 ? bvr2 :
882bvr1 ? bvr1 : chain;
883
884return bvr;
885}
886
887//==========================================================================
888
889#define LP '('
890#define RP ')'
891int gBIOSDev;
892
893/*!
894 This is like boot2's gBootVolume except it is for the internal use of
895 libsaio to track which volume an unqualified path should be relative to.
896 This replaces bootInfo->kernDev as the carrier of this information.
897 */
898static BVRef gRootVolume;
899
900void setRootVolume(BVRef volume)
901{
902 gRootVolume = volume;
903 // Veto non-native FS. Basically that means don't allow the root volume to
904 // be set to a volume we can't read files from.
905 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
906 gRootVolume = NULL;
907}
908
909void setBootGlobals(BVRef chain)
910{
911 // Record default boot device.
912 gBootVolume = selectBootVolume(chain);
913
914 // turbo - Save the ORIGINAL boot volume too for loading our mkext
915 if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
916
917 setRootVolume(gBootVolume);
918}
919
920/*!
921 Extracts the volume selector from the pathname, returns the selected
922 BVRef, and sets *outPath to the remainder of the path.
923 If the path did not include a volume selector then the current volume
924 is used. When called with a volume selector the current volume
925 is changed to the selected volume unless the volume selector is
926 that of a ramdisk.
927 */
928BVRef getBootVolumeRef( const char * path, const char ** outPath )
929{
930 const char * cp;
931 BVRef bvr = gRootVolume;
932 int biosdev = gBIOSDev;
933
934 // Search for left parenthesis in the path specification.
935
936 for (cp = path; *cp; cp++) {
937 if (*cp == LP || *cp == '/') break;
938 }
939
940 if (*cp != LP) // no left paren found
941 {
942 // Path is using the implicit current device so if there is
943 // no current device, then we must fail.
944 cp = path;
945 if ( gRootVolume == NULL )
946 return NULL;
947 }
948 else if ((cp - path) == 2) // found "xx("
949 {
950 const struct devsw * dp;
951 const char * xp = path;
952 int i;
953 int unit = -1;
954 int part = -1;
955
956 cp++;
957
958 // Check the 2 character device name pointed by 'xp'.
959
960 for (dp = devsw; dp->name; dp++)
961 {
962 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
963 break; // found matching entry
964 }
965 if (dp->name == NULL)
966 {
967 error("Unknown device '%c%c'\n", xp[0], xp[1]);
968 return NULL;
969 }
970
971 // Extract the optional unit number from the specification.
972 // hd(unit) or hd(unit, part).
973
974 i = 0;
975 while (*cp >= '0' && *cp <= '9')
976 {
977 i = i * 10 + *cp++ - '0';
978 unit = i;
979 }
980
981 // Unit is no longer optional and never really was.
982 // If the user failed to specify it then the unit number from the previous kernDev
983 // would have been used which makes little sense anyway.
984 // For example, if the user did fd()/foobar and the current root device was the
985 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
986 if(unit == -1)
987 return NULL;
988
989 // Extract the optional partition number from the specification.
990
991 if (*cp == ',')
992 part = atoi(++cp);
993
994 // If part is not specified part will be -1 whereas before it would have been
995 // whatever the last partition was which makes about zero sense if the device
996 // has been switched.
997
998 // Skip past the right paren.
999
1000 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
1001 if (*cp == RP) cp++;
1002
1003 biosdev = dp->biosdev + unit;
1004bvr = newBootVolumeRef(biosdev, part);
1005
1006 if(bvr == NULL)
1007 return NULL;
1008 }
1009 else
1010 {
1011 // Bad device specifier, skip past the right paren.
1012
1013 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
1014 if (*cp == RP) cp++;
1015 // If gRootVolume was NULL, then bvr will be NULL as well which
1016 // should be caught by the caller.
1017 }
1018
1019 // Returns the file path following the device spec.
1020 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1021
1022 *outPath = cp;
1023
1024 return bvr;
1025}
1026
1027//==========================================================================
1028// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1029// which caches the information. So it's only allocated on the first run.
1030static BVRef newBootVolumeRef( int biosdev, int partno )
1031{
1032BVRef bvr, bvr1, bvrChain;
1033
1034bvr = bvr1 = NULL;
1035
1036 // Try resolving "rd" and "bt" devices first.
1037if (biosdev == kPseudoBIOSDevRAMDisk)
1038{
1039if (gRAMDiskVolume)
1040 bvr1 = gRAMDiskVolume;
1041}
1042else if (biosdev == kPseudoBIOSDevBooter)
1043{
1044if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
1045bvr1 = gRAMDiskVolume;
1046else
1047bvr1 = gBIOSBootVolume;
1048}
1049else
1050{
1051// Fetch the volume list from the device.
1052
1053scanBootVolumes( biosdev, NULL );
1054bvrChain = getBVChainForBIOSDev(biosdev);
1055
1056// Look for a perfect match based on device and partition number.
1057
1058for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1059{
1060if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1061
1062bvr1 = bvr;
1063if ( bvr->part_no == partno ) break;
1064}
1065}
1066
1067return bvr ? bvr : bvr1;
1068}
1069
1070//==========================================================================
1071// getDeviceDescription() - Extracts unit number and partition number
1072// from bvr structure into "dw(u,p)" format.
1073// Returns length of the out string
1074int getDeviceDescription(BVRef bvr, char *str)
1075{
1076 if(!str)
1077 return 0;
1078
1079*str = '\0';
1080
1081if (bvr)
1082{
1083 const struct devsw *dp = devsw;
1084while(dp->name && bvr->biosdev >= dp->biosdev)
1085 dp++;
1086
1087dp--;
1088if (dp->name)
1089 return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1090}
1091
1092return 0;
1093}
1094

Archive Download this file

Revision: 2029