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

Archive Download this file

Revision: 2564