Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/libsaio/sys.c

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

Archive Download this file

Revision: 2341