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

Archive Download this file

Revision: 1468