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";
971char *label;
972u_int32_t time;
973u_int32_t lasttime= 0;
974long flags;
975#endif
976
977if (chain->filtered)
978{
979filteredChain = true;
980}
981
982if (multiboot_partition_set)
983{
984for ( bvr = chain; bvr; bvr = bvr->next )
985{
986if (!bvr)
987{
988break;
989}
990
991if ( (bvr->part_no == multiboot_partition) && (bvr->biosdev == gBIOSDev) )
992{
993#if DEBUG_FEATURE_LAST_BOOT
994label = bvr->label[0] ? bvr->label : (bvr->altlabel[0] ? bvr->altlabel : (bvr->name[0] ? bvr->name : "Untitled"));
995DBG("Multiboot partition set: hd(%d,%d) '%s'\n", BIOS_DEV_UNIT(bvr), bvr->part_no, label);
996#endif
997return bvr;
998}
999}
1000}
1001
1002/*
1003 * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
1004 * to override the default selection.
1005 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
1006 */
1007char *val = XMLDecode(getStringForKey(kDefaultPartition, &bootInfo->chameleonConfig));
1008if (val)
1009{
1010for ( bvr = chain; bvr; bvr = bvr->next )
1011{
1012if (!bvr)
1013{
1014break;
1015}
1016
1017if (matchVolumeToString(bvr, val, false))
1018{
1019free(val);
1020#if DEBUG_FEATURE_LAST_BOOT
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);
1023#endif
1024return bvr;
1025}
1026}
1027free(val);
1028}
1029
1030#if DEBUG_FEATURE_LAST_BOOT // the above code cause "AllocateKernelMemory error"
1031// Bungo: select last booted partition as the boot volume
1032// TODO: support other OSes (foreign boot)
1033for (bvr = chain; bvr; bvr = bvr->next)
1034{
1035if (bvr->flags & (kBVFlagSystemVolume | kBVFlagForeignBoot))
1036{
1037time = 0;
1038flags = 0;
1039sprintf(dirSpec, "hd(%d,%d)/", BIOS_DEV_UNIT(bvr), bvr->part_no);
1040if ((GetFileInfo(dirSpec, fileSpec, &flags, &time) == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory))
1041{
1042if (time > lasttime)
1043{
1044lasttime = time;
1045bvr1 = bvr;
1046label = bvr1->label[0] ? bvr1->label : (bvr1->altlabel[0] ? bvr1->altlabel : (bvr1->name[0] ? bvr1->name : "Untitled"));
1047}
1048}
1049}
1050}
1051
1052if (bvr1)
1053{
1054DBG("Last booted volume: hd(%d,%d) '%s' set as default partition\n\n", BIOS_DEV_UNIT(bvr1), bvr1->part_no, label);
1055return bvr1;
1056}
1057// Bungo: code below selects first partition in the chain (last partition on disk),
1058// in my case Recovery HD, as boot volume, so I would prefer last booted partition
1059// as default boot volume - see the code above
1060#endif
1061
1062/*
1063 * Scannig the volume chain backwards and trying to find
1064 * a HFS+ volume with valid boot record signature.
1065 * If not found any active partition then we will
1066 * select this volume as the boot volume.
1067 */
1068for ( bvr = chain; bvr; bvr = bvr->next )
1069{
1070if (!bvr)
1071{
1072break;
1073}
1074
1075if (multiboot_skip_partition_set)
1076{
1077if (bvr->part_no == multiboot_skip_partition)
1078{
1079continue;
1080}
1081}
1082
1083if ( (bvr->flags & kBVFlagPrimary) && (bvr->biosdev == gBIOSDev) )
1084{
1085foundPrimary = true;
1086}
1087
1088// zhell -- Undo a regression that was introduced from r491 to 492.
1089// if gBIOSBootVolume is set already, no change is required
1090if ( (bvr->flags & (kBVFlagBootable | kBVFlagSystemVolume))
1091&& gBIOSBootVolume
1092&& (!filteredChain || (filteredChain && bvr->visible))
1093&& (bvr->biosdev == gBIOSDev) )
1094{
1095bvr2 = bvr;
1096}
1097
1098// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
1099// from r491,
1100if ( (bvr->flags & kBVFlagBootable)
1101&& !gBIOSBootVolume
1102&& (bvr->biosdev == gBIOSDev) )
1103{
1104bvr2 = bvr;
1105}
1106}
1107
1108/*
1109 * Use the standrad method for selecting the boot volume.
1110 */
1111if (foundPrimary)
1112{
1113for ( bvr = chain; bvr; bvr = bvr->next )
1114{
1115if (!bvr)
1116{
1117break;
1118}
1119
1120if ( (bvr->flags & kBVFlagNativeBoot) && (bvr->biosdev == gBIOSDev) )
1121{
1122bvr1 = bvr;
1123}
1124if ( (bvr->flags & kBVFlagPrimary) && (bvr->biosdev == gBIOSDev) )
1125{
1126bvr2 = bvr;
1127}
1128}
1129}
1130
1131bvr = bvr2 ? bvr2 : (bvr1 ? bvr1 : chain);
1132#if DEBUG_FEATURE_LAST_BOOT
1133label = bvr->label[0] ? bvr->label : (bvr->altlabel[0] ? bvr->altlabel : (bvr->name[0] ? bvr->name : "Untitled"));
1134DBG("Default partition set: hd(%d,%d) '%s'\n", BIOS_DEV_UNIT(bvr), bvr->part_no, label);
1135#endif
1136return bvr;
1137}
1138
1139//==========================================================================
1140
1141
1142/*!
1143 This is like boot2's gBootVolume except it is for the internal use of
1144 libsaio to track which volume an unqualified path should be relative to.
1145 This replaces bootInfo->kernDev as the carrier of this information.
1146 */
1147static BVRef gRootVolume;
1148
1149//==========================================================================
1150
1151void setRootVolume(BVRef volume)
1152{
1153gRootVolume = volume;
1154// Veto non-native FS. Basically that means don't allow the root volume to
1155// be set to a volume we can't read files from.
1156if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
1157{
1158gRootVolume = NULL;
1159}
1160}
1161
1162//==========================================================================
1163
1164void setBootGlobals(BVRef chain)
1165{
1166// Record default boot device.
1167gBootVolume = selectBootVolume(chain);
1168
1169// turbo - Save the ORIGINAL boot volume too for loading our mkext
1170if (!gBIOSBootVolume)
1171{
1172gBIOSBootVolume = gBootVolume;
1173}
1174
1175setRootVolume(gBootVolume);
1176}
1177
1178//==========================================================================
1179/*!
1180 Extracts the volume selector from the pathname, returns the selected
1181 BVRef, and sets *outPath to the remainder of the path.
1182 If the path did not include a volume selector then the current volume
1183 is used. When called with a volume selector the current volume
1184 is changed to the selected volume unless the volume selector is
1185 that of a ramdisk.
1186 */
1187BVRef getBootVolumeRef(const char *path, const char **outPath)
1188{
1189const char*cp;
1190BVRef bvr= gRootVolume;
1191int biosdev= gBIOSDev;
1192
1193// Search for left parenthesis in the path specification.
1194
1195for (cp = path; *cp; cp++)
1196{
1197if (*cp == LP || *cp == '/')
1198{
1199break;
1200}
1201}
1202
1203if (*cp != LP) // no left paren found
1204{
1205cp = path;
1206// Path is using the implicit current device so if there is
1207// no current device, then we must fail.
1208if (gRootVolume == NULL)
1209{
1210return NULL;
1211}
1212}
1213else if ((cp - path) == 2) // found "xx("
1214{
1215const struct devsw *dp;
1216const char *xp = path;
1217
1218int i;
1219int unit = -1;
1220int part = -1;
1221
1222cp++;
1223
1224// Check the 2 character device name pointed by 'xp'.
1225
1226for (dp = devsw; dp->name; dp++)
1227{
1228if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
1229{
1230break;// Found matching entry.
1231}
1232}
1233
1234if (dp->name == NULL)
1235{
1236error("Unknown device '%c%c'\n", xp[0], xp[1]);
1237return NULL;
1238}
1239
1240// Extract the optional unit number from the specification.
1241// hd(unit) or hd(unit, part).
1242
1243i = 0;
1244
1245while (*cp >= '0' && *cp <= '9')
1246{
1247i = i * 10 + *cp++ - '0';
1248unit = i;
1249}
1250
1251// Unit is no longer optional and never really was.
1252// If the user failed to specify it then the unit number from the previous kernDev
1253// would have been used which makes little sense anyway.
1254// For example, if the user did fd()/foobar and the current root device was the
1255// second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
1256if (unit == -1)
1257{
1258return NULL;
1259}
1260
1261// Extract the optional partition number from the specification.
1262
1263if (*cp == ',')
1264{
1265part = atoi(++cp);
1266}
1267
1268// If part is not specified part will be -1 whereas before it would have been
1269// whatever the last partition was which makes about zero sense if the device
1270// has been switched.
1271
1272// Skip past the right paren.
1273
1274for ( ; *cp && *cp != RP; cp++) /* LOOP */;
1275
1276if (*cp == RP)
1277{
1278cp++;
1279}
1280
1281biosdev = dp->biosdev + unit;
1282
1283bvr = newBootVolumeRef(biosdev, part);
1284
1285if (bvr == NULL)
1286{
1287return NULL;
1288}
1289}
1290else
1291{
1292// Bad device specifier, skip past the right paren.
1293
1294for (cp++; *cp && *cp != RP; cp++) /* LOOP */;
1295if (*cp == RP)
1296{
1297cp++;
1298}
1299
1300// If gRootVolume was NULL, then bvr will be NULL as well which
1301// should be caught by the caller.
1302}
1303
1304// Returns the file path following the device spec.
1305// e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
1306
1307*outPath = cp;
1308
1309return bvr;
1310}
1311
1312//==========================================================================
1313// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
1314// which caches the information. So it's only allocated on the first run.
1315static BVRef newBootVolumeRef( int biosdev, int partno )
1316{
1317BVRef bvr, bvr1, bvrChain;
1318
1319bvr = bvr1 = NULL;
1320
1321// Try resolving "rd" and "bt" devices first.
1322if (biosdev == kPseudoBIOSDevRAMDisk)
1323{
1324if (gRAMDiskVolume)
1325{
1326bvr1 = gRAMDiskVolume;
1327}
1328}
1329else if (biosdev == kPseudoBIOSDevBooter)
1330{
1331if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
1332{
1333bvr1 = gRAMDiskVolume;
1334}
1335else
1336{
1337bvr1 = gBIOSBootVolume;
1338}
1339}
1340else
1341{
1342// Fetch the volume list from the device.
1343#if 0
1344scanBootVolumes( biosdev, NULL );
1345#endif
1346bvrChain = getBVChainForBIOSDev(biosdev);
1347
1348// Look for a perfect match based on device and partition number.
1349
1350for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
1351{
1352if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 )
1353{
1354continue;
1355}
1356
1357bvr1 = bvr;
1358
1359if ( bvr->part_no == partno )
1360{
1361break;
1362}
1363}
1364}
1365
1366return bvr ? bvr : bvr1;
1367}
1368
1369//==========================================================================
1370// getDeviceDescription() - Extracts unit number and partition number
1371// from bvr structure into "dw(u,p)" format.
1372// Returns length of the out string
1373int getDeviceDescription(BVRef bvr, char *str)
1374{
1375if(!str)
1376{
1377return 0;
1378}
1379
1380*str = '\0';
1381
1382if (bvr)
1383{
1384const struct devsw *dp = devsw;
1385while(dp->name && bvr->biosdev >= dp->biosdev)
1386{
1387dp++;
1388 }
1389dp--;
1390if (dp->name)
1391{
1392return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);
1393}
1394}
1395
1396return 0;
1397}
1398
1399//==========================================================================
1400

Archive Download this file

Revision: 2636