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
113static BVRef newBootVolumeRef( int biosdev, int partno );
114static int GetFreeFd(void);
115
116static int open_bvr(BVRef bvr, const char *filePath);
117
118//==========================================================================
119// LoadVolumeFile - LOW-LEVEL FILESYSTEM FUNCTION.
120// Load the specified file from the specified volume
121// to the load buffer at LOAD_ADDR.
122// If the file is fat, load only the i386 portion.
123
124long LoadVolumeFile(BVRef bvr, const char *filePath)
125{
126 long fileSize;
127
128 // Read file into load buffer. The data in the load buffer will be
129 // overwritten by the next LoadFile() call.
130
131safe_set_env(envgFSLoadAddress, (uint32_t)(void *)LOAD_ADDR);
132
133 fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
134
135 // Return the size of the file, or -1 if load failed.
136
137 return fileSize;
138}
139
140//==========================================================================
141// LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
142// Load the specified file to the load buffer at LOAD_ADDR.
143// If the file is fat, load only the i386 portion.
144
145long LoadFile(const char * fileSpec)
146{
147 const char * filePath;
148 BVRef bvr;
149
150 // Resolve the boot volume from the file spec.
151
152 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
153 return -1;
154
155 return LoadVolumeFile(bvr, filePath);
156}
157
158#if UNUSED
159long ReadFileAtOffset(const char * fileSpec, void *buffer, uint64_t offset, uint64_t length)
160{
161 const char *filePath;
162 BVRef bvr;
163
164 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
165 return -1;
166
167 if (bvr->fs_readfile == NULL)
168 return -1;
169
170 return bvr->fs_readfile(bvr, (char *)filePath, buffer, offset, length);
171}
172#endif
173
174long LoadThinFatFile(const char *fileSpec, void **binary)
175{
176 const char *filePath;
177 FSReadFile readFile;
178 BVRef bvr;
179 unsigned long length/*, length2*/;
180long length2;
181
182 // Resolve the boot volume from the file spec.
183
184 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
185 return -1;
186
187 *binary = (void *)kLoadAddr;
188
189 // Read file into load buffer. The data in the load buffer will be
190 // overwritten by the next LoadFile() call.
191
192safe_set_env(envgFSLoadAddress, (uint32_t)(void *)LOAD_ADDR);
193
194 readFile = bvr->fs_readfile;
195
196 if (readFile != NULL) {
197 // Read the first 4096 bytes (fat header)
198 length = readFile(bvr, (char *)filePath, *binary, 0, 0x1000);
199 if (length > 0) {
200 if (ThinFatFile(binary, &length) == 0) {
201if (length == 0)
202return 0;
203 // We found a fat binary; read only the thin part
204 length = readFile(bvr, (char *)filePath,
205 (void *)kLoadAddr, (unsigned long)(*binary) - kLoadAddr, length);
206 *binary = (void *)kLoadAddr;
207 } else {
208 // Not a fat binary; read the rest of the file
209 length2 = readFile(bvr, (char *)filePath, (void *)(kLoadAddr + length), length, 0);
210 //if (length2 == -1) return -1;
211if (length2 < 0) return -1;
212
213 length += (unsigned long)length2;
214 }
215 }
216 } else {
217 length = bvr->fs_loadfile(bvr, (char *)filePath);
218 if (length > 0) {
219 ThinFatFile(binary, &length);
220 }
221 }
222
223 return length;
224}
225
226// filesystem-specific getUUID functions call this shared string generator
227long CreateUUIDString(uint8_t uubytes[], int nbytes, char *uuidStr)
228{
229 unsigned fmtbase, fmtidx, i;
230 uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 };
231 char *p = uuidStr;
232 MD5_CTX md5c;
233 uint8_t mdresult[16];
234
235 bzero(mdresult, sizeof(mdresult));
236
237 // just like AppleFileSystemDriver
238 MD5Init(&md5c);
239 MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1));
240 MD5Update(&md5c, uubytes, nbytes);
241 MD5Final(mdresult, &md5c);
242
243 // this UUID has been made version 3 style (i.e. via namespace)
244 // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte)
245 mdresult[6] = 0x30 | ( mdresult[6] & 0x0F );
246 mdresult[8] = 0x80 | ( mdresult[8] & 0x3F );
247
248
249 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
250 fmtbase = 0;
251 for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) {
252 for(i=0; i < uuidfmt[fmtidx]; i++) {
253 uint8_t byte = mdresult[fmtbase+i];
254 char nib;
255
256 nib = byte >> 4;
257 *p = nib + '0'; // 0x4 -> '4'
258 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
259 p++;
260
261 nib = byte & 0xf;
262 *p = nib + '0'; // 0x4 -> '4'
263 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
264 p++;
265
266 }
267 fmtbase += i;
268 if(fmtidx < sizeof(uuidfmt)-1)
269 *(p++) = '-';
270 else
271 *p = '\0';
272 }
273
274 return 0;
275}
276
277
278//==========================================================================
279// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
280// Fetch the next directory entry for the given directory.
281
282long GetDirEntry(const char * dirSpec, long long * dirIndex, const char ** name,
283 long * flags, long * time)
284{
285 const char * dirPath;
286 BVRef bvr;
287
288 // Resolve the boot volume from the dir spec.
289
290 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
291 return -1;
292
293 // Return 0 on success, or -1 if there are no additional entries.
294
295 return bvr->fs_getdirentry( bvr,
296 /* dirPath */ (char *)dirPath,
297 /* dirIndex */ dirIndex,
298 /* dirEntry */ (char **)name, flags, time, 0, 0 );
299}
300
301//==========================================================================
302// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
303// Get attributes for the specified file.
304
305static char* gMakeDirSpec;
306
307long GetFileInfo(const char * dirSpec, const char * name,
308 long * flags, long * time)
309{
310 long long index = 0;
311 const char * entryName;
312
313 if (gMakeDirSpec == 0)
314 gMakeDirSpec = (char *)malloc(1024);
315
316if (!gMakeDirSpec) return -1;
317
318 if (!dirSpec) {
319 long idx, len;
320
321 len = strlen(name);
322
323 for (idx = len; idx && (name[idx] != '/' && name[idx] != '\\'); idx--) {}
324 if (idx == 0) {
325 gMakeDirSpec[0] = '/';
326 gMakeDirSpec[1] = '\0';
327 } else {
328 idx++;
329 strncpy(gMakeDirSpec, name, idx);
330 name += idx;
331 }
332 dirSpec = gMakeDirSpec;
333 }
334
335 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
336 {
337 if (strcmp(entryName, name) == 0)
338 return 0; // success
339 }
340 return -1; // file not found
341}
342
343//==========================================================================
344// GetFreeFD()
345
346static int GetFreeFd(void)
347{
348intfd;
349
350// Locate a free descriptor slot.
351for (fd = 0; fd < NFILES; fd++) {
352if (iob[fd].i_flgs == 0) {
353return fd;
354}
355}
356stop("Out of file descriptors");
357// not reached
358return -1;
359}
360
361//==========================================================================
362// iob_from_fdesc()
363//
364// Return a pointer to an allocated 'iob' based on the file descriptor
365// provided. Returns NULL if the file descriptor given is invalid.
366
367struct iob * iob_from_fdesc(int fdesc)
368{
369 register struct iob * io;
370
371 if (fdesc < 0 || fdesc >= NFILES ||
372 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
373 return NULL;
374 else
375 return io;
376}
377
378//==========================================================================
379// open() - Open the file specified by 'path' for reading.
380
381static int open_bvr(BVRef bvr, const char *filePath)
382{
383struct iob*io;
384intfdesc;
385inti;
386
387if (bvr == NULL) {
388return -1;
389}
390
391fdesc = GetFreeFd();
392io = &iob[fdesc];
393bzero(io, sizeof(*io));
394
395// Mark the descriptor as taken.
396io->i_flgs = F_ALLOC;
397
398// Find the next available memory block in the download buffer.
399io->i_buf = (char *) LOAD_ADDR;
400for (i = 0; i < NFILES; i++) {
401if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) {
402continue;
403}
404io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
405}
406
407// Load entire file into memory. Unnecessary open() calls must be avoided.
408//gFSLoadAddress = io->i_buf;
409safe_set_env(envgFSLoadAddress, (uint32_t)(void *)io->i_buf);
410
411io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
412if (io->i_filesize < 0) {
413close(fdesc);
414return -1;
415}
416return fdesc;
417}
418
419
420int open(const char *path)
421{
422const char*filepath;
423BVRefbvr;
424
425// Resolve the boot volume from the file spec.
426if ((bvr = getBootVolumeRef(path, &filepath)) != NULL) {
427
428 return open_bvr(bvr, filepath);
429}
430return -1;
431}
432
433
434int open_bvdev(const char *bvd, const char *path)
435{
436const struct devsw*dp;
437const char*cp;
438BVRefbvr;
439inti;
440intlen;
441intunit;
442intpartition;
443
444if ((i = open(path)) >= 0) {
445return i;
446}
447
448if (bvd == NULL || (len = strlen(bvd)) < 2) {
449return -1;
450}
451
452for (dp=devsw; dp->name; dp++) {
453if (bvd[0] == dp->name[0] && bvd[1] == dp->name[1]) {
454unit = 0;
455partition = 0;
456/* get optional unit and partition */
457if (len >= 5 && bvd[2] == '(') { /* min must be present xx(0) */
458cp = &bvd[3];
459i = 0;
460while ((cp - path) < len && isdigit(*cp)) {
461i = i * 10 + *cp++ - '0';
462unit = i;
463}
464if (*cp++ == ',') {
465i = 0;
466while ((cp - path) < len && isdigit(*cp)) {
467i = i * 10 + *cp++ - '0';
468partition = i;
469}
470}
471}
472bvr = newBootVolumeRef(dp->biosdev + unit, partition);
473
474 return open_bvr(bvr, path);
475}
476}
477return -1;
478}
479
480//==========================================================================
481// close() - Close a file descriptor.
482
483int close(int fdesc)
484{
485 struct iob * io;
486
487 if ((io = iob_from_fdesc(fdesc)) == NULL)
488 return (-1);
489
490 io->i_flgs = 0;
491
492 return 0;
493}
494
495//==========================================================================
496// read() - Read up to 'count' bytes of data from the file descriptor
497// into the buffer pointed to by buf.
498
499int read(int fdesc, char * buf, int count)
500{
501 struct iob * io;
502
503 if ((io = iob_from_fdesc(fdesc)) == NULL)
504 return (-1);
505
506 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
507 count = io->i_filesize - io->i_offset;
508
509 if (count <= 0)
510 return 0; // end of file
511
512 bcopy(io->i_buf + io->i_offset, buf, count);
513
514 io->i_offset += count;
515
516 return count;
517}
518
519//==========================================================================
520// file_size() - Returns the size of the file described by the file
521// descriptor.
522
523int file_size(int fdesc)
524{
525 struct iob * io;
526
527 if ((io = iob_from_fdesc(fdesc)) == 0)
528 return 0;
529
530 return io->i_filesize;
531}
532
533#if UNUSED
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
585long GetFSUUID(char *spec, char *uuidStr)
586{
587 BVRef bvr;
588 long rval = -1;
589 const char *devSpec;
590
591 if ((bvr = getBootVolumeRef(spec, &devSpec)) == NULL)
592 return -1;
593
594 if(bvr->fs_getuuid)
595 rval = bvr->fs_getuuid(bvr, uuidStr);
596
597 return rval;
598}
599
600long GetFileBlock(const char *fileSpec, unsigned long long *firstBlock)
601{
602 const char * filePath;
603 BVRef bvr;
604
605 // Resolve the boot volume from the file spec.
606
607 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) {
608 printf("Boot volume for '%s' is bogus\n", fileSpec);
609 return -1;
610 }
611
612 return bvr->fs_getfileblock(bvr, (char *)filePath, firstBlock);
613}
614
615//==========================================================================
616// openmem()
617
618int openmem(char * buf, int len)
619{
620 int fdesc;
621 struct iob * io;
622
623 fdesc = GetFreeFd();
624 io = &iob[fdesc];
625 bzero(io, sizeof(*io));
626
627 // Mark the descriptor as taken. Set the F_MEM flag to indicate
628 // that the file buffer is provided by the caller.
629
630 io->i_flgs = F_ALLOC | F_MEM;
631 io->i_buf = buf;
632 io->i_filesize = len;
633
634 return fdesc;
635}
636
637//==========================================================================
638// lseek() - Reposition the byte offset of the file descriptor from the
639// beginning of the file. Returns the relocated offset.
640
641int b_lseek(int fdesc, int offset, int ptr)
642{
643 struct iob * io;
644
645 if ((io = iob_from_fdesc(fdesc)) == NULL)
646 return (-1);
647
648 io->i_offset = offset;
649
650 return offset;
651}
652
653//==========================================================================
654// tell() - Returns the byte offset of the file descriptor.
655
656int tell(int fdesc)
657{
658 struct iob * io;
659
660 if ((io = iob_from_fdesc(fdesc)) == NULL)
661 return 0;
662
663 return io->i_offset;
664}
665#endif
666//==========================================================================
667// write() - Write up to 'count' bytes of data to the file descriptor
668// from the buffer pointed to by buf.
669
670int write(int fdesc, const char * buf, int count)
671{
672 struct iob * io;
673
674 if ((io = iob_from_fdesc(fdesc)) == NULL)
675 return (-1);
676
677 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
678 count = io->i_filesize - io->i_offset;
679
680 if (count <= 0)
681 return 0; // end of file
682
683 bcopy(buf, io->i_buf + io->i_offset, count);
684
685 io->i_offset += count;
686
687 return count;
688}
689#if UNUSED
690int writebyte(int fdesc, char value)
691{
692 struct iob * io;
693
694 if ((io = iob_from_fdesc(fdesc)) == NULL)
695 return (-1);
696
697 if ((io->i_offset + 1) > (unsigned int)io->i_filesize)
698 return 0; // end of file
699
700 io->i_buf[io->i_offset++] = value;
701
702 return 1;
703}
704
705int writeint(int fdesc, int value)
706{
707 struct iob * io;
708
709 if ((io = iob_from_fdesc(fdesc)) == NULL)
710 return (-1);
711
712 if ((io->i_offset + 4) > (unsigned int)io->i_filesize)
713 return 0; // end of file
714
715 bcopy(&value, io->i_buf + io->i_offset, 4);
716
717 io->i_offset += 4;
718
719 return 4;
720}
721//==========================================================================
722
723struct dirstuff * vol_opendir(BVRef bvr, const char * path)
724{
725 struct dirstuff * dirp = 0;
726
727 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
728 if (dirp == NULL)
729 goto error;
730
731 dirp->dir_path = newString(path);
732 if (dirp->dir_path == NULL)
733 goto error;
734
735 dirp->dir_bvr = bvr;
736
737 return dirp;
738
739error:
740 closedir(dirp);
741 return NULL;
742}
743
744//==========================================================================
745
746int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
747long * time, FinderInfo *finderInfo, long *infoValid)
748{
749 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
750 /* dirPath */ dirp->dir_path,
751 /* dirIndex */ &dirp->dir_index,
752 /* dirEntry */ (char **)name,
753 flags, time,
754 finderInfo, infoValid);
755}
756//==========================================================================
757
758const char * systemConfigDir()
759{
760 if (get_env(envgBootFileType) == kNetworkDeviceType)
761return "";
762 return "/Library/Preferences/SystemConfiguration";
763}
764
765#endif
766
767//==========================================================================
768
769void scanBootVolumes( int biosdev, int * count )
770{
771BVRef bvr = 0;
772
773bvr = diskScanBootVolumes(biosdev, count);
774if (bvr == NULL)
775{
776#ifdef NBP_SUPPORT
777bvr = nbpScanBootVolumes(biosdev, count);
778if (bvr != NULL)
779{
780safe_set_env(envgBootFileType, kNetworkDeviceType);
781}
782#endif
783}
784else
785{
786safe_set_env(envgBootFileType, kBlockDeviceType);
787
788}
789}
790
791//==========================================================================
792
793void scanDisks(void)
794{
795#define MAX_HDD_COUNT 32
796int bvCount;
797int hd = 0;
798
799// Testing up to MAX_HDD_COUNT hard drives.
800while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
801{
802bvCount = 0;
803scanBootVolumes(0x80 + hd, &bvCount);
804hd++;
805}
806int gBIOSDev = (int)get_env(envgBIOSDev);
807// Also scanning CD/DVD drive.
808if (biosDevIsCDROM(gBIOSDev))
809{
810bvCount = 0;
811scanBootVolumes(gBIOSDev, &bvCount);
812}
813}
814
815//==========================================================================
816
817BVRef selectBootVolume( BVRef chain )
818{
819bool filteredChain = false;
820bool foundPrimary = false;
821BVRef bvr, bvr1 = 0, bvr2 = 0;
822
823if (chain->filtered) filteredChain = true;
824
825int gBIOSDev = (int)get_env(envgBIOSDev);
826
827#if UNUSED
828if (multiboot_partition_set)
829for (bvr = chain; bvr < (BVRef)ULONG_MAX; bvr = bvr->next) {
830 if (!bvr) {
831 break;
832 }
833if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
834return bvr;
835 }
836#endif
837/*
838 * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
839 * to override the default selection.
840 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
841 */
842char *val = XMLDecode(getStringForKey(kDefaultPartition, DEFAULT_BOOT_CONFIG));
843 if (val) {
844 for (bvr = chain; bvr < (BVRef)ULONG_MAX; bvr = bvr->next)
845 {
846 if (!bvr) {
847 break;
848 }
849 if (matchVolumeToString(bvr, val, false)) {
850 free(val);
851 return bvr;
852 }
853 }
854 free(val);
855 }
856
857/*
858 * Scannig the volume chain backwards and trying to find
859 * a HFS+ volume with valid boot record signature.
860 * If not found any active partition then we will
861 * select this volume as the boot volume.
862 */
863
864{
865 for (bvr = chain; bvr < (BVRef)ULONG_MAX; bvr = bvr->next)
866 {
867 if (!bvr) {
868 break;
869 }
870#if UNUSED
871if (multiboot_skip_partition_set) {
872if (bvr->part_no == multiboot_skip_partition) continue;
873}
874#endif
875if ( (bvr->flags & kBVFlagPrimary) && (bvr->biosdev == gBIOSDev) ) foundPrimary = true;
876// zhell -- Undo a regression that was introduced from r491 to 492.
877// if gBIOSBootVolume is set already, no change is required
878if ( (bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume))
879&& get_env(envgBIOSBootVolume)
880&& (!filteredChain || (filteredChain && bvr->visible))
881&& (bvr->biosdev == gBIOSDev) )
882{
883bvr2 = bvr;
884}
885
886// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
887// from r491,
888if ( bvr->flags & kBVFlagBootable
889&& !get_env(envgBIOSBootVolume)/*gBIOSBootVolume*/
890&& bvr->biosdev == gBIOSDev )
891{
892bvr2 = bvr;
893}
894 }
895}
896
897/*
898 * Use the standrad method for selecting the boot volume.
899 */
900if (foundPrimary)
901{
902for (bvr = chain; bvr < (BVRef)ULONG_MAX; bvr = bvr->next)
903 {
904 if (!bvr) {
905 break;
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 ')'
922
923/*!
924 This is like boot2's gBootVolume except it is for the internal use of
925 libsaio to track which volume an unqualified path should be relative to.
926 This replaces bootInfo->kernDev as the carrier of this information.
927 */
928static BVRef gRootVolume;
929
930void setRootVolume(BVRef volume)
931{
932 gRootVolume = volume;
933 // Veto non-native FS. Basically that means don't allow the root volume to
934 // be set to a volume we can't read files from.
935 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
936 gRootVolume = NULL;
937}
938
939void setBootGlobals(BVRef chain)
940{
941// Record default boot device.
942BVRef gBootVolume = selectBootVolume(chain);
943
944// turbo - Save the ORIGINAL boot volume too for loading our mkext
945if (!get_env(envgBIOSBootVolume)) safe_set_env(envgBIOSBootVolume, (uint32_t)gBootVolume);
946
947safe_set_env(envgBootVolume, (uint32_t)gBootVolume);
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 = (int)get_env(envgBIOSDev);
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 int 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 = (BVRef)(uint32_t)get_env(envgBIOSBootVolume);
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: 2006