Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/libsaio/sys.c

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

Archive Download this file

Revision: 2562