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

Archive Download this file

Revision: 2606