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#include <AvailabilityMacros.h>
62
63#include "libsaio.h"
64#include "boot.h"
65#include "bootstruct.h"
66#include "ramdisk.h"
67#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
68# include <Kernel/libkern/crypto/md5.h>
69#else
70# include <sys/md5.h>
71#endif
72#include <uuid/uuid.h>
73#if 0 /* No OS X release has ever included this. */
74#include <Kernel/uuid/namespace.h>
75#else
76/* copied from uuid/namespace.h, just like BootX's fs.c does. */
77UUID_DEFINE( kFSUUIDNamespaceSHA1, 0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC );
78#endif
79
80extern int multiboot_partition;
81extern int multiboot_partition_set;
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
113void * gFSLoadAddress = 0;
114
115// Turbo - save what we think is our original BIOS boot volume if we have one 0xab
116BVRef gBIOSBootVolume = NULL;
117BVRef gBootVolume;
118
119//static BVRef getBootVolumeRef( const char * path, const char ** outPath );
120static BVRef newBootVolumeRef( int biosdev, int partno );
121
122//==========================================================================
123// LoadVolumeFile - LOW-LEVEL FILESYSTEM FUNCTION.
124// Load the specified file from the specified volume
125// to the load buffer at LOAD_ADDR.
126// If the file is fat, load only the i386 portion.
127
128long LoadVolumeFile(BVRef bvr, const char *filePath)
129{
130 long fileSize;
131
132 // Read file into load buffer. The data in the load buffer will be
133 // overwritten by the next LoadFile() call.
134
135 gFSLoadAddress = (void *) LOAD_ADDR;
136
137 fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
138
139 // Return the size of the file, or -1 if load failed.
140
141 return fileSize;
142}
143
144//==========================================================================
145// LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
146// Load the specified file to the load buffer at LOAD_ADDR.
147// If the file is fat, load only the i386 portion.
148
149long LoadFile(const char * fileSpec)
150{
151 const char * filePath;
152 BVRef bvr;
153
154 // Resolve the boot volume from the file spec.
155
156 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
157 return -1;
158
159 return LoadVolumeFile(bvr, filePath);
160}
161
162long ReadFileAtOffset(const char * fileSpec, void *buffer, uint64_t offset, uint64_t length)
163{
164 const char *filePath;
165 BVRef bvr;
166
167 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
168 return -1;
169
170 if (bvr->fs_readfile == NULL)
171 return -1;
172
173 return bvr->fs_readfile(bvr, (char *)filePath, buffer, offset, length);
174}
175
176long LoadThinFatFile(const char *fileSpec, void **binary)
177{
178 const char *filePath;
179 FSReadFile readFile;
180 BVRef bvr;
181 unsigned long length, length2;
182
183 // Resolve the boot volume from the file spec.
184
185 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
186 return -1;
187
188 *binary = (void *)kLoadAddr;
189
190 // Read file into load buffer. The data in the load buffer will be
191 // overwritten by the next LoadFile() call.
192
193 gFSLoadAddress = (void *) LOAD_ADDR;
194
195 readFile = bvr->fs_readfile;
196
197 if (readFile != NULL) {
198 // Read the first 4096 bytes (fat header)
199 length = readFile(bvr, (char *)filePath, *binary, 0, 0x1000);
200 if (length > 0) {
201 if (ThinFatFile(binary, &length) == 0) {
202if (length == 0)
203return 0;
204 // We found a fat binary; read only the thin part
205 length = readFile(bvr, (char *)filePath,
206 (void *)kLoadAddr, (unsigned long)(*binary) - kLoadAddr, length);
207 *binary = (void *)kLoadAddr;
208 } else {
209 // Not a fat binary; read the rest of the file
210 length2 = readFile(bvr, (char *)filePath, (void *)(kLoadAddr + length), length, 0);
211 if (length2 == -1) return -1;
212 length += length2;
213 }
214 }
215 } else {
216 length = bvr->fs_loadfile(bvr, (char *)filePath);
217 if (length > 0) {
218 ThinFatFile(binary, &length);
219 }
220 }
221
222 return length;
223}
224
225#if UNUSED
226long GetFSUUID(char *spec, char *uuidStr)
227{
228 BVRef bvr;
229 long rval = -1;
230 const char *devSpec;
231
232 if ((bvr = getBootVolumeRef(spec, &devSpec)) == NULL)
233 return -1;
234
235 if(bvr->fs_getuuid)
236 rval = bvr->fs_getuuid(bvr, uuidStr);
237
238 return rval;
239}
240#endif
241
242// filesystem-specific getUUID functions call this shared string generator
243long CreateUUIDString(uint8_t uubytes[], int nbytes, char *uuidStr)
244{
245 unsigned fmtbase, fmtidx, i;
246 uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 };
247 char *p = uuidStr;
248 MD5_CTX md5c;
249 uint8_t mdresult[16];
250
251 bzero(mdresult, sizeof(mdresult));
252
253 // just like AppleFileSystemDriver
254 MD5Init(&md5c);
255 MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1));
256 MD5Update(&md5c, uubytes, nbytes);
257 MD5Final(mdresult, &md5c);
258
259 // this UUID has been made version 3 style (i.e. via namespace)
260 // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte)
261 mdresult[6] = 0x30 | ( mdresult[6] & 0x0F );
262 mdresult[8] = 0x80 | ( mdresult[8] & 0x3F );
263
264
265 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
266 i = 0; fmtbase = 0;
267 for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) {
268 for(i=0; i < uuidfmt[fmtidx]; i++) {
269 uint8_t byte = mdresult[fmtbase+i];
270 char nib;
271
272 nib = byte >> 4;
273 *p = nib + '0'; // 0x4 -> '4'
274 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
275 p++;
276
277 nib = byte & 0xf;
278 *p = nib + '0'; // 0x4 -> '4'
279 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
280 p++;
281
282 }
283 fmtbase += i;
284 if(fmtidx < sizeof(uuidfmt)-1)
285 *(p++) = '-';
286 else
287 *p = '\0';
288 }
289
290 return 0;
291}
292
293
294//==========================================================================
295// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
296// Fetch the next directory entry for the given directory.
297
298long GetDirEntry(const char * dirSpec, long long * dirIndex, const char ** name,
299 long * flags, long * time)
300{
301 const char * dirPath;
302 BVRef bvr;
303
304 // Resolve the boot volume from the dir spec.
305
306 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
307 return -1;
308
309 // Return 0 on success, or -1 if there are no additional entries.
310
311 return bvr->fs_getdirentry( bvr,
312 /* dirPath */ (char *)dirPath,
313 /* dirIndex */ dirIndex,
314 /* dirEntry */ (char **)name, flags, time, 0, 0 );
315}
316
317//==========================================================================
318// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
319// Get attributes for the specified file.
320
321static char* gMakeDirSpec;
322
323long GetFileInfo(const char * dirSpec, const char * name,
324 long * flags, long * time)
325{
326 long long index = 0;
327 const char * entryName;
328
329 if (gMakeDirSpec == 0)
330 gMakeDirSpec = (char *)malloc(1024);
331
332 if (!dirSpec) {
333 long idx, len;
334
335 len = strlen(name);
336
337 for (idx = len; idx && (name[idx] != '/' && name[idx] != '\\'); idx--) {}
338 if (idx == 0) {
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) or the volume UUID -
823 * to override the default selection.
824 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
825 */
826const char * val;
827char testStr[64];
828int cnt;
829
830if (getValueForKey(kDefaultPartition, &val, &cnt, &bootInfo->bootConfig) && cnt >= 7 && filteredChain)
831{
832for ( bvr = chain; bvr; bvr = bvr->next )
833{
834if ( bvr->biosdev >= 0x80 && bvr->biosdev < 0x100
835&& ( bvr->flags & ( kBVFlagSystemVolume|kBVFlagForeignBoot ) ) )
836{
837// Trying to match hd(x,y) format.
838sprintf(testStr, "hd(%d,%d)", bvr->biosdev - 0x80, bvr->part_no);
839if (strcmp(testStr, val) == 0)
840return bvr;
841
842// Trying to match volume UUID.
843if (bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0 && strcmp(testStr, val) == 0)
844return bvr;
845}
846}
847}
848
849/*
850 * Scannig the volume chain backwards and trying to find
851 * a HFS+ volume with valid boot record signature.
852 * If not found any active partition then we will
853 * select this volume as the boot volume.
854 */
855for ( bvr = chain; bvr; bvr = bvr->next )
856{
857if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = true;
858// zhell -- Undo a regression that was introduced from r491 to 492.
859// if gBIOSBootVolume is set already, no change is required
860if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
861&& gBIOSBootVolume
862&& (!filteredChain || (filteredChain && bvr->visible))
863&& bvr->biosdev == gBIOSDev )
864bvr2 = bvr;
865// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
866// from r491,
867if ( bvr->flags & kBVFlagBootable
868&& ! gBIOSBootVolume
869&& bvr->biosdev == gBIOSDev )
870bvr2 = bvr;
871}
872
873
874/*
875 * Use the standrad method for selecting the boot volume.
876 */
877if (foundPrimary)
878{
879for ( bvr = chain; bvr; bvr = bvr->next )
880{
881if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
882if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
883}
884}
885
886bvr = bvr2 ? bvr2 :
887bvr1 ? bvr1 : chain;
888
889return bvr;
890}
891
892//==========================================================================
893
894#define LP '('
895#define RP ')'
896int gBIOSDev;
897
898/*!
899 This is like boot2's gBootVolume except it is for the internal use of
900 libsaio to track which volume an unqualified path should be relative to.
901 This replaces bootInfo->kernDev as the carrier of this information.
902 */
903static BVRef gRootVolume;
904
905void setRootVolume(BVRef volume)
906{
907 gRootVolume = volume;
908 // Veto non-native FS. Basically that means don't allow the root volume to
909 // be set to a volume we can't read files from.
910 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
911 gRootVolume = NULL;
912}
913
914void setBootGlobals(BVRef chain)
915{
916 // Record default boot device.
917 gBootVolume = selectBootVolume(chain);
918
919 // turbo - Save the ORIGINAL boot volume too for loading our mkext
920 if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
921
922 setRootVolume(gBootVolume);
923}
924
925/*!
926 Extracts the volume selector from the pathname, returns the selected
927 BVRef, and sets *outPath to the remainder of the path.
928 If the path did not include a volume selector then the current volume
929 is used. When called with a volume selector the current volume
930 is changed to the selected volume unless the volume selector is
931 that of a ramdisk.
932 */
933BVRef getBootVolumeRef( const char * path, const char ** outPath )
934{
935 const char * cp;
936 BVRef bvr = gRootVolume;
937 int biosdev = gBIOSDev;
938
939 // Search for left parenthesis in the path specification.
940
941 for (cp = path; *cp; cp++) {
942 if (*cp == LP || *cp == '/') break;
943 }
944
945 if (*cp != LP) // no left paren found
946 {
947 // Path is using the implicit current device so if there is
948 // no current device, then we must fail.
949 cp = path;
950 if ( gRootVolume == NULL )
951 return NULL;
952 }
953 else if ((cp - path) == 2) // found "xx("
954 {
955 const struct devsw * dp;
956 const char * xp = path;
957 int i;
958 int unit = -1;
959 int part = -1;
960
961 cp++;
962
963 // Check the 2 character device name pointed by 'xp'.
964
965 for (dp = devsw; dp->name; dp++)
966 {
967 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
968 break; // found matching entry
969 }
970 if (dp->name == NULL)
971 {
972 error("Unknown device '%c%c'\n", xp[0], xp[1]);
973 return NULL;
974 }
975
976 // Extract the optional unit number from the specification.
977 // hd(unit) or hd(unit, part).
978
979 i = 0;
980 while (*cp >= '0' && *cp <= '9')
981 {
982 i = i * 10 + *cp++ - '0';
983 unit = i;
984 }
985
986 // Unit is no longer optional and never really was.
987 // If the user failed to specify it then the unit number from the previous kernDev
988 // would have been used which makes little sense anyway.
989 // For example, if the user did fd()/foobar and the current root device was the
990 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
991 if(unit == -1)
992 return NULL;
993
994 // Extract the optional partition number from the specification.
995
996 if (*cp == ',')
997 part = atoi(++cp);
998
999 // If part is not specified part will be -1 whereas before it would have been
1000 // whatever the last partition was which makes about zero sense if the device
1001 // has been switched.
1002
1003 // Skip past the right paren.
1004
1005 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
1006 if (*cp == RP) cp++;
1007
1008 biosdev = dp->biosdev + unit;
1009 bvr = newBootVolumeRef(biosdev, part);
1010
1011 if(bvr == NULL)
1012 return NULL;
1013 }
1014 else
1015 {
1016 // Bad device specifier, skip past the right paren.
1017
1018 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
1019 if (*cp == RP) cp++;
1020 // If gRootVolume was NULL, then bvr will be NULL as well which
1021 // should be caught by the caller.
1022 }
1023
1024 // Returns the file path following the device spec.
1025 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1026
1027 *outPath = cp;
1028
1029 return bvr;
1030}
1031
1032//==========================================================================
1033// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1034// which caches the information. So it's only allocated on the first run.
1035static BVRef newBootVolumeRef( int biosdev, int partno )
1036{
1037BVRef bvr, bvr1, bvrChain;
1038
1039bvr = bvr1 = NULL;
1040
1041 // Try resolving "rd" and "bt" devices first.
1042if (biosdev == kPseudoBIOSDevRAMDisk)
1043{
1044if (gRAMDiskVolume)
1045 bvr1 = gRAMDiskVolume;
1046}
1047else if (biosdev == kPseudoBIOSDevBooter)
1048{
1049if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
1050bvr1 = gRAMDiskVolume;
1051else
1052bvr1 = gBIOSBootVolume;
1053}
1054else
1055{
1056// Fetch the volume list from the device.
1057
1058scanBootVolumes( biosdev, NULL );
1059bvrChain = getBVChainForBIOSDev(biosdev);
1060
1061// Look for a perfect match based on device and partition number.
1062
1063for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1064{
1065if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
1066
1067bvr1 = bvr;
1068if ( bvr->part_no == partno ) break;
1069}
1070}
1071
1072return bvr ? bvr : bvr1;
1073}
1074
1075//==========================================================================
1076// getDeviceDescription() - Extracts unit number and partition number
1077// from bvr structure into "dw(u,p)" format.
1078int getDeviceDescription(BVRef bvr, char *str)
1079{
1080const struct devsw *dp;
1081
1082*str = '\0';
1083
1084if (bvr)
1085{
1086for (dp = devsw; dp->name && bvr->biosdev >= dp->biosdev; dp++);
1087dp--;
1088if (dp->name) sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1089
1090return true;
1091}
1092
1093return false;
1094}
1095

Archive Download this file

Revision: 264