Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2476