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

Archive Download this file

Revision: 2458