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, u_int32_t * 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, u_int32_t * 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,
832u_int32_t * 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,
843u_int32_t * 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)
965{
966continue;
967}
968}
969if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev )
970{
971foundPrimary = true;
972}
973
974// zhell -- Undo a regression that was introduced from r491 to 492.
975// if gBIOSBootVolume is set already, no change is required
976if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
977&& gBIOSBootVolume
978&& (!filteredChain || (filteredChain && bvr->visible))
979&& bvr->biosdev == gBIOSDev )
980{
981bvr2 = bvr;
982}
983
984// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
985// from r491,
986if ( bvr->flags & kBVFlagBootable
987&& ! gBIOSBootVolume
988&& bvr->biosdev == gBIOSDev )
989{
990bvr2 = bvr;
991}
992}
993
994/*
995 * Use the standrad method for selecting the boot volume.
996 */
997if (foundPrimary)
998{
999for ( bvr = chain; bvr; bvr = bvr->next )
1000{
1001if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev )
1002{
1003bvr1 = bvr;
1004}
1005if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev )
1006{
1007bvr2 = bvr;
1008}
1009}
1010}
1011
1012bvr = bvr2 ? bvr2 :
1013bvr1 ? bvr1 : chain;
1014
1015return bvr;
1016}
1017
1018//==========================================================================
1019
1020#define LP '('
1021#define RP ')'
1022int gBIOSDev;
1023
1024/*!
1025 This is like boot2's gBootVolume except it is for the internal use of
1026 libsaio to track which volume an unqualified path should be relative to.
1027 This replaces bootInfo->kernDev as the carrier of this information.
1028 */
1029static BVRef gRootVolume;
1030
1031void setRootVolume(BVRef volume)
1032{
1033gRootVolume = volume;
1034// Veto non-native FS. Basically that means don't allow the root volume to
1035// be set to a volume we can't read files from.
1036if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
1037{
1038gRootVolume = NULL;
1039}
1040}
1041
1042void setBootGlobals(BVRef chain)
1043{
1044// Record default boot device.
1045gBootVolume = selectBootVolume(chain);
1046
1047// turbo - Save the ORIGINAL boot volume too for loading our mkext
1048if (!gBIOSBootVolume)
1049{
1050gBIOSBootVolume = gBootVolume;
1051}
1052
1053setRootVolume(gBootVolume);
1054}
1055
1056/*!
1057 Extracts the volume selector from the pathname, returns the selected
1058 BVRef, and sets *outPath to the remainder of the path.
1059 If the path did not include a volume selector then the current volume
1060 is used. When called with a volume selector the current volume
1061 is changed to the selected volume unless the volume selector is
1062 that of a ramdisk.
1063 */
1064BVRef getBootVolumeRef( const char * path, const char ** outPath )
1065{
1066 const char * cp;
1067 BVRef bvr = gRootVolume;
1068 int biosdev = gBIOSDev;
1069
1070 // Search for left parenthesis in the path specification.
1071
1072for (cp = path; *cp; cp++) {
1073if (*cp == LP || *cp == '/')
1074{
1075break;
1076}
1077}
1078
1079if (*cp != LP) { // no left paren found
1080cp = path;
1081// Path is using the implicit current device so if there is
1082// no current device, then we must fail.
1083if (gRootVolume == NULL)
1084{
1085return NULL;
1086}
1087} else if ((cp - path) == 2) { // found "xx("
1088const struct devsw * dp;
1089const char * xp = path;
1090
1091int i;
1092int unit = -1;
1093int part = -1;
1094
1095cp++;
1096
1097// Check the 2 character device name pointed by 'xp'.
1098
1099for (dp = devsw; dp->name; dp++)
1100{
1101if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
1102{
1103break;// Found matching entry.
1104}
1105}
1106
1107if (dp->name == NULL)
1108{
1109error("Unknown device '%c%c'\n", xp[0], xp[1]);
1110return NULL;
1111}
1112
1113// Extract the optional unit number from the specification.
1114// hd(unit) or hd(unit, part).
1115
1116i = 0;
1117
1118while (*cp >= '0' && *cp <= '9')
1119{
1120i = i * 10 + *cp++ - '0';
1121unit = i;
1122}
1123
1124// Unit is no longer optional and never really was.
1125// If the user failed to specify it then the unit number from the previous kernDev
1126// would have been used which makes little sense anyway.
1127// For example, if the user did fd()/foobar and the current root device was the
1128// second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
1129if (unit == -1)
1130{
1131return NULL;
1132}
1133
1134// Extract the optional partition number from the specification.
1135
1136if (*cp == ',')
1137{
1138part = atoi(++cp);
1139}
1140
1141// If part is not specified part will be -1 whereas before it would have been
1142// whatever the last partition was which makes about zero sense if the device
1143// has been switched.
1144
1145// Skip past the right paren.
1146
1147for ( ; *cp && *cp != RP; cp++) /* LOOP */;
1148
1149if (*cp == RP)
1150{
1151cp++;
1152}
1153
1154biosdev = dp->biosdev + unit;
1155
1156bvr = newBootVolumeRef(biosdev, part);
1157
1158if (bvr == NULL)
1159{
1160return NULL;
1161}
1162}
1163else
1164{
1165// Bad device specifier, skip past the right paren.
1166
1167for (cp++; *cp && *cp != RP; cp++) /* LOOP */;
1168if (*cp == RP)
1169{
1170cp++;
1171}
1172
1173// If gRootVolume was NULL, then bvr will be NULL as well which
1174// should be caught by the caller.
1175}
1176
1177// Returns the file path following the device spec.
1178// e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1179
1180*outPath = cp;
1181
1182return bvr;
1183}
1184
1185//==========================================================================
1186// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1187// which caches the information. So it's only allocated on the first run.
1188static BVRef newBootVolumeRef( int biosdev, int partno )
1189{
1190BVRef bvr, bvr1, bvrChain;
1191
1192bvr = bvr1 = NULL;
1193
1194// Try resolving "rd" and "bt" devices first.
1195if (biosdev == kPseudoBIOSDevRAMDisk)
1196{
1197if (gRAMDiskVolume)
1198{
1199bvr1 = gRAMDiskVolume;
1200}
1201}
1202else if (biosdev == kPseudoBIOSDevBooter)
1203{
1204if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
1205{
1206bvr1 = gRAMDiskVolume;
1207}
1208else
1209{
1210bvr1 = gBIOSBootVolume;
1211}
1212}
1213else
1214{
1215// Fetch the volume list from the device.
1216
1217scanBootVolumes( biosdev, NULL );
1218bvrChain = getBVChainForBIOSDev(biosdev);
1219
1220// Look for a perfect match based on device and partition number.
1221
1222for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1223{
1224if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 )
1225{
1226continue;
1227}
1228
1229bvr1 = bvr;
1230if ( bvr->part_no == partno )
1231{
1232break;
1233}
1234}
1235}
1236
1237return bvr ? bvr : bvr1;
1238}
1239
1240//==========================================================================
1241// getDeviceDescription() - Extracts unit number and partition number
1242// from bvr structure into "dw(u,p)" format.
1243// Returns length of the out string
1244int getDeviceDescription(BVRef bvr, char *str)
1245{
1246if(!str)
1247{
1248return 0;
1249}
1250
1251*str = '\0';
1252
1253if (bvr)
1254{
1255const struct devsw *dp = devsw;
1256while(dp->name && bvr->biosdev >= dp->biosdev)
1257{
1258dp++;
1259 }
1260dp--;
1261if (dp->name)
1262{
1263return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1264}
1265}
1266
1267return 0;
1268}
1269

Archive Download this file

Revision: 2490