Chameleon

Chameleon Svn Source Tree

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