Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2706