Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1119