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

Archive Download this file

Revision: 2542