Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2382