]>
git.saurik.com Git - apple/boot.git/blob - i386/libsaio/sys.c
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
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.
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
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.
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.
54 * @(#)sys.c 7.1 (Berkeley) 6/5/86
58 #include "bootstruct.h"
60 #include <uuid/uuid.h>
61 #include <Kernel/uuid/namespace.h>
65 unsigned char biosdev
;
69 static struct devsw devsw
[] =
71 { "sd", 0x80, kBIOSDevTypeHardDrive
}, /* DEV_SD */
72 { "hd", 0x80, kBIOSDevTypeHardDrive
}, /* DEV_HD */
73 { "fd", 0x00, kBIOSDevTypeFloppy
}, /* DEV_FD */
74 { "en", 0xE0, kBIOSDevTypeNetwork
}, /* DEV_EN */
79 * Max number of file descriptors.
83 static struct iob iob
[NFILES
];
85 void * gFSLoadAddress
= 0;
87 //static BVRef getBootVolumeRef( const char * path, const char ** outPath );
88 static BVRef
newBootVolumeRef( int biosdev
, int partno
);
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.
96 long LoadVolumeFile(BVRef bvr
, const char *filePath
)
100 // Read file into load buffer. The data in the load buffer will be
101 // overwritten by the next LoadFile() call.
103 gFSLoadAddress
= (void *) LOAD_ADDR
;
105 fileSize
= bvr
->fs_loadfile(bvr
, (char *)filePath
);
107 // Return the size of the file, or -1 if load failed.
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.
117 long LoadFile(const char * fileSpec
)
119 const char * filePath
;
122 // Resolve the boot volume from the file spec.
124 if ((bvr
= getBootVolumeRef(fileSpec
, &filePath
)) == NULL
)
127 return LoadVolumeFile(bvr
, filePath
);
130 long ReadFileAtOffset(const char * fileSpec
, void *buffer
, unsigned long offset
, unsigned long length
)
132 const char *filePath
;
135 if ((bvr
= getBootVolumeRef(fileSpec
, &filePath
)) == NULL
)
138 if (bvr
->fs_readfile
== NULL
)
141 return bvr
->fs_readfile(bvr
, (char *)filePath
, buffer
, offset
, length
);
144 long LoadThinFatFile(const char *fileSpec
, void **binary
)
146 const char *filePath
;
149 unsigned long length
, length2
;
151 // Resolve the boot volume from the file spec.
153 if ((bvr
= getBootVolumeRef(fileSpec
, &filePath
)) == NULL
)
156 *binary
= (void *)kLoadAddr
;
158 // Read file into load buffer. The data in the load buffer will be
159 // overwritten by the next LoadFile() call.
161 gFSLoadAddress
= (void *) LOAD_ADDR
;
163 readFile
= bvr
->fs_readfile
;
165 if (readFile
!= NULL
) {
166 // Read the first 4096 bytes (fat header)
167 length
= readFile(bvr
, (char *)filePath
, *binary
, 0, 0x1000);
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
;
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;
182 length
= bvr
->fs_loadfile(bvr
, (char *)filePath
);
184 ThinFatFile(binary
, &length
);
191 long GetFSUUID(char *spec
, char *uuidStr
)
197 if ((bvr
= getBootVolumeRef(spec
, &devSpec
)) == NULL
)
201 rval
= bvr
->fs_getuuid(bvr
, uuidStr
);
207 // filesystem-specific getUUID functions call this shared string generator
208 long CreateUUIDString(uint8_t uubytes
[], int nbytes
, char *uuidStr
)
210 unsigned fmtbase
, fmtidx
, i
;
211 uint8_t uuidfmt
[] = { 4, 2, 2, 2, 6 };
214 uint8_t mdresult
[16];
216 bzero(mdresult
, sizeof(mdresult
));
218 // just like AppleFileSystemDriver
220 MD5Update(&md5c
, kFSUUIDNamespaceSHA1
, sizeof(kFSUUIDNamespaceSHA1
));
221 MD5Update(&md5c
, uubytes
, nbytes
);
222 MD5Final(mdresult
, &md5c
);
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 );
230 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
232 for(fmtidx
= 0; fmtidx
< sizeof(uuidfmt
); fmtidx
++) {
233 for(i
=0; i
< uuidfmt
[fmtidx
]; i
++) {
234 uint8_t byte
= mdresult
[fmtbase
+i
];
238 *p
= nib
+ '0'; // 0x4 -> '4'
239 if(*p
> '9') *p
= (nib
- 9 + ('A'-1)); // 0xB -> 'B'
243 *p
= nib
+ '0'; // 0x4 -> '4'
244 if(*p
> '9') *p
= (nib
- 9 + ('A'-1)); // 0xB -> 'B'
249 if(fmtidx
< sizeof(uuidfmt
)-1)
259 //==========================================================================
260 // GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
261 // Fetch the next directory entry for the given directory.
263 long GetDirEntry(const char * dirSpec
, long * dirIndex
, const char ** name
,
264 long * flags
, long * time
)
266 const char * dirPath
;
269 // Resolve the boot volume from the dir spec.
271 if ((bvr
= getBootVolumeRef(dirSpec
, &dirPath
)) == NULL
)
274 // Return 0 on success, or -1 if there are no additional entries.
276 return bvr
->fs_getdirentry( bvr
,
277 /* dirPath */ (char *)dirPath
,
278 /* dirIndex */ dirIndex
,
279 /* dirEntry */ (char **)name
, flags
, time
, 0, 0 );
282 //==========================================================================
283 // GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
284 // Get attributes for the specified file.
286 static char* gMakeDirSpec
;
288 long GetFileInfo(const char * dirSpec
, const char * name
,
289 long * flags
, long * time
)
292 const char * entryName
;
294 if (gMakeDirSpec
== 0)
295 gMakeDirSpec
= (char *)malloc(1024);
302 for (idx
= len
; idx
&& (name
[idx
] != '/' && name
[idx
] != '\\'); idx
--) {}
304 gMakeDirSpec
[0] = '/';
305 gMakeDirSpec
[1] = '\0';
308 strncpy(gMakeDirSpec
, name
, idx
);
311 dirSpec
= gMakeDirSpec
;
314 while (GetDirEntry(dirSpec
, &index
, &entryName
, flags
, time
) == 0)
316 if (strcmp(entryName
, name
) == 0)
319 return -1; // file not found
322 long GetFileBlock(const char *fileSpec
, unsigned long long *firstBlock
)
324 const char * filePath
;
327 // Resolve the boot volume from the file spec.
329 if ((bvr
= getBootVolumeRef(fileSpec
, &filePath
)) == NULL
) {
330 printf("Boot volume for '%s' is bogus\n", fileSpec
);
334 return bvr
->fs_getfileblock(bvr
, (char *)filePath
, firstBlock
);
337 //==========================================================================
340 // Return a pointer to an allocated 'iob' based on the file descriptor
341 // provided. Returns NULL if the file descriptor given is invalid.
343 static struct iob
* iob_from_fdesc(int fdesc
)
345 register struct iob
* io
;
347 if (fdesc
< 0 || fdesc
>= NFILES
||
348 ((io
= &iob
[fdesc
])->i_flgs
& F_ALLOC
) == 0)
355 //==========================================================================
358 int openmem(char * buf
, int len
)
363 // Locate a free descriptor slot.
365 for (fdesc
= 0; fdesc
< NFILES
; fdesc
++)
366 if (iob
[fdesc
].i_flgs
== 0)
369 stop("Out of file descriptors");
373 bzero(io
, sizeof(*io
));
375 // Mark the descriptor as taken. Set the F_MEM flag to indicate
376 // that the file buffer is provided by the caller.
378 io
->i_flgs
= F_ALLOC
| F_MEM
;
380 io
->i_filesize
= len
;
386 //==========================================================================
387 // open() - Open the file specified by 'path' for reading.
389 int open(const char * path
, int flags
)
393 const char * filePath
;
396 // Locate a free descriptor slot.
398 for (fdesc
= 0; fdesc
< NFILES
; fdesc
++)
399 if (iob
[fdesc
].i_flgs
== 0)
402 stop("Out of file descriptors");
406 bzero(io
, sizeof(*io
));
408 // Mark the descriptor as taken.
410 io
->i_flgs
= F_ALLOC
;
412 // Resolve the boot volume from the file spec.
414 if ((bvr
= getBootVolumeRef(path
, &filePath
)) == NULL
)
417 // Find the next available memory block in the download buffer.
419 io
->i_buf
= (char *) LOAD_ADDR
;
420 for (i
= 0; i
< NFILES
; i
++)
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
);
426 // Load entire file into memory. Unnecessary open() calls must
429 gFSLoadAddress
= io
->i_buf
;
430 io
->i_filesize
= bvr
->fs_loadfile(bvr
, (char *)filePath
);
431 if (io
->i_filesize
< 0) {
442 //==========================================================================
443 // close() - Close a file descriptor.
449 if ((io
= iob_from_fdesc(fdesc
)) == NULL
)
457 //==========================================================================
458 // lseek() - Reposition the byte offset of the file descriptor from the
459 // beginning of the file. Returns the relocated offset.
461 int b_lseek(int fdesc
, int offset
, int ptr
)
465 if ((io
= iob_from_fdesc(fdesc
)) == NULL
)
468 io
->i_offset
= offset
;
473 //==========================================================================
474 // tell() - Returns the byte offset of the file descriptor.
480 if ((io
= iob_from_fdesc(fdesc
)) == NULL
)
486 //==========================================================================
487 // read() - Read up to 'count' bytes of data from the file descriptor
488 // into the buffer pointed to by buf.
490 int read(int fdesc
, char * buf
, int count
)
494 if ((io
= iob_from_fdesc(fdesc
)) == NULL
)
497 if ((io
->i_offset
+ count
) > (unsigned int)io
->i_filesize
)
498 count
= io
->i_filesize
- io
->i_offset
;
501 return 0; // end of file
503 bcopy(io
->i_buf
+ io
->i_offset
, buf
, count
);
505 io
->i_offset
+= count
;
510 //==========================================================================
511 // file_size() - Returns the size of the file described by the file
514 int file_size(int fdesc
)
518 if ((io
= iob_from_fdesc(fdesc
)) == 0)
521 return io
->i_filesize
;
524 //==========================================================================
526 struct dirstuff
* vol_opendir(BVRef bvr
, const char * path
)
528 struct dirstuff
* dirp
= 0;
530 dirp
= (struct dirstuff
*) malloc(sizeof(struct dirstuff
));
534 dirp
->dir_path
= newString(path
);
535 if (dirp
->dir_path
== NULL
)
547 //==========================================================================
549 struct dirstuff
* opendir(const char * path
)
551 struct dirstuff
* dirp
= 0;
552 const char * dirPath
;
555 if ((bvr
= getBootVolumeRef(path
, &dirPath
)) == NULL
)
558 dirp
= (struct dirstuff
*) malloc(sizeof(struct dirstuff
));
562 dirp
->dir_path
= newString(dirPath
);
563 if (dirp
->dir_path
== NULL
)
575 //==========================================================================
577 int closedir(struct dirstuff
* dirp
)
580 if (dirp
->dir_path
) free(dirp
->dir_path
);
586 //==========================================================================
588 int readdir(struct dirstuff
* dirp
, const char ** name
, long * flags
,
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
,
598 //==========================================================================
600 int readdir_ext(struct dirstuff
* dirp
, const char ** name
, long * flags
,
601 long * time
, FinderInfo
*finderInfo
, long *infoValid
)
603 return dirp
->dir_bvr
->fs_getdirentry( dirp
->dir_bvr
,
604 /* dirPath */ dirp
->dir_path
,
605 /* dirIndex */ &dirp
->dir_index
,
606 /* dirEntry */ (char **)name
,
608 finderInfo
, infoValid
);
611 //==========================================================================
615 printf("currentdev = %d\n", bootInfo
->kernDev
);
616 return bootInfo
->kernDev
;
619 //==========================================================================
621 int switchdev(int dev
)
623 bootInfo
->kernDev
= dev
;
627 //==========================================================================
629 const char * usrDevices()
631 if (gBootFileType
== kNetworkDeviceType
)
633 return "/private/Drivers/i386";
636 //==========================================================================
638 const char * systemConfigDir()
640 if (gBootFileType
== kNetworkDeviceType
)
642 return "/Library/Preferences/SystemConfiguration";
645 //==========================================================================
649 BVRef
scanBootVolumes( int biosdev
, int * count
)
653 bvr
= diskScanBootVolumes(biosdev
, count
);
655 bvr
= nbpScanBootVolumes(biosdev
, count
);
657 gBootFileType
= kNetworkDeviceType
;
660 gBootFileType
= kBlockDeviceType
;
665 //==========================================================================
667 BVRef
selectBootVolume( BVRef chain
)
669 BVRef bvr
, bvr1
= 0, bvr2
= 0;
671 for ( bvr
= chain
; bvr
; bvr
= bvr
->next
)
673 if ( bvr
->flags
& kBVFlagNativeBoot
) bvr1
= bvr
;
674 if ( bvr
->flags
& kBVFlagPrimary
) bvr2
= bvr
;
683 //==========================================================================
689 BVRef
getBootVolumeRef( const char * path
, const char ** outPath
)
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
;
700 // Search for left parenthesis in the path specification.
702 for (cp
= path
; *cp
; cp
++) {
703 if (*cp
== LP
|| *cp
== '/') break;
706 if (*cp
!= LP
) // no left paren found
709 if ( lastBVR
&& lastKernDev
== bootInfo
->kernDev
)
715 else if ((cp
- path
) == 2) // found "xx("
717 const struct devsw
* dp
;
718 const char * xp
= path
;
723 // Check the 2 character device name pointed by 'xp'.
725 for (dp
= devsw
; dp
->name
; dp
++)
727 if ((xp
[0] == dp
->name
[0]) && (xp
[1] == dp
->name
[1]))
728 break; // found matching entry
730 if (dp
->name
== NULL
)
732 error("Unknown device '%c%c'\n", xp
[0], xp
[1]);
735 type
= dp
- devsw
; // kerndev type
737 // Extract the optional unit number from the specification.
738 // hd(unit) or hd(unit, part).
741 while (*cp
>= '0' && *cp
<= '9')
743 i
= i
* 10 + *cp
++ - '0';
747 // Extract the optional partition number from the specification.
752 // Skip past the right paren.
754 for ( ; *cp
&& *cp
!= RP
; cp
++) /* LOOP */;
757 biosdev
= dp
->biosdev
+ unit
;
761 // Bad device specifier, skip past the right paren.
763 for ( cp
++; *cp
&& *cp
!= RP
; cp
++) /* LOOP */;
767 if ((bvr
= newBootVolumeRef(biosdev
, part
)) == NULL
)
769 // error("newBootVolumeRef() error\n");
773 // Record the most recent device parameters in the
776 bootInfo
->kernDev
= biosdev
;
779 lastKernDev
= bootInfo
->kernDev
;
782 // Returns the file path following the device spec.
783 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
790 //==========================================================================
792 static BVRef
newBootVolumeRef( int biosdev
, int partno
)
794 BVRef bvr
, bvr1
, bvrChain
;
796 // Fetch the volume list from the device.
798 bvrChain
= scanBootVolumes( biosdev
, NULL
);
800 // Look for a perfect match based on device and partition number.
802 for ( bvr1
= NULL
, bvr
= bvrChain
; bvr
; bvr
= bvr
->next
)
804 if ( ( bvr
->flags
& kBVFlagNativeBoot
) == 0 ) continue;
807 if ( bvr
->part_no
== partno
) break;
810 return bvr
? bvr
: bvr1
;