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 if(name[idx] == '/' || name[idx] == '\\') ++name; // todo: ensure other functions handel \ properly
339 gMakeDirSpec[0] = '/';
340 gMakeDirSpec[1] = '\0';
341 } else {
342 idx++;
343 strncpy(gMakeDirSpec, name, idx);
344 name += idx;
345 }
346 dirSpec = gMakeDirSpec;
347 }
348
349 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
350 {
351 if (strcmp(entryName, name) == 0)
352 return 0; // success
353 }
354 return -1; // file not found
355}
356
357long GetFileBlock(const char *fileSpec, unsigned long long *firstBlock)
358{
359 const char * filePath;
360 BVRef bvr;
361
362 // Resolve the boot volume from the file spec.
363
364 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) {
365 printf("Boot volume for '%s' is bogus\n", fileSpec);
366 return -1;
367 }
368
369 return bvr->fs_getfileblock(bvr, (char *)filePath, firstBlock);
370}
371
372//==========================================================================
373// GetFreeFD()
374
375static int GetFreeFd(void)
376{
377intfd;
378
379// Locate a free descriptor slot.
380for (fd = 0; fd < NFILES; fd++) {
381if (iob[fd].i_flgs == 0) {
382return fd;
383 }
384}
385stop("Out of file descriptors");
386// not reached
387return -1;
388}
389
390//==========================================================================
391// iob_from_fdesc()
392//
393// Return a pointer to an allocated 'iob' based on the file descriptor
394// provided. Returns NULL if the file descriptor given is invalid.
395
396static struct iob * iob_from_fdesc(int fdesc)
397{
398 register struct iob * io;
399
400 if (fdesc < 0 || fdesc >= NFILES ||
401 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
402 return NULL;
403 else
404 return io;
405}
406
407//==========================================================================
408// openmem()
409
410int openmem(char * buf, int len)
411{
412 int fdesc;
413 struct iob * io;
414
415 fdesc = GetFreeFd();
416 io = &iob[fdesc];
417 bzero(io, sizeof(*io));
418
419 // Mark the descriptor as taken. Set the F_MEM flag to indicate
420 // that the file buffer is provided by the caller.
421
422 io->i_flgs = F_ALLOC | F_MEM;
423 io->i_buf = buf;
424 io->i_filesize = len;
425
426 return fdesc;
427}
428
429//==========================================================================
430// open() - Open the file specified by 'path' for reading.
431
432static int open_bvr(BVRef bvr, const char *filePath, int flags)
433{
434struct iob*io;
435intfdesc;
436inti;
437
438if (bvr == NULL) {
439return -1;
440}
441
442fdesc = GetFreeFd();
443io = &iob[fdesc];
444bzero(io, sizeof(*io));
445
446// Mark the descriptor as taken.
447io->i_flgs = F_ALLOC;
448
449// Find the next available memory block in the download buffer.
450io->i_buf = (char *) LOAD_ADDR;
451for (i = 0; i < NFILES; i++) {
452if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) {
453continue;
454}
455io->i_buf = MAX(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
456}
457
458// Load entire file into memory. Unnecessary open() calls must be avoided.
459gFSLoadAddress = io->i_buf;
460io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
461if (io->i_filesize < 0) {
462close(fdesc);
463return -1;
464}
465return fdesc;
466}
467
468int open(const char *path, int flags)
469{
470const char*filepath;
471BVRefbvr;
472
473// Resolve the boot volume from the file spec.
474if ((bvr = getBootVolumeRef(path, &filepath)) != NULL) {
475return open_bvr(bvr, filepath, flags);
476}
477return -1;
478}
479
480int open_bvdev(const char *bvd, const char *path, int flags)
481{
482 const struct devsw*dp;
483const char*cp;
484BVRefbvr;
485inti;
486intlen;
487intunit;
488intpartition;
489
490if ((i = open(path, flags)) >= 0) {
491return i;
492}
493
494if (bvd == NULL || (len = strlen(bvd)) < 2) {
495return -1;
496}
497
498for (dp=devsw; dp->name; dp++) {
499if (bvd[0] == dp->name[0] && bvd[1] == dp->name[1]) {
500unit = 0;
501partition = 0;
502/* get optional unit and partition */
503if (len >= 5 && bvd[2] == '(') { /* min must be present xx(0) */
504cp = &bvd[3];
505i = 0;
506while ((cp - path) < len && isdigit(*cp)) {
507i = i * 10 + *cp++ - '0';
508unit = i;
509}
510if (*cp++ == ',') {
511i = 0;
512while ((cp - path) < len && isdigit(*cp)) {
513i = i * 10 + *cp++ - '0';
514partition = i;
515}
516}
517}
518bvr = newBootVolumeRef(dp->biosdev + unit, partition);
519return open_bvr(bvr, path, flags);
520}
521 }
522return -1;
523}
524
525//==========================================================================
526// close() - Close a file descriptor.
527
528int close(int fdesc)
529{
530 struct iob * io;
531
532 if ((io = iob_from_fdesc(fdesc)) == NULL)
533 return (-1);
534
535 io->i_flgs = 0;
536
537 return 0;
538}
539
540//==========================================================================
541// lseek() - Reposition the byte offset of the file descriptor from the
542// beginning of the file. Returns the relocated offset.
543
544int b_lseek(int fdesc, int offset, int ptr)
545{
546 struct iob * io;
547
548 if ((io = iob_from_fdesc(fdesc)) == NULL)
549 return (-1);
550
551 io->i_offset = offset;
552
553 return offset;
554}
555
556//==========================================================================
557// tell() - Returns the byte offset of the file descriptor.
558
559int tell(int fdesc)
560{
561 struct iob * io;
562
563 if ((io = iob_from_fdesc(fdesc)) == NULL)
564 return 0;
565
566 return io->i_offset;
567}
568
569//==========================================================================
570// read() - Read up to 'count' bytes of data from the file descriptor
571// into the buffer pointed to by buf.
572
573int read(int fdesc, char * buf, int count)
574{
575 struct iob * io;
576
577 if ((io = iob_from_fdesc(fdesc)) == NULL)
578 return (-1);
579
580 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
581 count = io->i_filesize - io->i_offset;
582
583 if (count <= 0)
584 return 0; // end of file
585
586 bcopy(io->i_buf + io->i_offset, buf, count);
587
588 io->i_offset += count;
589
590 return count;
591}
592
593//==========================================================================
594// write() - Write up to 'count' bytes of data to the file descriptor
595// from the buffer pointed to by buf.
596
597int write(int fdesc, const char * buf, int count)
598{
599 struct iob * io;
600
601 if ((io = iob_from_fdesc(fdesc)) == NULL)
602 return (-1);
603
604 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
605 count = io->i_filesize - io->i_offset;
606
607 if (count <= 0)
608 return 0; // end of file
609
610 bcopy(buf, io->i_buf + io->i_offset, count);
611
612 io->i_offset += count;
613
614 return count;
615}
616
617int writebyte(int fdesc, char value)
618{
619 struct iob * io;
620
621 if ((io = iob_from_fdesc(fdesc)) == NULL)
622 return (-1);
623
624 if ((io->i_offset + 1) > (unsigned int)io->i_filesize)
625 return 0; // end of file
626
627 io->i_buf[io->i_offset++] = value;
628
629 return 1;
630}
631
632int writeint(int fdesc, int value)
633{
634 struct iob * io;
635
636 if ((io = iob_from_fdesc(fdesc)) == NULL)
637 return (-1);
638
639 if ((io->i_offset + 4) > (unsigned int)io->i_filesize)
640 return 0; // end of file
641
642 bcopy(&value, io->i_buf + io->i_offset, 4);
643
644 io->i_offset += 4;
645
646 return 4;
647}
648
649//==========================================================================
650// file_size() - Returns the size of the file described by the file
651// descriptor.
652
653int file_size(int fdesc)
654{
655 struct iob * io;
656
657 if ((io = iob_from_fdesc(fdesc)) == 0)
658 return 0;
659
660 return io->i_filesize;
661}
662
663//==========================================================================
664
665struct dirstuff * vol_opendir(BVRef bvr, const char * path)
666{
667 struct dirstuff * dirp = 0;
668
669 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
670 if (dirp == NULL)
671 goto error;
672
673 dirp->dir_path = newString(path);
674 if (dirp->dir_path == NULL)
675 goto error;
676
677 dirp->dir_bvr = bvr;
678
679 return dirp;
680
681error:
682 closedir(dirp);
683 return NULL;
684}
685
686//==========================================================================
687
688struct dirstuff * opendir(const char * path)
689{
690 struct dirstuff * dirp = 0;
691 const char * dirPath;
692 BVRef bvr;
693
694 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
695 goto error;
696
697 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
698 if (dirp == NULL)
699 goto error;
700
701 dirp->dir_path = newString(dirPath);
702 if (dirp->dir_path == NULL)
703 goto error;
704
705 dirp->dir_bvr = bvr;
706
707 return dirp;
708
709error:
710 closedir(dirp);
711 return NULL;
712}
713
714//==========================================================================
715
716int closedir(struct dirstuff * dirp)
717{
718 if (dirp) {
719 if (dirp->dir_path) free(dirp->dir_path);
720 free(dirp);
721 }
722 return 0;
723}
724
725//==========================================================================
726
727int readdir(struct dirstuff * dirp, const char ** name, long * flags,
728 long * time)
729{
730 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
731 /* dirPath */ dirp->dir_path,
732 /* dirIndex */ &dirp->dir_index,
733 /* dirEntry */ (char **)name, flags, time,
734 0, 0);
735}
736
737//==========================================================================
738
739int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
740 long * time, FinderInfo *finderInfo, long *infoValid)
741{
742 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
743 /* dirPath */ dirp->dir_path,
744 /* dirIndex */ &dirp->dir_index,
745 /* dirEntry */ (char **)name,
746 flags, time,
747 finderInfo, infoValid);
748}
749
750//==========================================================================
751
752const char * systemConfigDir()
753{
754 if (gBootFileType == kNetworkDeviceType)
755return "";
756 return "/Library/Preferences/SystemConfiguration";
757}
758
759//==========================================================================
760
761int gBootFileType;
762
763void scanBootVolumes( int biosdev, int * count )
764{
765 BVRef bvr = 0;
766
767 bvr = diskScanBootVolumes(biosdev, count);
768 if (bvr == NULL)
769 {
770 bvr = nbpScanBootVolumes(biosdev, count);
771 if (bvr != NULL)
772 {
773 gBootFileType = kNetworkDeviceType;
774 }
775 }
776 else
777 {
778 gBootFileType = kBlockDeviceType;
779 }
780}
781
782//==========================================================================
783
784void scanDisks(int biosdev, int *count)
785{
786 #define MAX_HDD_COUNT 32
787 int bvCount;
788 int hd = 0;
789
790 // Testing up to MAX_HDD_COUNT hard drives.
791while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
792{
793 bvCount = 0;
794 scanBootVolumes(0x80 + hd, &bvCount);
795 hd++;
796}
797
798 // Also scanning CD/DVD drive.
799if (biosDevIsCDROM(gBIOSDev))
800{
801 bvCount = 0;
802 scanBootVolumes(gBIOSDev, &bvCount);
803}
804}
805
806//==========================================================================
807
808BVRef selectBootVolume( BVRef chain )
809{
810bool filteredChain = false;
811bool foundPrimary = false;
812BVRef bvr, bvr1 = 0, bvr2 = 0;
813
814if (chain->filtered) filteredChain = true;
815
816if (multiboot_partition_set)
817for ( bvr = chain; bvr; bvr = bvr->next )
818if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
819return bvr;
820
821/*
822 * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
823 * to override the default selection.
824 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
825 */
826char *val = XMLDecode(getStringForKey(kDefaultPartition, &bootInfo->chameleonConfig));
827 if (val) {
828 for ( bvr = chain; bvr; bvr = bvr->next ) {
829 if (matchVolumeToString(bvr, val, false)) {
830 free(val);
831 return bvr;
832 }
833 }
834 free(val);
835 }
836
837/*
838 * Scannig the volume chain backwards and trying to find
839 * a HFS+ volume with valid boot record signature.
840 * If not found any active partition then we will
841 * select this volume as the boot volume.
842 */
843for ( bvr = chain; bvr; bvr = bvr->next )
844{
845if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = true;
846// zhell -- Undo a regression that was introduced from r491 to 492.
847// if gBIOSBootVolume is set already, no change is required
848if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
849&& gBIOSBootVolume
850&& (!filteredChain || (filteredChain && bvr->visible))
851&& bvr->biosdev == gBIOSDev )
852bvr2 = bvr;
853// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
854// from r491,
855if ( bvr->flags & kBVFlagBootable
856&& ! gBIOSBootVolume
857&& bvr->biosdev == gBIOSDev )
858bvr2 = bvr;
859}
860
861
862/*
863 * Use the standrad method for selecting the boot volume.
864 */
865if (foundPrimary)
866{
867for ( bvr = chain; bvr; bvr = bvr->next )
868{
869if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
870if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
871}
872}
873
874bvr = bvr2 ? bvr2 :
875bvr1 ? bvr1 : chain;
876
877return bvr;
878}
879
880//==========================================================================
881
882#define LP '('
883#define RP ')'
884int gBIOSDev;
885
886/*!
887 This is like boot2's gBootVolume except it is for the internal use of
888 libsaio to track which volume an unqualified path should be relative to.
889 This replaces bootInfo->kernDev as the carrier of this information.
890 */
891static BVRef gRootVolume;
892
893void setRootVolume(BVRef volume)
894{
895 gRootVolume = volume;
896 // Veto non-native FS. Basically that means don't allow the root volume to
897 // be set to a volume we can't read files from.
898 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
899 gRootVolume = NULL;
900}
901
902void setBootGlobals(BVRef chain)
903{
904 // Record default boot device.
905 gBootVolume = selectBootVolume(chain);
906
907 // turbo - Save the ORIGINAL boot volume too for loading our mkext
908 if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
909
910 setRootVolume(gBootVolume);
911}
912
913/*!
914 Extracts the volume selector from the pathname, returns the selected
915 BVRef, and sets *outPath to the remainder of the path.
916 If the path did not include a volume selector then the current volume
917 is used. When called with a volume selector the current volume
918 is changed to the selected volume unless the volume selector is
919 that of a ramdisk.
920 */
921BVRef getBootVolumeRef( const char * path, const char ** outPath )
922{
923 const char * cp;
924 BVRef bvr = gRootVolume;
925 int biosdev = gBIOSDev;
926
927 // Search for left parenthesis in the path specification.
928
929 for (cp = path; *cp; cp++) {
930 if (*cp == LP || *cp == '/') break;
931 }
932
933 if (*cp != LP) // no left paren found
934 {
935 // Path is using the implicit current device so if there is
936 // no current device, then we must fail.
937 cp = path;
938 if ( gRootVolume == NULL )
939 return NULL;
940 }
941 else if ((cp - path) == 2) // found "xx("
942 {
943 const struct devsw * dp;
944 const char * xp = path;
945 int i;
946 int unit = -1;
947 int part = -1;
948
949 cp++;
950
951 // Check the 2 character device name pointed by 'xp'.
952
953 for (dp = devsw; dp->name; dp++)
954 {
955 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
956 break; // found matching entry
957 }
958 if (dp->name == NULL)
959 {
960 error("Unknown device '%c%c'\n", xp[0], xp[1]);
961 return NULL;
962 }
963
964 // Extract the optional unit number from the specification.
965 // hd(unit) or hd(unit, part).
966
967 i = 0;
968 while (*cp >= '0' && *cp <= '9')
969 {
970 i = i * 10 + *cp++ - '0';
971 unit = i;
972 }
973
974 // Unit is no longer optional and never really was.
975 // If the user failed to specify it then the unit number from the previous kernDev
976 // would have been used which makes little sense anyway.
977 // For example, if the user did fd()/foobar and the current root device was the
978 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
979 if(unit == -1)
980 return NULL;
981
982 // Extract the optional partition number from the specification.
983
984 if (*cp == ',')
985 part = atoi(++cp);
986
987 // If part is not specified part will be -1 whereas before it would have been
988 // whatever the last partition was which makes about zero sense if the device
989 // has been switched.
990
991 // Skip past the right paren.
992
993 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
994 if (*cp == RP) cp++;
995
996 biosdev = dp->biosdev + unit;
997 bvr = newBootVolumeRef(biosdev, part);
998
999 if(bvr == NULL)
1000 return NULL;
1001 }
1002 else
1003 {
1004 // Bad device specifier, skip past the right paren.
1005
1006 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
1007 if (*cp == RP) cp++;
1008 // If gRootVolume was NULL, then bvr will be NULL as well which
1009 // should be caught by the caller.
1010 }
1011
1012 // Returns the file path following the device spec.
1013 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1014
1015 *outPath = cp;
1016
1017 return bvr;
1018}
1019
1020//==========================================================================
1021// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1022// which caches the information. So it's only allocated on the first run.
1023static BVRef newBootVolumeRef( int biosdev, int partno )
1024{
1025BVRef bvr, bvr1, bvrChain;
1026
1027bvr = bvr1 = NULL;
1028
1029 // Try resolving "rd" and "bt" devices first.
1030if (biosdev == kPseudoBIOSDevRAMDisk)
1031{
1032if (gRAMDiskVolume)
1033 bvr1 = gRAMDiskVolume;
1034}
1035else if (biosdev == kPseudoBIOSDevBooter)
1036{
1037if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
1038bvr1 = gRAMDiskVolume;
1039else
1040bvr1 = gBIOSBootVolume;
1041}
1042else
1043{
1044// Fetch the volume list from the device.
1045
1046scanBootVolumes( biosdev, NULL );
1047bvrChain = getBVChainForBIOSDev(biosdev);
1048
1049// Look for a perfect match based on device and partition number.
1050
1051for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1052{
1053if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1054
1055bvr1 = bvr;
1056if ( bvr->part_no == partno ) break;
1057}
1058}
1059
1060return bvr ? bvr : bvr1;
1061}
1062
1063//==========================================================================
1064// getDeviceDescription() - Extracts unit number and partition number
1065// from bvr structure into "dw(u,p)" format.
1066// Returns length of the out string
1067int getDeviceDescription(BVRef bvr, char *str)
1068{
1069 if(!str)
1070 return 0;
1071
1072*str = '\0';
1073
1074if (bvr)
1075{
1076 const struct devsw *dp = devsw;
1077while(dp->name && bvr->biosdev >= dp->biosdev)
1078 dp++;
1079
1080dp--;
1081if (dp->name)
1082 return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1083}
1084
1085return 0;
1086}
1087

Archive Download this file

Revision: 1118