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

Archive Download this file

Revision: 1916