Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1171