Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1919