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
598for (dp=devsw; dp->name; dp++)
599{
600if (bvd[0] == dp->name[0] && bvd[1] == dp->name[1])
601{
602unit = 0;
603partition = 0;
604/* get optional unit and partition */
605if (len >= 5 && bvd[2] == '(') { /* min must be present xx(0) */
606cp = &bvd[3];
607i = 0;
608while ((cp - path) < len && isdigit(*cp))
609{
610i = i * 10 + *cp++ - '0';
611unit = i;
612}
613if (*cp++ == ',')
614{
615i = 0;
616while ((cp - path) < len && isdigit(*cp))
617{
618i = i * 10 + *cp++ - '0';
619partition = i;
620}
621}
622}
623bvr = newBootVolumeRef(dp->biosdev + unit, partition);
624
625return open_bvr(bvr, path, flags);
626}
627}
628return -1;
629}
630
631//==========================================================================
632// close() - Close a file descriptor.
633
634int close(int fdesc)
635{
636struct iob * io;
637
638if ((io = iob_from_fdesc(fdesc)) == NULL)
639{
640return (-1);
641}
642
643io->i_flgs = 0;
644
645return 0;
646}
647
648//==========================================================================
649// lseek() - Reposition the byte offset of the file descriptor from the
650// beginning of the file. Returns the relocated offset.
651
652int b_lseek(int fdesc, int offset, int ptr)
653{
654struct iob * io;
655
656if ((io = iob_from_fdesc(fdesc)) == NULL)
657{
658return (-1);
659}
660
661io->i_offset = offset;
662
663return offset;
664}
665
666//==========================================================================
667// tell() - Returns the byte offset of the file descriptor.
668
669int tell(int fdesc)
670{
671struct iob * io;
672
673if ((io = iob_from_fdesc(fdesc)) == NULL)
674{
675return 0;
676}
677
678return io->i_offset;
679}
680
681//==========================================================================
682// read() - Read up to 'count' bytes of data from the file descriptor
683// into the buffer pointed to by buf.
684
685int read(int fdesc, char * buf, int count)
686{
687struct iob * io;
688
689if ((io = iob_from_fdesc(fdesc)) == NULL)
690{
691return (-1);
692}
693
694if ((io->i_offset + count) > (unsigned int)io->i_filesize)
695{
696count = io->i_filesize - io->i_offset;
697}
698
699if (count <= 0)
700{
701return 0; // end of file
702}
703
704bcopy(io->i_buf + io->i_offset, buf, count);
705
706io->i_offset += count;
707
708return count;
709}
710
711//==========================================================================
712// write() - Write up to 'count' bytes of data to the file descriptor
713// from the buffer pointed to by buf.
714
715int write(int fdesc, const char * buf, int count)
716{
717 struct iob * io;
718
719 if ((io = iob_from_fdesc(fdesc)) == NULL)
720 return (-1);
721
722 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
723 count = io->i_filesize - io->i_offset;
724
725 if (count <= 0)
726 return 0; // end of file
727
728 bcopy(buf, io->i_buf + io->i_offset, count);
729
730 io->i_offset += count;
731
732 return count;
733}
734
735//==========================================================================
736
737int writebyte(int fdesc, char value)
738{
739struct iob * io;
740
741if ((io = iob_from_fdesc(fdesc)) == NULL)
742 return (-1);
743
744 if ((io->i_offset + 1) > (unsigned int)io->i_filesize)
745 return 0; // end of file
746
747 io->i_buf[io->i_offset++] = value;
748
749 return 1;
750}
751
752//==========================================================================
753
754int writeint(int fdesc, int value)
755{
756 struct iob * io;
757
758 if ((io = iob_from_fdesc(fdesc)) == NULL)
759 return (-1);
760
761 if ((io->i_offset + 4) > (unsigned int)io->i_filesize)
762 return 0; // end of file
763
764 bcopy(&value, io->i_buf + io->i_offset, 4);
765
766 io->i_offset += 4;
767
768 return 4;
769}
770
771//==========================================================================
772// file_size() - Returns the size of the file described by the file
773// descriptor.
774
775int file_size(int fdesc)
776{
777struct iob * io;
778
779if ((io = iob_from_fdesc(fdesc)) == 0)
780{
781return 0;
782}
783
784return io->i_filesize;
785}
786
787//==========================================================================
788
789struct dirstuff * vol_opendir(BVRef bvr, const char * path)
790{
791struct dirstuff * dirp = 0;
792
793dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
794
795if (dirp == NULL)
796goto error;
797
798dirp->dir_path = newString(path);
799if (dirp->dir_path == NULL)
800goto error;
801
802dirp->dir_bvr = bvr;
803
804return dirp;
805
806error:
807closedir(dirp);
808
809return NULL;
810}
811
812//==========================================================================
813
814struct dirstuff * opendir(const char * path)
815{
816struct dirstuff * dirp = 0;
817const char * dirPath;
818BVRef bvr;
819
820if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
821goto error;
822
823dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
824if (dirp == NULL)
825goto error;
826
827dirp->dir_path = newString(dirPath);
828if (dirp->dir_path == NULL)
829goto error;
830
831dirp->dir_bvr = bvr;
832
833 return dirp;
834
835error:
836closedir(dirp);
837
838return NULL;
839}
840
841//==========================================================================
842
843int closedir(struct dirstuff * dirp)
844{
845if (dirp)
846{
847if (dirp->dir_path)
848{
849free(dirp->dir_path);
850}
851
852free(dirp);
853}
854
855return 0;
856}
857
858//==========================================================================
859
860int readdir(struct dirstuff * dirp, const char ** name, long * flags, u_int32_t * time)
861{
862return dirp->dir_bvr->fs_getdirentry(dirp->dir_bvr,
863/* dirPath */ dirp->dir_path,
864/* dirIndex */ &dirp->dir_index,
865/* dirEntry */ (char **)name, flags, time, 0, 0);
866}
867
868//==========================================================================
869
870int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags, u_int32_t * time, FinderInfo *finderInfo, long *infoValid)
871{
872return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
873/* dirPath */ dirp->dir_path,
874/* dirIndex */ &dirp->dir_index,
875/* dirEntry */ (char **)name,
876flags, time,
877finderInfo, infoValid);
878}
879
880//==========================================================================
881
882const char * systemConfigDir()
883{
884if (gBootFileType == kNetworkDeviceType)
885{
886return "";
887}
888return "/Library/Preferences/SystemConfiguration";
889}
890
891//==========================================================================
892
893int gBootFileType;
894
895void scanBootVolumes(int biosdev, int * count)
896{
897BVRef bvr = 0;
898
899bvr = diskScanBootVolumes(biosdev, count);
900if (bvr == NULL)
901{
902bvr = nbpScanBootVolumes(biosdev, count);
903if (bvr != NULL)
904{
905gBootFileType = kNetworkDeviceType;
906}
907}
908else
909{
910gBootFileType = kBlockDeviceType;
911}
912}
913
914//==========================================================================
915
916void scanDisks(int biosdev, int *count)
917{
918#define MAX_HDD_COUNT 32
919int bvCount;
920int hd = 0;
921
922// Testing up to MAX_HDD_COUNT hard drives.
923while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
924{
925bvCount = 0;
926scanBootVolumes(0x80 + hd, &bvCount);
927hd++;
928}
929
930// Also scanning CD/DVD drive.
931if (biosDevIsCDROM(gBIOSDev))
932{
933bvCount = 0;
934scanBootVolumes(gBIOSDev, &bvCount);
935}
936}
937
938//==========================================================================
939
940BVRef selectBootVolume( BVRef chain )
941{
942bool filteredChain = false;
943bool foundPrimary = false;
944BVRef bvr, bvr1 = 0, bvr2 = 0;
945
946if (chain->filtered)
947{
948filteredChain = true;
949}
950
951if (multiboot_partition_set)
952{
953for ( bvr = chain; bvr; bvr = bvr->next )
954{
955if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
956{
957return bvr;
958}
959}
960}
961
962/*
963 * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
964 * to override the default selection.
965 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
966 */
967char *val = XMLDecode(getStringForKey(kDefaultPartition, &bootInfo->chameleonConfig));
968if (val)
969{
970for ( bvr = chain; bvr; bvr = bvr->next )
971{
972if (matchVolumeToString(bvr, val, false))
973{
974free(val);
975return bvr;
976}
977}
978free(val);
979}
980
981/*
982 * Scannig the volume chain backwards and trying to find
983 * a HFS+ volume with valid boot record signature.
984 * If not found any active partition then we will
985 * select this volume as the boot volume.
986 */
987for ( bvr = chain; bvr; bvr = bvr->next )
988{
989if (multiboot_skip_partition_set)
990{
991if (bvr->part_no == multiboot_skip_partition)
992{
993continue;
994}
995}
996
997if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev )
998{
999foundPrimary = true;
1000}
1001
1002// zhell -- Undo a regression that was introduced from r491 to 492.
1003// if gBIOSBootVolume is set already, no change is required
1004if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
1005&& gBIOSBootVolume
1006&& (!filteredChain || (filteredChain && bvr->visible))
1007&& bvr->biosdev == gBIOSDev )
1008{
1009bvr2 = bvr;
1010}
1011
1012// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
1013// from r491,
1014if ( bvr->flags & kBVFlagBootable
1015&& ! gBIOSBootVolume
1016&& bvr->biosdev == gBIOSDev )
1017{
1018bvr2 = bvr;
1019}
1020}
1021
1022/*
1023 * Use the standrad method for selecting the boot volume.
1024 */
1025if (foundPrimary)
1026{
1027for ( bvr = chain; bvr; bvr = bvr->next )
1028{
1029if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev )
1030{
1031bvr1 = bvr;
1032}
1033if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev )
1034{
1035bvr2 = bvr;
1036}
1037}
1038}
1039
1040bvr = bvr2 ? bvr2 :
1041bvr1 ? bvr1 : chain;
1042
1043return bvr;
1044}
1045
1046//==========================================================================
1047
1048
1049/*!
1050 This is like boot2's gBootVolume except it is for the internal use of
1051 libsaio to track which volume an unqualified path should be relative to.
1052 This replaces bootInfo->kernDev as the carrier of this information.
1053 */
1054static BVRef gRootVolume;
1055
1056//==========================================================================
1057
1058void setRootVolume(BVRef volume)
1059{
1060gRootVolume = volume;
1061// Veto non-native FS. Basically that means don't allow the root volume to
1062// be set to a volume we can't read files from.
1063if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
1064{
1065gRootVolume = NULL;
1066}
1067}
1068
1069//==========================================================================
1070
1071void setBootGlobals(BVRef chain)
1072{
1073// Record default boot device.
1074gBootVolume = selectBootVolume(chain);
1075
1076// turbo - Save the ORIGINAL boot volume too for loading our mkext
1077if (!gBIOSBootVolume)
1078{
1079gBIOSBootVolume = gBootVolume;
1080}
1081
1082setRootVolume(gBootVolume);
1083}
1084
1085//==========================================================================
1086/*!
1087 Extracts the volume selector from the pathname, returns the selected
1088 BVRef, and sets *outPath to the remainder of the path.
1089 If the path did not include a volume selector then the current volume
1090 is used. When called with a volume selector the current volume
1091 is changed to the selected volume unless the volume selector is
1092 that of a ramdisk.
1093 */
1094BVRef getBootVolumeRef( const char * path, const char ** outPath )
1095{
1096const char*cp;
1097BVRef bvr= gRootVolume;
1098int biosdev= gBIOSDev;
1099
1100// Search for left parenthesis in the path specification.
1101
1102for (cp = path; *cp; cp++)
1103{
1104if (*cp == LP || *cp == '/')
1105{
1106break;
1107}
1108}
1109
1110if (*cp != LP) // no left paren found
1111{
1112cp = path;
1113// Path is using the implicit current device so if there is
1114// no current device, then we must fail.
1115if (gRootVolume == NULL)
1116{
1117return NULL;
1118}
1119}
1120else if ((cp - path) == 2) // found "xx("
1121{
1122const struct devsw * dp;
1123const char * xp = path;
1124
1125int i;
1126int unit = -1;
1127int part = -1;
1128
1129cp++;
1130
1131// Check the 2 character device name pointed by 'xp'.
1132
1133for (dp = devsw; dp->name; dp++)
1134{
1135if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
1136{
1137break;// Found matching entry.
1138}
1139}
1140
1141if (dp->name == NULL)
1142{
1143error("Unknown device '%c%c'\n", xp[0], xp[1]);
1144return NULL;
1145}
1146
1147// Extract the optional unit number from the specification.
1148// hd(unit) or hd(unit, part).
1149
1150i = 0;
1151
1152while (*cp >= '0' && *cp <= '9')
1153{
1154i = i * 10 + *cp++ - '0';
1155unit = i;
1156}
1157
1158// Unit is no longer optional and never really was.
1159// If the user failed to specify it then the unit number from the previous kernDev
1160// would have been used which makes little sense anyway.
1161// For example, if the user did fd()/foobar and the current root device was the
1162// second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
1163if (unit == -1)
1164{
1165return NULL;
1166}
1167
1168// Extract the optional partition number from the specification.
1169
1170if (*cp == ',')
1171{
1172part = atoi(++cp);
1173}
1174
1175// If part is not specified part will be -1 whereas before it would have been
1176// whatever the last partition was which makes about zero sense if the device
1177// has been switched.
1178
1179// Skip past the right paren.
1180
1181for ( ; *cp && *cp != RP; cp++) /* LOOP */;
1182
1183if (*cp == RP)
1184{
1185cp++;
1186}
1187
1188biosdev = dp->biosdev + unit;
1189
1190bvr = newBootVolumeRef(biosdev, part);
1191
1192if (bvr == NULL)
1193{
1194return NULL;
1195}
1196}
1197else
1198{
1199// Bad device specifier, skip past the right paren.
1200
1201for (cp++; *cp && *cp != RP; cp++) /* LOOP */;
1202if (*cp == RP)
1203{
1204cp++;
1205}
1206
1207// If gRootVolume was NULL, then bvr will be NULL as well which
1208// should be caught by the caller.
1209}
1210
1211// Returns the file path following the device spec.
1212// e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1213
1214*outPath = cp;
1215
1216return bvr;
1217}
1218
1219//==========================================================================
1220// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1221// which caches the information. So it's only allocated on the first run.
1222static BVRef newBootVolumeRef( int biosdev, int partno )
1223{
1224BVRef bvr, bvr1, bvrChain;
1225
1226bvr = bvr1 = NULL;
1227
1228// Try resolving "rd" and "bt" devices first.
1229if (biosdev == kPseudoBIOSDevRAMDisk)
1230{
1231if (gRAMDiskVolume)
1232{
1233bvr1 = gRAMDiskVolume;
1234}
1235}
1236else if (biosdev == kPseudoBIOSDevBooter)
1237{
1238if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
1239{
1240bvr1 = gRAMDiskVolume;
1241}
1242else
1243{
1244bvr1 = gBIOSBootVolume;
1245}
1246}
1247else
1248{
1249// Fetch the volume list from the device.
1250#if 0
1251scanBootVolumes( biosdev, NULL );
1252#endif
1253bvrChain = getBVChainForBIOSDev(biosdev);
1254
1255// Look for a perfect match based on device and partition number.
1256
1257for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1258{
1259if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 )
1260{
1261continue;
1262}
1263
1264bvr1 = bvr;
1265
1266if ( bvr->part_no == partno )
1267{
1268break;
1269}
1270}
1271}
1272
1273return bvr ? bvr : bvr1;
1274}
1275
1276//==========================================================================
1277// getDeviceDescription() - Extracts unit number and partition number
1278// from bvr structure into "dw(u,p)" format.
1279// Returns length of the out string
1280int getDeviceDescription(BVRef bvr, char *str)
1281{
1282if(!str)
1283{
1284return 0;
1285}
1286
1287*str = '\0';
1288
1289if (bvr)
1290{
1291const struct devsw *dp = devsw;
1292while(dp->name && bvr->biosdev >= dp->biosdev)
1293{
1294dp++;
1295 }
1296dp--;
1297if (dp->name)
1298{
1299return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1300}
1301}
1302
1303return 0;
1304}
1305
1306//==========================================================================
1307

Archive Download this file

Revision: 2523