Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 515