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, long strMaxLen)
228{
229 unsigned fmtbase, fmtidx, i;
230 uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 };
231 char *p = uuidStr;
232 char *end = p + strMaxLen;
233 MD5_CTX md5c;
234 uint8_t mdresult[16];
235
236 bzero(mdresult, sizeof(mdresult));
237
238 // just like AppleFileSystemDriver
239 MD5Init(&md5c);
240 MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1));
241 MD5Update(&md5c, uubytes, nbytes);
242 MD5Final(mdresult, &md5c);
243
244 // this UUID has been made version 3 style (i.e. via namespace)
245 // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte)
246 mdresult[6] = 0x30 | ( mdresult[6] & 0x0F );
247 mdresult[8] = 0x80 | ( mdresult[8] & 0x3F );
248
249
250 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
251 fmtbase = 0;
252 for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) {
253 for(i=0; i < uuidfmt[fmtidx]; i++) {
254 if (p > end)
255 {
256 break;
257 }
258 else if (p == end)
259 {
260 break;
261 *p = '\0';
262 }
263 uint8_t byte = mdresult[fmtbase+i];
264 char nib;
265
266 nib = byte >> 4;
267 *p = nib + '0'; // 0x4 -> '4'
268 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
269 p++;
270
271 nib = byte & 0xf;
272 *p = nib + '0'; // 0x4 -> '4'
273 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
274 p++;
275
276 }
277 fmtbase += i;
278 if(fmtidx < sizeof(uuidfmt)-1)
279 *(p++) = '-';
280 else
281 *p = '\0';
282 }
283
284 return 0;
285}
286
287
288//==========================================================================
289// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
290// Fetch the next directory entry for the given directory.
291
292long GetDirEntry(const char * dirSpec, long long * dirIndex, const char ** name,
293 long * flags, long * time)
294{
295 const char * dirPath;
296 BVRef bvr;
297
298 // Resolve the boot volume from the dir spec.
299
300 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
301 return -1;
302
303 // Return 0 on success, or -1 if there are no additional entries.
304
305 return bvr->fs_getdirentry( bvr,
306 /* dirPath */ (char *)dirPath,
307 /* dirIndex */ dirIndex,
308 /* dirEntry */ (char **)name, flags, time, 0, 0 );
309}
310
311//==========================================================================
312// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
313// Get attributes for the specified file.
314
315static char* gMakeDirSpec;
316
317long GetFileInfo(const char * dirSpec, const char * name,
318 long * flags, long * time)
319{
320 long long index = 0;
321 const char * entryName;
322
323 if (gMakeDirSpec == 0)
324 gMakeDirSpec = (char *)malloc(1024);
325
326if (!gMakeDirSpec) return -1;
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
377struct 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
391static int open_bvr(BVRef bvr, const char *filePath)
392{
393struct iob*io;
394intfdesc;
395inti;
396
397if (bvr == NULL) {
398return -1;
399}
400
401fdesc = GetFreeFd();
402io = &iob[fdesc];
403bzero(io, sizeof(*io));
404
405// Mark the descriptor as taken.
406io->i_flgs = F_ALLOC;
407
408// Find the next available memory block in the download buffer.
409io->i_buf = (char *) LOAD_ADDR;
410for (i = 0; i < NFILES; i++) {
411if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) {
412continue;
413}
414io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
415}
416
417// Load entire file into memory. Unnecessary open() calls must be avoided.
418//gFSLoadAddress = io->i_buf;
419safe_set_env(envgFSLoadAddress, (uint32_t)(void *)io->i_buf);
420
421io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
422if (io->i_filesize < 0) {
423close(fdesc);
424return -1;
425}
426return fdesc;
427}
428
429
430int open(const char *path)
431{
432const char*filepath;
433BVRefbvr;
434
435// Resolve the boot volume from the file spec.
436if ((bvr = getBootVolumeRef(path, &filepath)) != NULL) {
437
438 return open_bvr(bvr, filepath);
439}
440return -1;
441}
442
443
444int open_bvdev(const char *bvd, const char *path)
445{
446const struct devsw*dp;
447const char*cp;
448BVRefbvr;
449inti;
450intlen;
451intunit;
452intpartition;
453
454if ((i = open(path)) >= 0) {
455return i;
456}
457
458if (bvd == NULL || (len = strlen(bvd)) < 2) {
459return -1;
460}
461
462for (dp=devsw; dp->name; dp++) {
463if (bvd[0] == dp->name[0] && bvd[1] == dp->name[1]) {
464unit = 0;
465partition = 0;
466/* get optional unit and partition */
467if (len >= 5 && bvd[2] == '(') { /* min must be present xx(0) */
468cp = &bvd[3];
469i = 0;
470while ((cp - path) < len && isdigit(*cp)) {
471i = i * 10 + *cp++ - '0';
472unit = i;
473}
474if (*cp++ == ',') {
475i = 0;
476while ((cp - path) < len && isdigit(*cp)) {
477i = i * 10 + *cp++ - '0';
478partition = i;
479}
480}
481}
482bvr = newBootVolumeRef(dp->biosdev + unit, partition);
483
484 return open_bvr(bvr, path);
485}
486}
487return -1;
488}
489
490//==========================================================================
491// close() - Close a file descriptor.
492
493int close(int fdesc)
494{
495 struct iob * io;
496
497 if ((io = iob_from_fdesc(fdesc)) == NULL)
498 return (-1);
499
500 io->i_flgs = 0;
501
502 return 0;
503}
504
505//==========================================================================
506// read() - Read up to 'count' bytes of data from the file descriptor
507// into the buffer pointed to by buf.
508
509int read(int fdesc, char * buf, int count)
510{
511 struct iob * io;
512
513 if ((io = iob_from_fdesc(fdesc)) == NULL)
514 return (-1);
515
516 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
517 count = io->i_filesize - io->i_offset;
518
519 if (count <= 0)
520 return 0; // end of file
521
522 bcopy(io->i_buf + io->i_offset, buf, count);
523
524 io->i_offset += count;
525
526 return count;
527}
528
529//==========================================================================
530// file_size() - Returns the size of the file described by the file
531// descriptor.
532
533int file_size(int fdesc)
534{
535 struct iob * io;
536
537 if ((io = iob_from_fdesc(fdesc)) == 0)
538 return 0;
539
540 return io->i_filesize;
541}
542
543#if UNUSED
544//==========================================================================
545
546struct dirstuff * opendir(const char * path)
547{
548 struct dirstuff * dirp = 0;
549 const char * dirPath;
550 BVRef bvr;
551
552 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
553 goto error;
554
555 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
556 if (dirp == NULL)
557 goto error;
558
559 dirp->dir_path = newString(dirPath);
560 if (dirp->dir_path == NULL)
561 goto error;
562
563 dirp->dir_bvr = bvr;
564
565 return dirp;
566
567error:
568 closedir(dirp);
569 return NULL;
570}
571
572//==========================================================================
573
574int closedir(struct dirstuff * dirp)
575{
576 if (dirp) {
577 if (dirp->dir_path) free(dirp->dir_path);
578 free(dirp);
579 }
580 return 0;
581}
582
583//==========================================================================
584
585int readdir(struct dirstuff * dirp, const char ** name, long * flags,
586 long * time)
587{
588 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
589 /* dirPath */ dirp->dir_path,
590 /* dirIndex */ &dirp->dir_index,
591 /* dirEntry */ (char **)name, flags, time,
592 0, 0);
593}
594
595long GetFSUUID(char *spec, char *uuidStr, long strMaxLen)
596{
597 BVRef bvr;
598 long rval = -1;
599 const char *devSpec;
600
601 if ((bvr = getBootVolumeRef(spec, &devSpec)) == NULL)
602 return -1;
603
604 if(bvr->fs_getuuid)
605 rval = bvr->fs_getuuid(bvr, uuidStr, strMaxLen);
606
607 return rval;
608}
609
610long GetFileBlock(const char *fileSpec, unsigned long long *firstBlock)
611{
612 const char * filePath;
613 BVRef bvr;
614
615 // Resolve the boot volume from the file spec.
616
617 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) {
618 printf("Boot volume for '%s' is bogus\n", fileSpec);
619 return -1;
620 }
621
622 return bvr->fs_getfileblock(bvr, (char *)filePath, firstBlock);
623}
624
625//==========================================================================
626// openmem()
627
628int openmem(char * buf, int len)
629{
630 int fdesc;
631 struct iob * io;
632
633 fdesc = GetFreeFd();
634 io = &iob[fdesc];
635 bzero(io, sizeof(*io));
636
637 // Mark the descriptor as taken. Set the F_MEM flag to indicate
638 // that the file buffer is provided by the caller.
639
640 io->i_flgs = F_ALLOC | F_MEM;
641 io->i_buf = buf;
642 io->i_filesize = len;
643
644 return fdesc;
645}
646
647//==========================================================================
648// lseek() - Reposition the byte offset of the file descriptor from the
649// beginning of the file. Returns the relocated offset.
650
651int b_lseek(int fdesc, int offset, int ptr)
652{
653 struct iob * io;
654
655 if ((io = iob_from_fdesc(fdesc)) == NULL)
656 return (-1);
657
658 io->i_offset = offset;
659
660 return offset;
661}
662
663//==========================================================================
664// tell() - Returns the byte offset of the file descriptor.
665
666int tell(int fdesc)
667{
668 struct iob * io;
669
670 if ((io = iob_from_fdesc(fdesc)) == NULL)
671 return 0;
672
673 return io->i_offset;
674}
675#endif
676//==========================================================================
677// write() - Write up to 'count' bytes of data to the file descriptor
678// from the buffer pointed to by buf.
679
680int write(int fdesc, const char * buf, int count)
681{
682 struct iob * io;
683
684 if ((io = iob_from_fdesc(fdesc)) == NULL)
685 return (-1);
686
687 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
688 count = io->i_filesize - io->i_offset;
689
690 if (count <= 0)
691 return 0; // end of file
692
693 bcopy(buf, io->i_buf + io->i_offset, count);
694
695 io->i_offset += count;
696
697 return count;
698}
699#if UNUSED
700int writebyte(int fdesc, char value)
701{
702 struct iob * io;
703
704 if ((io = iob_from_fdesc(fdesc)) == NULL)
705 return (-1);
706
707 if ((io->i_offset + 1) > (unsigned int)io->i_filesize)
708 return 0; // end of file
709
710 io->i_buf[io->i_offset++] = value;
711
712 return 1;
713}
714
715int writeint(int fdesc, int value)
716{
717 struct iob * io;
718
719 if ((io = iob_from_fdesc(fdesc)) == NULL)
720 return (-1);
721
722 if ((io->i_offset + 4) > (unsigned int)io->i_filesize)
723 return 0; // end of file
724
725 bcopy(&value, io->i_buf + io->i_offset, 4);
726
727 io->i_offset += 4;
728
729 return 4;
730}
731//==========================================================================
732
733struct dirstuff * vol_opendir(BVRef bvr, const char * path)
734{
735 struct dirstuff * dirp = 0;
736
737 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
738 if (dirp == NULL)
739 goto error;
740
741 dirp->dir_path = newString(path);
742 if (dirp->dir_path == NULL)
743 goto error;
744
745 dirp->dir_bvr = bvr;
746
747 return dirp;
748
749error:
750 closedir(dirp);
751 return NULL;
752}
753
754//==========================================================================
755
756int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
757long * time, FinderInfo *finderInfo, long *infoValid)
758{
759 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
760 /* dirPath */ dirp->dir_path,
761 /* dirIndex */ &dirp->dir_index,
762 /* dirEntry */ (char **)name,
763 flags, time,
764 finderInfo, infoValid);
765}
766//==========================================================================
767
768const char * systemConfigDir()
769{
770 if (get_env(envgBootFileType) == kNetworkDeviceType)
771return "";
772 return "/Library/Preferences/SystemConfiguration";
773}
774
775#endif
776
777//==========================================================================
778
779void scanBootVolumes( int biosdev, int * count )
780{
781BVRef bvr = 0;
782
783bvr = diskScanBootVolumes(biosdev, count);
784if (bvr == NULL)
785{
786#ifdef NBP_SUPPORT
787bvr = nbpScanBootVolumes(biosdev, count);
788if (bvr != NULL)
789{
790safe_set_env(envgBootFileType, kNetworkDeviceType);
791}
792#endif
793}
794else
795{
796safe_set_env(envgBootFileType, kBlockDeviceType);
797
798}
799}
800
801//==========================================================================
802
803void scanDisks(void)
804{
805#define MAX_HDD_COUNT 32
806int bvCount;
807int hd = 0;
808
809// Testing up to MAX_HDD_COUNT hard drives.
810while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
811{
812bvCount = 0;
813scanBootVolumes(0x80 + hd, &bvCount);
814hd++;
815}
816int gBIOSDev = (int)get_env(envgBIOSDev);
817// Also scanning CD/DVD drive.
818if (biosDevIsCDROM(gBIOSDev))
819{
820bvCount = 0;
821scanBootVolumes(gBIOSDev, &bvCount);
822}
823}
824
825//==========================================================================
826
827BVRef selectBootVolume( BVRef chain )
828{
829bool filteredChain = false;
830bool foundPrimary = false;
831BVRef bvr, bvr1 = 0, bvr2 = 0;
832
833if (chain->filtered) filteredChain = true;
834
835int gBIOSDev = (int)get_env(envgBIOSDev);
836
837#if UNUSED
838if (multiboot_partition_set)
839for (bvr = chain; bvr < (BVRef)ULONG_MAX; bvr = bvr->next) {
840 if (!bvr) {
841 break;
842 }
843if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
844return bvr;
845 }
846#endif
847/*
848 * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
849 * to override the default selection.
850 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
851 */
852char *val = XMLDecode(getStringForKey(kDefaultPartition, DEFAULT_BOOT_CONFIG));
853 if (val) {
854 for (bvr = chain; bvr < (BVRef)ULONG_MAX; bvr = bvr->next)
855 {
856 if (!bvr) {
857 break;
858 }
859 if (matchVolumeToString(bvr, val, false)) {
860 free(val);
861 return bvr;
862 }
863 }
864 free(val);
865 }
866
867/*
868 * Scannig the volume chain backwards and trying to find
869 * a HFS+ volume with valid boot record signature.
870 * If not found any active partition then we will
871 * select this volume as the boot volume.
872 */
873
874{
875 for (bvr = chain; bvr < (BVRef)ULONG_MAX; bvr = bvr->next)
876 {
877 if (!bvr) {
878 break;
879 }
880#if UNUSED
881if (multiboot_skip_partition_set) {
882if (bvr->part_no == multiboot_skip_partition) continue;
883}
884#endif
885if ( (bvr->flags & kBVFlagPrimary) && (bvr->biosdev == gBIOSDev) ) foundPrimary = true;
886// zhell -- Undo a regression that was introduced from r491 to 492.
887// if gBIOSBootVolume is set already, no change is required
888if ( (bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume))
889&& get_env(envgBIOSBootVolume)
890&& (!filteredChain || (filteredChain && bvr->visible))
891&& (bvr->biosdev == gBIOSDev) )
892{
893bvr2 = bvr;
894}
895
896// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
897// from r491,
898if ( bvr->flags & kBVFlagBootable
899&& !get_env(envgBIOSBootVolume)/*gBIOSBootVolume*/
900&& bvr->biosdev == gBIOSDev )
901{
902bvr2 = bvr;
903}
904 }
905}
906
907/*
908 * Use the standrad method for selecting the boot volume.
909 */
910if (foundPrimary)
911{
912for (bvr = chain; bvr < (BVRef)ULONG_MAX; bvr = bvr->next)
913 {
914 if (!bvr) {
915 break;
916 }
917if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
918if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
919}
920}
921
922bvr = bvr2 ? bvr2 :
923bvr1 ? bvr1 : chain;
924
925return bvr;
926}
927
928//==========================================================================
929
930#define LP '('
931#define RP ')'
932
933/*!
934 This is like boot2's gBootVolume except it is for the internal use of
935 libsaio to track which volume an unqualified path should be relative to.
936 This replaces bootInfo->kernDev as the carrier of this information.
937 */
938static BVRef gRootVolume;
939
940void setRootVolume(BVRef volume)
941{
942 gRootVolume = volume;
943 // Veto non-native FS. Basically that means don't allow the root volume to
944 // be set to a volume we can't read files from.
945 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
946 gRootVolume = NULL;
947}
948
949void setBootGlobals(BVRef chain)
950{
951// Record default boot device.
952BVRef gBootVolume = selectBootVolume(chain);
953
954// turbo - Save the ORIGINAL boot volume too for loading our mkext
955if (!get_env(envgBIOSBootVolume)) safe_set_env(envgBIOSBootVolume, (uint32_t)gBootVolume);
956
957safe_set_env(envgBootVolume, (uint32_t)gBootVolume);
958setRootVolume(gBootVolume);
959}
960
961/*!
962 Extracts the volume selector from the pathname, returns the selected
963 BVRef, and sets *outPath to the remainder of the path.
964 If the path did not include a volume selector then the current volume
965 is used. When called with a volume selector the current volume
966 is changed to the selected volume unless the volume selector is
967 that of a ramdisk.
968 */
969BVRef getBootVolumeRef( const char * path, const char ** outPath )
970{
971 const char * cp;
972 BVRef bvr = gRootVolume;
973 //int biosdev = (int)get_env(envgBIOSDev);
974
975 // Search for left parenthesis in the path specification.
976
977 for (cp = path; *cp; cp++) {
978 if (*cp == LP || *cp == '/') break;
979 }
980
981 if (*cp != LP) // no left paren found
982 {
983 // Path is using the implicit current device so if there is
984 // no current device, then we must fail.
985 cp = path;
986 if ( gRootVolume == NULL )
987 return NULL;
988 }
989 else if ((cp - path) == 2) // found "xx("
990 {
991 const struct devsw * dp;
992 const char * xp = path;
993 int i;
994 int unit = -1;
995 int part = -1;
996
997 cp++;
998
999 // Check the 2 character device name pointed by 'xp'.
1000
1001 for (dp = devsw; dp->name; dp++)
1002 {
1003 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
1004 break; // found matching entry
1005 }
1006 if (dp->name == NULL)
1007 {
1008 error("Unknown device '%c%c'\n", xp[0], xp[1]);
1009 return NULL;
1010 }
1011
1012 // Extract the optional unit number from the specification.
1013 // hd(unit) or hd(unit, part).
1014
1015 i = 0;
1016 while (*cp >= '0' && *cp <= '9')
1017 {
1018 i = i * 10 + *cp++ - '0';
1019 unit = i;
1020 }
1021
1022 // Unit is no longer optional and never really was.
1023 // If the user failed to specify it then the unit number from the previous kernDev
1024 // would have been used which makes little sense anyway.
1025 // For example, if the user did fd()/foobar and the current root device was the
1026 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
1027 if(unit == -1)
1028 return NULL;
1029
1030 // Extract the optional partition number from the specification.
1031
1032 if (*cp == ',')
1033 part = atoi(++cp);
1034
1035 // If part is not specified part will be -1 whereas before it would have been
1036 // whatever the last partition was which makes about zero sense if the device
1037 // has been switched.
1038
1039 // Skip past the right paren.
1040
1041 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
1042 if (*cp == RP) cp++;
1043
1044 int biosdev = dp->biosdev + unit;
1045 bvr = newBootVolumeRef(biosdev, part);
1046
1047 if(bvr == NULL)
1048 return NULL;
1049 }
1050 else
1051 {
1052 // Bad device specifier, skip past the right paren.
1053
1054 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
1055 if (*cp == RP) cp++;
1056 // If gRootVolume was NULL, then bvr will be NULL as well which
1057 // should be caught by the caller.
1058 }
1059
1060 // Returns the file path following the device spec.
1061 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1062
1063 *outPath = cp;
1064
1065 return bvr;
1066}
1067
1068//==========================================================================
1069// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1070// which caches the information. So it's only allocated on the first run.
1071static BVRef newBootVolumeRef( int biosdev, int partno )
1072{
1073BVRef bvr, bvr1, bvrChain;
1074
1075bvr = bvr1 = NULL;
1076
1077 // Try resolving "rd" and "bt" devices first.
1078execute_hook("newRamDisk_BVR", &biosdev, &bvr1, NULL, NULL, NULL, NULL);
1079
1080 // Try resolving "rd" and "bt" devices first.
1081
1082if (biosdev == kPseudoBIOSDevBooter)
1083{
1084if (bvr1 == NULL )
1085bvr1 = (BVRef)(uint32_t)get_env(envgBIOSBootVolume);
1086}
1087else
1088{
1089// Fetch the volume list from the device.
1090
1091scanBootVolumes( biosdev, NULL );
1092bvrChain = getBVChainForBIOSDev(biosdev);
1093
1094// Look for a perfect match based on device and partition number.
1095
1096for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1097{
1098if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1099
1100bvr1 = bvr;
1101if ( bvr->part_no == partno ) break;
1102}
1103}
1104
1105return bvr ? bvr : bvr1;
1106}
1107
1108//==========================================================================
1109// getDeviceDescription() - Extracts unit number and partition number
1110// from bvr structure into "dw(u,p)" format.
1111// Returns length of the out string
1112int getDeviceDescription(BVRef bvr, char *str, long strMaxLen)
1113{
1114 if(!str)
1115 return 0;
1116
1117*str = '\0';
1118
1119if (bvr)
1120{
1121 const struct devsw *dp = devsw;
1122while(dp->name && bvr->biosdev >= dp->biosdev)
1123 dp++;
1124
1125dp--;
1126if (dp->name)
1127 return snprintf(str, strMaxLen, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1128}
1129
1130return 0;
1131}
1132

Archive Download this file

Revision: 2044