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

Archive Download this file

Revision: 1931