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

Archive Download this file

Revision: 2525