]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/sys.c
boot-132.tar.gz
[apple/boot.git] / 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 */
48
49 /*
50 * Copyright (c) 1982, 1986 Regents of the University of California.
51 * All rights reserved. The Berkeley software License Agreement
52 * specifies the terms and conditions for redistribution.
53 *
54 * @(#)sys.c 7.1 (Berkeley) 6/5/86
55 */
56
57 #include "libsaio.h"
58 #include "bootstruct.h"
59 #include <sys/md5.h>
60 #include <uuid/uuid.h>
61 #include <Kernel/uuid/namespace.h>
62
63 struct devsw {
64 const char * name;
65 unsigned char biosdev;
66 int type;
67 };
68
69 static struct devsw devsw[] =
70 {
71 { "sd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_SD */
72 { "hd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_HD */
73 { "fd", 0x00, kBIOSDevTypeFloppy }, /* DEV_FD */
74 { "en", 0xE0, kBIOSDevTypeNetwork }, /* DEV_EN */
75 { 0, 0 }
76 };
77
78 /*
79 * Max number of file descriptors.
80 */
81 #define NFILES 6
82
83 static struct iob iob[NFILES];
84
85 void * gFSLoadAddress = 0;
86
87 //static BVRef getBootVolumeRef( const char * path, const char ** outPath );
88 static BVRef newBootVolumeRef( int biosdev, int partno );
89
90 //==========================================================================
91 // LoadVolumeFile - LOW-LEVEL FILESYSTEM FUNCTION.
92 // Load the specified file from the specified volume
93 // to the load buffer at LOAD_ADDR.
94 // If the file is fat, load only the i386 portion.
95
96 long LoadVolumeFile(BVRef bvr, const char *filePath)
97 {
98 long fileSize;
99
100 // Read file into load buffer. The data in the load buffer will be
101 // overwritten by the next LoadFile() call.
102
103 gFSLoadAddress = (void *) LOAD_ADDR;
104
105 fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
106
107 // Return the size of the file, or -1 if load failed.
108
109 return fileSize;
110 }
111
112 //==========================================================================
113 // LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
114 // Load the specified file to the load buffer at LOAD_ADDR.
115 // If the file is fat, load only the i386 portion.
116
117 long LoadFile(const char * fileSpec)
118 {
119 const char * filePath;
120 BVRef bvr;
121
122 // Resolve the boot volume from the file spec.
123
124 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
125 return -1;
126
127 return LoadVolumeFile(bvr, filePath);
128 }
129
130 long ReadFileAtOffset(const char * fileSpec, void *buffer, unsigned long offset, unsigned long length)
131 {
132 const char *filePath;
133 BVRef bvr;
134
135 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
136 return -1;
137
138 if (bvr->fs_readfile == NULL)
139 return -1;
140
141 return bvr->fs_readfile(bvr, (char *)filePath, buffer, offset, length);
142 }
143
144 long LoadThinFatFile(const char *fileSpec, void **binary)
145 {
146 const char *filePath;
147 FSReadFile readFile;
148 BVRef bvr;
149 unsigned long length, length2;
150
151 // Resolve the boot volume from the file spec.
152
153 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
154 return -1;
155
156 *binary = (void *)kLoadAddr;
157
158 // Read file into load buffer. The data in the load buffer will be
159 // overwritten by the next LoadFile() call.
160
161 gFSLoadAddress = (void *) LOAD_ADDR;
162
163 readFile = bvr->fs_readfile;
164
165 if (readFile != NULL) {
166 // Read the first 4096 bytes (fat header)
167 length = readFile(bvr, (char *)filePath, *binary, 0, 0x1000);
168 if (length > 0) {
169 if (ThinFatFile(binary, &length) == 0) {
170 // We found a fat binary; read only the thin part
171 length = readFile(bvr, (char *)filePath,
172 (void *)kLoadAddr, (unsigned long)(*binary) - kLoadAddr, length);
173 *binary = (void *)kLoadAddr;
174 } else {
175 // Not a fat binary; read the rest of the file
176 length2 = readFile(bvr, (char *)filePath, (void *)(kLoadAddr + length), length, 0);
177 if (length2 == -1) return -1;
178 length += length2;
179 }
180 }
181 } else {
182 length = bvr->fs_loadfile(bvr, (char *)filePath);
183 if (length > 0) {
184 ThinFatFile(binary, &length);
185 }
186 }
187
188 return length;
189 }
190
191 long GetFSUUID(char *spec, char *uuidStr)
192 {
193 BVRef bvr;
194 long rval = -1;
195 const char *devSpec;
196
197 if ((bvr = getBootVolumeRef(spec, &devSpec)) == NULL)
198 return -1;
199
200 if(bvr->fs_getuuid)
201 rval = bvr->fs_getuuid(bvr, uuidStr);
202
203 return rval;
204 }
205
206
207 // filesystem-specific getUUID functions call this shared string generator
208 long CreateUUIDString(uint8_t uubytes[], int nbytes, char *uuidStr)
209 {
210 unsigned fmtbase, fmtidx, i;
211 uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 };
212 char *p = uuidStr;
213 MD5_CTX md5c;
214 uint8_t mdresult[16];
215
216 bzero(mdresult, sizeof(mdresult));
217
218 // just like AppleFileSystemDriver
219 MD5Init(&md5c);
220 MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1));
221 MD5Update(&md5c, uubytes, nbytes);
222 MD5Final(mdresult, &md5c);
223
224 // this UUID has been made version 3 style (i.e. via namespace)
225 // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte)
226 mdresult[6] = 0x30 | ( mdresult[6] & 0x0F );
227 mdresult[8] = 0x80 | ( mdresult[8] & 0x3F );
228
229
230 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
231 i = 0; fmtbase = 0;
232 for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) {
233 for(i=0; i < uuidfmt[fmtidx]; i++) {
234 uint8_t byte = mdresult[fmtbase+i];
235 char nib;
236
237 nib = byte >> 4;
238 *p = nib + '0'; // 0x4 -> '4'
239 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
240 p++;
241
242 nib = byte & 0xf;
243 *p = nib + '0'; // 0x4 -> '4'
244 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
245 p++;
246
247 }
248 fmtbase += i;
249 if(fmtidx < sizeof(uuidfmt)-1)
250 *(p++) = '-';
251 else
252 *p = '\0';
253 }
254
255 return 0;
256 }
257
258
259 //==========================================================================
260 // GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
261 // Fetch the next directory entry for the given directory.
262
263 long GetDirEntry(const char * dirSpec, long * dirIndex, const char ** name,
264 long * flags, long * time)
265 {
266 const char * dirPath;
267 BVRef bvr;
268
269 // Resolve the boot volume from the dir spec.
270
271 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
272 return -1;
273
274 // Return 0 on success, or -1 if there are no additional entries.
275
276 return bvr->fs_getdirentry( bvr,
277 /* dirPath */ (char *)dirPath,
278 /* dirIndex */ dirIndex,
279 /* dirEntry */ (char **)name, flags, time, 0, 0 );
280 }
281
282 //==========================================================================
283 // GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
284 // Get attributes for the specified file.
285
286 static char* gMakeDirSpec;
287
288 long GetFileInfo(const char * dirSpec, const char * name,
289 long * flags, long * time)
290 {
291 long index = 0;
292 const char * entryName;
293
294 if (gMakeDirSpec == 0)
295 gMakeDirSpec = (char *)malloc(1024);
296
297 if (!dirSpec) {
298 long idx, len;
299
300 len = strlen(name);
301
302 for (idx = len; idx && (name[idx] != '/' && name[idx] != '\\'); idx--) {}
303 if (idx == 0) {
304 gMakeDirSpec[0] = '/';
305 gMakeDirSpec[1] = '\0';
306 } else {
307 idx++;
308 strncpy(gMakeDirSpec, name, idx);
309 name += idx;
310 }
311 dirSpec = gMakeDirSpec;
312 }
313
314 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
315 {
316 if (strcmp(entryName, name) == 0)
317 return 0; // success
318 }
319 return -1; // file not found
320 }
321
322 long GetFileBlock(const char *fileSpec, unsigned long long *firstBlock)
323 {
324 const char * filePath;
325 BVRef bvr;
326
327 // Resolve the boot volume from the file spec.
328
329 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) {
330 printf("Boot volume for '%s' is bogus\n", fileSpec);
331 return -1;
332 }
333
334 return bvr->fs_getfileblock(bvr, (char *)filePath, firstBlock);
335 }
336
337 //==========================================================================
338 // iob_from_fdesc()
339 //
340 // Return a pointer to an allocated 'iob' based on the file descriptor
341 // provided. Returns NULL if the file descriptor given is invalid.
342
343 static struct iob * iob_from_fdesc(int fdesc)
344 {
345 register struct iob * io;
346
347 if (fdesc < 0 || fdesc >= NFILES ||
348 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
349 return NULL;
350 else
351 return io;
352 }
353
354 #if UNUSED
355 //==========================================================================
356 // openmem()
357
358 int openmem(char * buf, int len)
359 {
360 int fdesc;
361 struct iob * io;
362
363 // Locate a free descriptor slot.
364
365 for (fdesc = 0; fdesc < NFILES; fdesc++)
366 if (iob[fdesc].i_flgs == 0)
367 goto gotfile;
368
369 stop("Out of file descriptors");
370
371 gotfile:
372 io = &iob[fdesc];
373 bzero(io, sizeof(*io));
374
375 // Mark the descriptor as taken. Set the F_MEM flag to indicate
376 // that the file buffer is provided by the caller.
377
378 io->i_flgs = F_ALLOC | F_MEM;
379 io->i_buf = buf;
380 io->i_filesize = len;
381
382 return fdesc;
383 }
384 #endif
385
386 //==========================================================================
387 // open() - Open the file specified by 'path' for reading.
388
389 int open(const char * path, int flags)
390 {
391 int fdesc, i;
392 struct iob * io;
393 const char * filePath;
394 BVRef bvr;
395
396 // Locate a free descriptor slot.
397
398 for (fdesc = 0; fdesc < NFILES; fdesc++)
399 if (iob[fdesc].i_flgs == 0)
400 goto gotfile;
401
402 stop("Out of file descriptors");
403
404 gotfile:
405 io = &iob[fdesc];
406 bzero(io, sizeof(*io));
407
408 // Mark the descriptor as taken.
409
410 io->i_flgs = F_ALLOC;
411
412 // Resolve the boot volume from the file spec.
413
414 if ((bvr = getBootVolumeRef(path, &filePath)) == NULL)
415 goto error;
416
417 // Find the next available memory block in the download buffer.
418
419 io->i_buf = (char *) LOAD_ADDR;
420 for (i = 0; i < NFILES; i++)
421 {
422 if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) continue;
423 io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
424 }
425
426 // Load entire file into memory. Unnecessary open() calls must
427 // be avoided.
428
429 gFSLoadAddress = io->i_buf;
430 io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
431 if (io->i_filesize < 0) {
432 goto error;
433 }
434
435 return fdesc;
436
437 error:
438 close(fdesc);
439 return -1;
440 }
441
442 //==========================================================================
443 // close() - Close a file descriptor.
444
445 int close(int fdesc)
446 {
447 struct iob * io;
448
449 if ((io = iob_from_fdesc(fdesc)) == NULL)
450 return (-1);
451
452 io->i_flgs = 0;
453
454 return 0;
455 }
456
457 //==========================================================================
458 // lseek() - Reposition the byte offset of the file descriptor from the
459 // beginning of the file. Returns the relocated offset.
460
461 int b_lseek(int fdesc, int offset, int ptr)
462 {
463 struct iob * io;
464
465 if ((io = iob_from_fdesc(fdesc)) == NULL)
466 return (-1);
467
468 io->i_offset = offset;
469
470 return offset;
471 }
472
473 //==========================================================================
474 // tell() - Returns the byte offset of the file descriptor.
475
476 int tell(int fdesc)
477 {
478 struct iob * io;
479
480 if ((io = iob_from_fdesc(fdesc)) == NULL)
481 return 0;
482
483 return io->i_offset;
484 }
485
486 //==========================================================================
487 // read() - Read up to 'count' bytes of data from the file descriptor
488 // into the buffer pointed to by buf.
489
490 int read(int fdesc, char * buf, int count)
491 {
492 struct iob * io;
493
494 if ((io = iob_from_fdesc(fdesc)) == NULL)
495 return (-1);
496
497 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
498 count = io->i_filesize - io->i_offset;
499
500 if (count <= 0)
501 return 0; // end of file
502
503 bcopy(io->i_buf + io->i_offset, buf, count);
504
505 io->i_offset += count;
506
507 return count;
508 }
509
510 //==========================================================================
511 // file_size() - Returns the size of the file described by the file
512 // descriptor.
513
514 int file_size(int fdesc)
515 {
516 struct iob * io;
517
518 if ((io = iob_from_fdesc(fdesc)) == 0)
519 return 0;
520
521 return io->i_filesize;
522 }
523
524 //==========================================================================
525
526 struct dirstuff * vol_opendir(BVRef bvr, const char * path)
527 {
528 struct dirstuff * dirp = 0;
529
530 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
531 if (dirp == NULL)
532 goto error;
533
534 dirp->dir_path = newString(path);
535 if (dirp->dir_path == NULL)
536 goto error;
537
538 dirp->dir_bvr = bvr;
539
540 return dirp;
541
542 error:
543 closedir(dirp);
544 return NULL;
545 }
546
547 //==========================================================================
548
549 struct dirstuff * opendir(const char * path)
550 {
551 struct dirstuff * dirp = 0;
552 const char * dirPath;
553 BVRef bvr;
554
555 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
556 goto error;
557
558 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
559 if (dirp == NULL)
560 goto error;
561
562 dirp->dir_path = newString(dirPath);
563 if (dirp->dir_path == NULL)
564 goto error;
565
566 dirp->dir_bvr = bvr;
567
568 return dirp;
569
570 error:
571 closedir(dirp);
572 return NULL;
573 }
574
575 //==========================================================================
576
577 int closedir(struct dirstuff * dirp)
578 {
579 if (dirp) {
580 if (dirp->dir_path) free(dirp->dir_path);
581 free(dirp);
582 }
583 return 0;
584 }
585
586 //==========================================================================
587
588 int readdir(struct dirstuff * dirp, const char ** name, long * flags,
589 long * time)
590 {
591 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
592 /* dirPath */ dirp->dir_path,
593 /* dirIndex */ &dirp->dir_index,
594 /* dirEntry */ (char **)name, flags, time,
595 0, 0);
596 }
597
598 //==========================================================================
599
600 int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
601 long * time, FinderInfo *finderInfo, long *infoValid)
602 {
603 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
604 /* dirPath */ dirp->dir_path,
605 /* dirIndex */ &dirp->dir_index,
606 /* dirEntry */ (char **)name,
607 flags, time,
608 finderInfo, infoValid);
609 }
610
611 //==========================================================================
612
613 int currentdev()
614 {
615 printf("currentdev = %d\n", bootInfo->kernDev);
616 return bootInfo->kernDev;
617 }
618
619 //==========================================================================
620
621 int switchdev(int dev)
622 {
623 bootInfo->kernDev = dev;
624 return dev;
625 }
626
627 //==========================================================================
628
629 const char * usrDevices()
630 {
631 if (gBootFileType == kNetworkDeviceType)
632 return "";
633 return "/private/Drivers/i386";
634 }
635
636 //==========================================================================
637
638 const char * systemConfigDir()
639 {
640 if (gBootFileType == kNetworkDeviceType)
641 return "";
642 return "/Library/Preferences/SystemConfiguration";
643 }
644
645 //==========================================================================
646
647 int gBootFileType;
648
649 BVRef scanBootVolumes( int biosdev, int * count )
650 {
651 BVRef bvr = 0;
652
653 bvr = diskScanBootVolumes(biosdev, count);
654 if (bvr == NULL) {
655 bvr = nbpScanBootVolumes(biosdev, count);
656 if (bvr != NULL) {
657 gBootFileType = kNetworkDeviceType;
658 }
659 } else {
660 gBootFileType = kBlockDeviceType;
661 }
662 return bvr;
663 }
664
665 //==========================================================================
666
667 BVRef selectBootVolume( BVRef chain )
668 {
669 BVRef bvr, bvr1 = 0, bvr2 = 0;
670
671 for ( bvr = chain; bvr; bvr = bvr->next )
672 {
673 if ( bvr->flags & kBVFlagNativeBoot ) bvr1 = bvr;
674 if ( bvr->flags & kBVFlagPrimary ) bvr2 = bvr;
675 }
676
677 bvr = bvr2 ? bvr2 :
678 bvr1 ? bvr1 : chain;
679
680 return bvr;
681 }
682
683 //==========================================================================
684
685 #define LP '('
686 #define RP ')'
687 int gBIOSDev;
688
689 BVRef getBootVolumeRef( const char * path, const char ** outPath )
690 {
691 const char * cp;
692 BVRef bvr;
693 int type = B_TYPE( bootInfo->kernDev );
694 int unit = B_UNIT( bootInfo->kernDev );
695 int part = B_PARTITION( bootInfo->kernDev );
696 int biosdev = gBIOSDev;
697 static BVRef lastBVR = 0;
698 static int lastKernDev;
699
700 // Search for left parenthesis in the path specification.
701
702 for (cp = path; *cp; cp++) {
703 if (*cp == LP || *cp == '/') break;
704 }
705
706 if (*cp != LP) // no left paren found
707 {
708 cp = path;
709 if ( lastBVR && lastKernDev == bootInfo->kernDev )
710 {
711 bvr = lastBVR;
712 goto quick_exit;
713 }
714 }
715 else if ((cp - path) == 2) // found "xx("
716 {
717 const struct devsw * dp;
718 const char * xp = path;
719 int i;
720
721 cp++;
722
723 // Check the 2 character device name pointed by 'xp'.
724
725 for (dp = devsw; dp->name; dp++)
726 {
727 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
728 break; // found matching entry
729 }
730 if (dp->name == NULL)
731 {
732 error("Unknown device '%c%c'\n", xp[0], xp[1]);
733 return NULL;
734 }
735 type = dp - devsw; // kerndev type
736
737 // Extract the optional unit number from the specification.
738 // hd(unit) or hd(unit, part).
739
740 i = 0;
741 while (*cp >= '0' && *cp <= '9')
742 {
743 i = i * 10 + *cp++ - '0';
744 unit = i;
745 }
746
747 // Extract the optional partition number from the specification.
748
749 if (*cp == ',')
750 part = atoi(++cp);
751
752 // Skip past the right paren.
753
754 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
755 if (*cp == RP) cp++;
756
757 biosdev = dp->biosdev + unit;
758 }
759 else
760 {
761 // Bad device specifier, skip past the right paren.
762
763 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
764 if (*cp == RP) cp++;
765 }
766
767 if ((bvr = newBootVolumeRef(biosdev, part)) == NULL)
768 {
769 // error("newBootVolumeRef() error\n");
770 return NULL;
771 }
772
773 // Record the most recent device parameters in the
774 // KernBootStruct.
775
776 bootInfo->kernDev = biosdev;
777
778 lastBVR = bvr;
779 lastKernDev = bootInfo->kernDev;
780
781 quick_exit:
782 // Returns the file path following the device spec.
783 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
784
785 *outPath = cp;
786
787 return bvr;
788 }
789
790 //==========================================================================
791
792 static BVRef newBootVolumeRef( int biosdev, int partno )
793 {
794 BVRef bvr, bvr1, bvrChain;
795
796 // Fetch the volume list from the device.
797
798 bvrChain = scanBootVolumes( biosdev, NULL );
799
800 // Look for a perfect match based on device and partition number.
801
802 for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
803 {
804 if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
805
806 bvr1 = bvr;
807 if ( bvr->part_no == partno ) break;
808 }
809
810 return bvr ? bvr : bvr1;
811 }