Chameleon

Chameleon Svn Source Tree

Root/branches/rewrite/i386/libsaio/sys.c

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

Archive Download this file

Revision: 1066