Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2037