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

Archive Download this file

Revision: 2182