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

Archive Download this file

Revision: 2118