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 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#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
854 int gBIOSDev = (int)get_env(envgBIOSDev);
855
856#if UNUSED
857if (multiboot_partition_set)
858for ( bvr = chain; bvr; bvr = bvr->next )
859if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
860return bvr;
861#endif
862/*
863 * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
864 * to override the default selection.
865 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
866 */
867char *val = XMLDecode(getStringForKey(kDefaultPartition, DEFAULT_BOOT_CONFIG));
868 if (val) {
869 for ( bvr = chain; bvr; bvr = bvr->next ) {
870 if (matchVolumeToString(bvr, val, false)) {
871 free(val);
872 return bvr;
873 }
874 }
875 free(val);
876 }
877
878/*
879 * Scannig the volume chain backwards and trying to find
880 * a HFS+ volume with valid boot record signature.
881 * If not found any active partition then we will
882 * select this volume as the boot volume.
883 */
884for ( bvr = chain; bvr; bvr = bvr->next )
885{
886if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = true;
887// zhell -- Undo a regression that was introduced from r491 to 492.
888// if gBIOSBootVolume is set already, no change is required
889if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
890&& gBIOSBootVolume
891&& (!filteredChain || (filteredChain && bvr->visible))
892&& bvr->biosdev == gBIOSDev )
893bvr2 = bvr;
894// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
895// from r491,
896if ( bvr->flags & kBVFlagBootable
897&& ! gBIOSBootVolume
898&& bvr->biosdev == gBIOSDev )
899bvr2 = bvr;
900}
901
902
903/*
904 * Use the standrad method for selecting the boot volume.
905 */
906if (foundPrimary)
907{
908for ( bvr = chain; bvr; bvr = bvr->next )
909{
910if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
911if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
912}
913}
914
915bvr = bvr2 ? bvr2 :
916bvr1 ? bvr1 : chain;
917
918return bvr;
919}
920
921//==========================================================================
922
923#define LP '('
924#define RP ')'
925
926/*!
927 This is like boot2's gBootVolume except it is for the internal use of
928 libsaio to track which volume an unqualified path should be relative to.
929 This replaces bootInfo->kernDev as the carrier of this information.
930 */
931static BVRef gRootVolume;
932
933void setRootVolume(BVRef volume)
934{
935 gRootVolume = volume;
936 // Veto non-native FS. Basically that means don't allow the root volume to
937 // be set to a volume we can't read files from.
938 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
939 gRootVolume = NULL;
940}
941
942void setBootGlobals(BVRef chain)
943{
944// Record default boot device.
945gBootVolume = selectBootVolume(chain);
946
947// turbo - Save the ORIGINAL boot volume too for loading our mkext
948if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
949
950setRootVolume(gBootVolume);
951}
952
953/*!
954 Extracts the volume selector from the pathname, returns the selected
955 BVRef, and sets *outPath to the remainder of the path.
956 If the path did not include a volume selector then the current volume
957 is used. When called with a volume selector the current volume
958 is changed to the selected volume unless the volume selector is
959 that of a ramdisk.
960 */
961BVRef getBootVolumeRef( const char * path, const char ** outPath )
962{
963 const char * cp;
964 BVRef bvr = gRootVolume;
965 int biosdev = (int)get_env(envgBIOSDev);
966
967 // Search for left parenthesis in the path specification.
968
969 for (cp = path; *cp; cp++) {
970 if (*cp == LP || *cp == '/') break;
971 }
972
973 if (*cp != LP) // no left paren found
974 {
975 // Path is using the implicit current device so if there is
976 // no current device, then we must fail.
977 cp = path;
978 if ( gRootVolume == NULL )
979 return NULL;
980 }
981 else if ((cp - path) == 2) // found "xx("
982 {
983 const struct devsw * dp;
984 const char * xp = path;
985 int i;
986 int unit = -1;
987 int part = -1;
988
989 cp++;
990
991 // Check the 2 character device name pointed by 'xp'.
992
993 for (dp = devsw; dp->name; dp++)
994 {
995 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
996 break; // found matching entry
997 }
998 if (dp->name == NULL)
999 {
1000 error("Unknown device '%c%c'\n", xp[0], xp[1]);
1001 return NULL;
1002 }
1003
1004 // Extract the optional unit number from the specification.
1005 // hd(unit) or hd(unit, part).
1006
1007 i = 0;
1008 while (*cp >= '0' && *cp <= '9')
1009 {
1010 i = i * 10 + *cp++ - '0';
1011 unit = i;
1012 }
1013
1014 // Unit is no longer optional and never really was.
1015 // If the user failed to specify it then the unit number from the previous kernDev
1016 // would have been used which makes little sense anyway.
1017 // For example, if the user did fd()/foobar and the current root device was the
1018 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
1019 if(unit == -1)
1020 return NULL;
1021
1022 // Extract the optional partition number from the specification.
1023
1024 if (*cp == ',')
1025 part = atoi(++cp);
1026
1027 // If part is not specified part will be -1 whereas before it would have been
1028 // whatever the last partition was which makes about zero sense if the device
1029 // has been switched.
1030
1031 // Skip past the right paren.
1032
1033 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
1034 if (*cp == RP) cp++;
1035
1036 biosdev = dp->biosdev + unit;
1037 bvr = newBootVolumeRef(biosdev, part);
1038
1039 if(bvr == NULL)
1040 return NULL;
1041 }
1042 else
1043 {
1044 // Bad device specifier, skip past the right paren.
1045
1046 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
1047 if (*cp == RP) cp++;
1048 // If gRootVolume was NULL, then bvr will be NULL as well which
1049 // should be caught by the caller.
1050 }
1051
1052 // Returns the file path following the device spec.
1053 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1054
1055 *outPath = cp;
1056
1057 return bvr;
1058}
1059
1060//==========================================================================
1061// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1062// which caches the information. So it's only allocated on the first run.
1063static BVRef newBootVolumeRef( int biosdev, int partno )
1064{
1065BVRef bvr, bvr1, bvrChain;
1066
1067bvr = bvr1 = NULL;
1068
1069 // Try resolving "rd" and "bt" devices first.
1070execute_hook("newRamDisk_BVR", &biosdev, &bvr1, NULL, NULL, NULL, NULL);
1071
1072 // Try resolving "rd" and "bt" devices first.
1073
1074if (biosdev == kPseudoBIOSDevBooter)
1075{
1076if (bvr1 == NULL )
1077bvr1 = gBIOSBootVolume;
1078}
1079else
1080{
1081// Fetch the volume list from the device.
1082
1083scanBootVolumes( biosdev, NULL );
1084bvrChain = getBVChainForBIOSDev(biosdev);
1085
1086// Look for a perfect match based on device and partition number.
1087
1088for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1089{
1090if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1091
1092bvr1 = bvr;
1093if ( bvr->part_no == partno ) break;
1094}
1095}
1096
1097return bvr ? bvr : bvr1;
1098}
1099
1100//==========================================================================
1101// getDeviceDescription() - Extracts unit number and partition number
1102// from bvr structure into "dw(u,p)" format.
1103// Returns length of the out string
1104int getDeviceDescription(BVRef bvr, char *str)
1105{
1106 if(!str)
1107 return 0;
1108
1109*str = '\0';
1110
1111if (bvr)
1112{
1113 const struct devsw *dp = devsw;
1114while(dp->name && bvr->biosdev >= dp->biosdev)
1115 dp++;
1116
1117dp--;
1118if (dp->name)
1119 return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1120}
1121
1122return 0;
1123}
1124

Archive Download this file

Revision: 1840