Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch_Modules/i386/libsaio/sys.c

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

Archive Download this file

Revision: 2238