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

Archive Download this file

Revision: 2666