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{
456const 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#endif
661//==========================================================================
662// lseek() - Reposition the byte offset of the file descriptor from the
663// beginning of the file. Returns the relocated offset.
664
665int b_lseek(int fdesc, int offset, int ptr)
666{
667 struct iob * io;
668
669 if ((io = iob_from_fdesc(fdesc)) == NULL)
670 return (-1);
671
672 io->i_offset = offset;
673
674 return offset;
675}
676#if UNUSED
677//==========================================================================
678// tell() - Returns the byte offset of the file descriptor.
679
680int tell(int fdesc)
681{
682 struct iob * io;
683
684 if ((io = iob_from_fdesc(fdesc)) == NULL)
685 return 0;
686
687 return io->i_offset;
688}
689
690//==========================================================================
691// write() - Write up to 'count' bytes of data to the file descriptor
692// from the buffer pointed to by buf.
693
694int write(int fdesc, const char * buf, int count)
695{
696 struct iob * io;
697
698 if ((io = iob_from_fdesc(fdesc)) == NULL)
699 return (-1);
700
701 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
702 count = io->i_filesize - io->i_offset;
703
704 if (count <= 0)
705 return 0; // end of file
706
707 bcopy(buf, io->i_buf + io->i_offset, count);
708
709 io->i_offset += count;
710
711 return count;
712}
713
714int writebyte(int fdesc, char value)
715{
716 struct iob * io;
717
718 if ((io = iob_from_fdesc(fdesc)) == NULL)
719 return (-1);
720
721 if ((io->i_offset + 1) > (unsigned int)io->i_filesize)
722 return 0; // end of file
723
724 io->i_buf[io->i_offset++] = value;
725
726 return 1;
727}
728
729int writeint(int fdesc, int value)
730{
731 struct iob * io;
732
733 if ((io = iob_from_fdesc(fdesc)) == NULL)
734 return (-1);
735
736 if ((io->i_offset + 4) > (unsigned int)io->i_filesize)
737 return 0; // end of file
738
739 bcopy(&value, io->i_buf + io->i_offset, 4);
740
741 io->i_offset += 4;
742
743 return 4;
744}
745//==========================================================================
746
747struct dirstuff * vol_opendir(BVRef bvr, const char * path)
748{
749 struct dirstuff * dirp = 0;
750
751 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
752 if (dirp == NULL)
753 goto error;
754
755 dirp->dir_path = newString(path);
756 if (dirp->dir_path == NULL)
757 goto error;
758
759 dirp->dir_bvr = bvr;
760
761 return dirp;
762
763error:
764 closedir(dirp);
765 return NULL;
766}
767
768//==========================================================================
769
770int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
771long * time, FinderInfo *finderInfo, long *infoValid)
772{
773 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
774 /* dirPath */ dirp->dir_path,
775 /* dirIndex */ &dirp->dir_index,
776 /* dirEntry */ (char **)name,
777 flags, time,
778 finderInfo, infoValid);
779}
780//==========================================================================
781
782const char * systemConfigDir()
783{
784 if (gBootFileType == kNetworkDeviceType)
785return "";
786 return "/Library/Preferences/SystemConfiguration";
787}
788
789#endif
790
791//==========================================================================
792
793int gBootFileType;
794
795void scanBootVolumes( int biosdev, int * count )
796{
797BVRef bvr = 0;
798
799bvr = diskScanBootVolumes(biosdev, count);
800if (bvr == NULL)
801{
802#ifdef NBP_SUPPORT
803bvr = nbpScanBootVolumes(biosdev, count);
804if (bvr != NULL)
805{
806gBootFileType = kNetworkDeviceType;
807}
808#endif
809}
810else
811{
812gBootFileType = kBlockDeviceType;
813}
814}
815
816//==========================================================================
817#if UNUSED
818void scanDisks(int biosdev, int *count)
819#else
820void scanDisks(void)
821#endif
822{
823#define MAX_HDD_COUNT 32
824int bvCount;
825int hd = 0;
826
827// Testing up to MAX_HDD_COUNT hard drives.
828while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
829{
830bvCount = 0;
831scanBootVolumes(0x80 + hd, &bvCount);
832hd++;
833}
834
835// Also scanning CD/DVD drive.
836if (biosDevIsCDROM(gBIOSDev))
837{
838bvCount = 0;
839scanBootVolumes(gBIOSDev, &bvCount);
840}
841}
842
843//==========================================================================
844
845BVRef selectBootVolume( BVRef chain )
846{
847bool filteredChain = false;
848bool foundPrimary = false;
849BVRef bvr, bvr1 = 0, bvr2 = 0;
850
851if (chain->filtered) filteredChain = true;
852
853#if UNUSED
854if (multiboot_partition_set)
855for ( bvr = chain; bvr; bvr = bvr->next )
856if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
857return bvr;
858#endif
859/*
860 * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
861 * to override the default selection.
862 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
863 */
864char *val = XMLDecode(getStringForKey(kDefaultPartition, &bootInfo->bootConfig));
865 if (val) {
866 for ( bvr = chain; bvr; bvr = bvr->next ) {
867 if (matchVolumeToString(bvr, val, false)) {
868 free(val);
869 return bvr;
870 }
871 }
872 free(val);
873 }
874
875/*
876 * Scannig the volume chain backwards and trying to find
877 * a HFS+ volume with valid boot record signature.
878 * If not found any active partition then we will
879 * select this volume as the boot volume.
880 */
881for ( bvr = chain; bvr; bvr = bvr->next )
882{
883if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = true;
884// zhell -- Undo a regression that was introduced from r491 to 492.
885// if gBIOSBootVolume is set already, no change is required
886if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
887&& gBIOSBootVolume
888&& (!filteredChain || (filteredChain && bvr->visible))
889&& bvr->biosdev == gBIOSDev )
890bvr2 = bvr;
891// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
892// from r491,
893if ( bvr->flags & kBVFlagBootable
894&& ! gBIOSBootVolume
895&& bvr->biosdev == gBIOSDev )
896bvr2 = bvr;
897}
898
899
900/*
901 * Use the standrad method for selecting the boot volume.
902 */
903if (foundPrimary)
904{
905for ( bvr = chain; bvr; bvr = bvr->next )
906{
907if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
908if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
909}
910}
911
912bvr = bvr2 ? bvr2 :
913bvr1 ? bvr1 : chain;
914
915return bvr;
916}
917
918//==========================================================================
919
920#define LP '('
921#define RP ')'
922int gBIOSDev;
923
924/*!
925 This is like boot2's gBootVolume except it is for the internal use of
926 libsaio to track which volume an unqualified path should be relative to.
927 This replaces bootInfo->kernDev as the carrier of this information.
928 */
929static BVRef gRootVolume;
930
931void setRootVolume(BVRef volume)
932{
933 gRootVolume = volume;
934 // Veto non-native FS. Basically that means don't allow the root volume to
935 // be set to a volume we can't read files from.
936 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
937 gRootVolume = NULL;
938}
939
940void setBootGlobals(BVRef chain)
941{
942// Record default boot device.
943gBootVolume = selectBootVolume(chain);
944
945// turbo - Save the ORIGINAL boot volume too for loading our mkext
946if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
947
948setRootVolume(gBootVolume);
949}
950
951/*!
952 Extracts the volume selector from the pathname, returns the selected
953 BVRef, and sets *outPath to the remainder of the path.
954 If the path did not include a volume selector then the current volume
955 is used. When called with a volume selector the current volume
956 is changed to the selected volume unless the volume selector is
957 that of a ramdisk.
958 */
959BVRef getBootVolumeRef( const char * path, const char ** outPath )
960{
961 const char * cp;
962 BVRef bvr = gRootVolume;
963 int biosdev = gBIOSDev;
964
965 // Search for left parenthesis in the path specification.
966
967 for (cp = path; *cp; cp++) {
968 if (*cp == LP || *cp == '/') break;
969 }
970
971 if (*cp != LP) // no left paren found
972 {
973 // Path is using the implicit current device so if there is
974 // no current device, then we must fail.
975 cp = path;
976 if ( gRootVolume == NULL )
977 return NULL;
978 }
979 else if ((cp - path) == 2) // found "xx("
980 {
981 const struct devsw * dp;
982 const char * xp = path;
983 int i;
984 int unit = -1;
985 int part = -1;
986
987 cp++;
988
989 // Check the 2 character device name pointed by 'xp'.
990
991 for (dp = devsw; dp->name; dp++)
992 {
993 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
994 break; // found matching entry
995 }
996 if (dp->name == NULL)
997 {
998 error("Unknown device '%c%c'\n", xp[0], xp[1]);
999 return NULL;
1000 }
1001
1002 // Extract the optional unit number from the specification.
1003 // hd(unit) or hd(unit, part).
1004
1005 i = 0;
1006 while (*cp >= '0' && *cp <= '9')
1007 {
1008 i = i * 10 + *cp++ - '0';
1009 unit = i;
1010 }
1011
1012 // Unit is no longer optional and never really was.
1013 // If the user failed to specify it then the unit number from the previous kernDev
1014 // would have been used which makes little sense anyway.
1015 // For example, if the user did fd()/foobar and the current root device was the
1016 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
1017 if(unit == -1)
1018 return NULL;
1019
1020 // Extract the optional partition number from the specification.
1021
1022 if (*cp == ',')
1023 part = atoi(++cp);
1024
1025 // If part is not specified part will be -1 whereas before it would have been
1026 // whatever the last partition was which makes about zero sense if the device
1027 // has been switched.
1028
1029 // Skip past the right paren.
1030
1031 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
1032 if (*cp == RP) cp++;
1033
1034 biosdev = dp->biosdev + unit;
1035 bvr = newBootVolumeRef(biosdev, part);
1036
1037 if(bvr == NULL)
1038 return NULL;
1039 }
1040 else
1041 {
1042 // Bad device specifier, skip past the right paren.
1043
1044 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
1045 if (*cp == RP) cp++;
1046 // If gRootVolume was NULL, then bvr will be NULL as well which
1047 // should be caught by the caller.
1048 }
1049
1050 // Returns the file path following the device spec.
1051 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1052
1053 *outPath = cp;
1054
1055 return bvr;
1056}
1057
1058//==========================================================================
1059// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1060// which caches the information. So it's only allocated on the first run.
1061static BVRef newBootVolumeRef( int biosdev, int partno )
1062{
1063BVRef bvr, bvr1, bvrChain;
1064
1065bvr = bvr1 = NULL;
1066
1067 // Try resolving "rd" and "bt" devices first.
1068execute_hook("newRamDisk_BVR", &biosdev, &bvr1, NULL, NULL, NULL, NULL);
1069
1070 // Try resolving "rd" and "bt" devices first.
1071
1072if (biosdev == kPseudoBIOSDevBooter)
1073{
1074if (bvr1 == NULL )
1075bvr1 = gBIOSBootVolume;
1076}
1077else
1078{
1079// Fetch the volume list from the device.
1080
1081scanBootVolumes( biosdev, NULL );
1082bvrChain = getBVChainForBIOSDev(biosdev);
1083
1084// Look for a perfect match based on device and partition number.
1085
1086for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1087{
1088if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1089
1090bvr1 = bvr;
1091if ( bvr->part_no == partno ) break;
1092}
1093}
1094
1095return bvr ? bvr : bvr1;
1096}
1097
1098//==========================================================================
1099// getDeviceDescription() - Extracts unit number and partition number
1100// from bvr structure into "dw(u,p)" format.
1101// Returns length of the out string
1102int getDeviceDescription(BVRef bvr, char *str)
1103{
1104 if(!str)
1105 return 0;
1106
1107*str = '\0';
1108
1109if (bvr)
1110{
1111 const struct devsw *dp = devsw;
1112while(dp->name && bvr->biosdev >= dp->biosdev)
1113 dp++;
1114
1115dp--;
1116if (dp->name)
1117 return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1118}
1119
1120return 0;
1121}
1122

Archive Download this file

Revision: 1804