Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2379