Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1053