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

Archive Download this file

Revision: 2554