Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2391