]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/sys.c
boot-111.tar.gz
[apple/boot.git] / i386 / libsaio / sys.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Mach Operating System
27 * Copyright (c) 1990 Carnegie-Mellon University
28 * Copyright (c) 1989 Carnegie-Mellon University
29 * Copyright (c) 1988 Carnegie-Mellon University
30 * Copyright (c) 1987 Carnegie-Mellon University
31 * All rights reserved. The CMU software License Agreement specifies
32 * the terms and conditions for use and redistribution.
33 *
34 */
35 /*
36 * HISTORY
37 * Revision 2.3 88/08/08 13:47:07 rvb
38 * Allocate buffers dynamically vs statically.
39 * Now b[i] and i_fs and i_buf, are allocated dynamically.
40 * boot_calloc(size) allocates and zeros a buffer rounded to a NPG
41 * boundary.
42 * Generalize boot spec to allow, xx()/mach, xx(n,[a..h])/mach,
43 * xx([a..h])/mach, ...
44 * Also default "xx" if unspecified and alloc just "/mach",
45 * where everything is defaulted
46 * Add routine, ptol(), to parse partition letters.
47 *
48 */
49
50 /*
51 * Copyright (c) 1982, 1986 Regents of the University of California.
52 * All rights reserved. The Berkeley software License Agreement
53 * specifies the terms and conditions for redistribution.
54 *
55 * @(#)sys.c 7.1 (Berkeley) 6/5/86
56 */
57
58 #include "libsaio.h"
59 #include "bootstruct.h"
60
61
62 struct devsw {
63 const char * name;
64 unsigned char biosdev;
65 int type;
66 };
67
68 static struct devsw devsw[] =
69 {
70 { "sd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_SD */
71 { "hd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_HD */
72 { "fd", 0x00, kBIOSDevTypeFloppy }, /* DEV_FD */
73 { "en", 0xE0, kBIOSDevTypeNetwork }, /* DEV_EN */
74 { 0, 0 }
75 };
76
77 /*
78 * Max number of file descriptors.
79 */
80 #define NFILES 6
81
82 static struct iob iob[NFILES];
83
84 void * gFSLoadAddress = 0;
85
86 static BVRef getBootVolumeRef( const char * path, const char ** outPath );
87 static BVRef newBootVolumeRef( int biosdev, int partno );
88
89 //==========================================================================
90 // LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
91 // Load the specified file to the load buffer at LOAD_ADDR.
92 // If the file is fat, load only the i386 portion.
93
94 long LoadFile(const char * fileSpec)
95 {
96 const char * filePath;
97 long fileSize;
98 BVRef bvr;
99
100 // Resolve the boot volume from the file spec.
101
102 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
103 return -1;
104
105 // Read file into load buffer. The data in the load buffer will be
106 // overwritten by the next LoadFile() call.
107
108 gFSLoadAddress = (void *) LOAD_ADDR;
109
110 fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
111
112 // Return the size of the file, or -1 if load failed.
113
114 return fileSize;
115 }
116
117 //==========================================================================
118 // GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
119 // Fetch the next directory entry for the given directory.
120
121 long GetDirEntry(const char * dirSpec, long * dirIndex, const char ** name,
122 long * flags, long * time)
123 {
124 const char * dirPath;
125 BVRef bvr;
126
127 // Resolve the boot volume from the dir spec.
128
129 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
130 return -1;
131
132 // Return 0 on success, or -1 if there are no additional entries.
133
134 return bvr->fs_getdirentry( bvr,
135 /* dirPath */ (char *)dirPath,
136 /* dirIndex */ dirIndex,
137 /* dirEntry */ (char **)name, flags, time );
138 }
139
140 //==========================================================================
141 // GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
142 // Get attributes for the specified file.
143
144 static char gMakeDirSpec[1024];
145
146 long GetFileInfo(const char * dirSpec, const char * name,
147 long * flags, long * time)
148 {
149 long index = 0;
150 const char * entryName;
151
152 if (!dirSpec) {
153 long idx, len;
154
155 len = strlen(name);
156
157 for (idx = len; idx && (name[idx] != '/' && name[idx] != '\\'); idx--) {}
158 if (idx == 0) {
159 gMakeDirSpec[0] = '/';
160 gMakeDirSpec[1] = '\0';
161 } else {
162 idx++;
163 strncpy(gMakeDirSpec, name, idx);
164 name += idx;
165 }
166 dirSpec = gMakeDirSpec;
167 }
168
169 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
170 {
171 if (strcmp(entryName, name) == 0)
172 return 0; // success
173 }
174 return -1; // file not found
175 }
176
177 //==========================================================================
178 // iob_from_fdesc()
179 //
180 // Return a pointer to an allocated 'iob' based on the file descriptor
181 // provided. Returns NULL if the file descriptor given is invalid.
182
183 static struct iob * iob_from_fdesc(int fdesc)
184 {
185 register struct iob * io;
186
187 if (fdesc < 0 || fdesc >= NFILES ||
188 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
189 return NULL;
190 else
191 return io;
192 }
193
194 //==========================================================================
195 // openmem()
196
197 int openmem(char * buf, int len)
198 {
199 int fdesc;
200 struct iob * io;
201
202 // Locate a free descriptor slot.
203
204 for (fdesc = 0; fdesc < NFILES; fdesc++)
205 if (iob[fdesc].i_flgs == 0)
206 goto gotfile;
207
208 stop("Out of file descriptors");
209
210 gotfile:
211 io = &iob[fdesc];
212 bzero(io, sizeof(*io));
213
214 // Mark the descriptor as taken. Set the F_MEM flag to indicate
215 // that the file buffer is provided by the caller.
216
217 io->i_flgs = F_ALLOC | F_MEM;
218 io->i_buf = buf;
219 io->i_filesize = len;
220
221 return fdesc;
222 }
223
224 //==========================================================================
225 // open() - Open the file specified by 'path' for reading.
226
227 int open(const char * path, int flags)
228 {
229 int fdesc, i;
230 struct iob * io;
231 const char * filePath;
232 BVRef bvr;
233
234 // Locate a free descriptor slot.
235
236 for (fdesc = 0; fdesc < NFILES; fdesc++)
237 if (iob[fdesc].i_flgs == 0)
238 goto gotfile;
239
240 stop("Out of file descriptors");
241
242 gotfile:
243 io = &iob[fdesc];
244 bzero(io, sizeof(*io));
245
246 // Mark the descriptor as taken.
247
248 io->i_flgs = F_ALLOC;
249
250 // Resolve the boot volume from the file spec.
251
252 if ((bvr = getBootVolumeRef(path, &filePath)) == NULL)
253 goto error;
254
255 // Find the next available memory block in the download buffer.
256
257 io->i_buf = (char *) LOAD_ADDR;
258 for (i = 0; i < NFILES; i++)
259 {
260 if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) continue;
261 io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
262 }
263
264 // Load entire file into memory. Unnecessary open() calls must
265 // be avoided.
266
267 gFSLoadAddress = io->i_buf;
268 io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
269 if (io->i_filesize < 0) {
270 goto error;
271 }
272
273 return fdesc;
274
275 error:
276 close(fdesc);
277 return -1;
278 }
279
280 //==========================================================================
281 // close() - Close a file descriptor.
282
283 int close(int fdesc)
284 {
285 struct iob * io;
286
287 if ((io = iob_from_fdesc(fdesc)) == NULL)
288 return (-1);
289
290 io->i_flgs = 0;
291
292 return 0;
293 }
294
295 //==========================================================================
296 // lseek() - Reposition the byte offset of the file descriptor from the
297 // beginning of the file. Returns the relocated offset.
298
299 int b_lseek(int fdesc, int offset, int ptr)
300 {
301 struct iob * io;
302
303 if ((io = iob_from_fdesc(fdesc)) == NULL)
304 return (-1);
305
306 io->i_offset = offset;
307
308 return offset;
309 }
310
311 //==========================================================================
312 // tell() - Returns the byte offset of the file descriptor.
313
314 int tell(int fdesc)
315 {
316 struct iob * io;
317
318 if ((io = iob_from_fdesc(fdesc)) == NULL)
319 return 0;
320
321 return io->i_offset;
322 }
323
324 //==========================================================================
325 // read() - Read up to 'count' bytes of data from the file descriptor
326 // into the buffer pointed to by buf.
327
328 int read(int fdesc, char * buf, int count)
329 {
330 struct iob * io;
331
332 if ((io = iob_from_fdesc(fdesc)) == NULL)
333 return (-1);
334
335 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
336 count = io->i_filesize - io->i_offset;
337
338 if (count <= 0)
339 return 0; // end of file
340
341 bcopy(io->i_buf + io->i_offset, buf, count);
342
343 io->i_offset += count;
344
345 return count;
346 }
347
348 //==========================================================================
349 // file_size() - Returns the size of the file described by the file
350 // descriptor.
351
352 int file_size(int fdesc)
353 {
354 struct iob * io;
355
356 if ((io = iob_from_fdesc(fdesc)) == 0)
357 return 0;
358
359 return io->i_filesize;
360 }
361
362 //==========================================================================
363
364 struct dirstuff * opendir(const char * path)
365 {
366 struct dirstuff * dirp = 0;
367 const char * dirPath;
368 BVRef bvr;
369
370 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
371 goto error;
372
373 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
374 if (dirp == NULL)
375 goto error;
376
377 dirp->dir_path = newString(dirPath);
378 if (dirp->dir_path == NULL)
379 goto error;
380
381 dirp->dir_bvr = bvr;
382
383 return dirp;
384
385 error:
386 closedir(dirp);
387 return NULL;
388 }
389
390 //==========================================================================
391
392 int closedir(struct dirstuff * dirp)
393 {
394 if (dirp) {
395 if (dirp->dir_path) free(dirp->dir_path);
396 free(dirp);
397 }
398 return 0;
399 }
400
401 //==========================================================================
402
403 int readdir(struct dirstuff * dirp, const char ** name, long * flags,
404 long * time)
405 {
406 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
407 /* dirPath */ dirp->dir_path,
408 /* dirIndex */ &dirp->dir_index,
409 /* dirEntry */ (char **)name, flags, time );
410 }
411
412 //==========================================================================
413
414 int currentdev()
415 {
416 return bootArgs->kernDev;
417 }
418
419 //==========================================================================
420
421 int switchdev(int dev)
422 {
423 bootArgs->kernDev = dev;
424 return dev;
425 }
426
427 //==========================================================================
428
429 const char * usrDevices()
430 {
431 if (gBootFileType == kNetworkDeviceType)
432 return "";
433 return "/private/Drivers/i386";
434 }
435
436 //==========================================================================
437
438 const char * systemConfigDir()
439 {
440 if (gBootFileType == kNetworkDeviceType)
441 return "";
442 return "/Library/Preferences/SystemConfiguration";
443 }
444
445 //==========================================================================
446
447 int gBootFileType;
448
449 BVRef scanBootVolumes( int biosdev, int * count )
450 {
451 BVRef bvr = 0;
452
453 bvr = diskScanBootVolumes(biosdev, count);
454 if (bvr == NULL) {
455 bvr = nbpScanBootVolumes(biosdev, count);
456 if (bvr != NULL) {
457 gBootFileType = kNetworkDeviceType;
458 }
459 } else {
460 gBootFileType = kBlockDeviceType;
461 }
462 return bvr;
463 }
464
465 //==========================================================================
466
467 void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen )
468 {
469 bvr->description( bvr, str, strMaxLen );
470 }
471
472 //==========================================================================
473
474 BVRef selectBootVolume( BVRef chain )
475 {
476 BVRef bvr, bvr1 = 0, bvr2 = 0;
477
478 for ( bvr = chain; bvr; bvr = bvr->next )
479 {
480 if ( bvr->flags & kBVFlagNativeBoot ) bvr1 = bvr;
481 if ( bvr->flags & kBVFlagPrimary ) bvr2 = bvr;
482 }
483
484 bvr = bvr2 ? bvr2 :
485 bvr1 ? bvr1 : chain;
486
487 return bvr;
488 }
489
490 //==========================================================================
491
492 #define LP '('
493 #define RP ')'
494 int gBIOSDev;
495
496 static BVRef getBootVolumeRef( const char * path, const char ** outPath )
497 {
498 const char * cp;
499 BVRef bvr;
500 int type = B_TYPE( bootArgs->kernDev );
501 int unit = B_UNIT( bootArgs->kernDev );
502 int part = B_PARTITION( bootArgs->kernDev );
503 int biosdev = gBIOSDev;
504 static BVRef lastBVR = 0;
505 static int lastKernDev;
506
507 // Search for left parenthesis in the path specification.
508
509 for (cp = path; *cp; cp++) {
510 if (*cp == LP || *cp == '/') break;
511 }
512
513 if (*cp != LP) // no left paren found
514 {
515 cp = path;
516 if ( lastBVR && lastKernDev == bootArgs->kernDev )
517 {
518 bvr = lastBVR;
519 goto quick_exit;
520 }
521 }
522 else if ((cp - path) == 2) // found "xx("
523 {
524 const struct devsw * dp;
525 const char * xp = path;
526 int i;
527
528 cp++;
529
530 // Check the 2 character device name pointed by 'xp'.
531
532 for (dp = devsw; dp->name; dp++)
533 {
534 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
535 break; // found matching entry
536 }
537 if (dp->name == NULL)
538 {
539 error("Unknown device '%c%c'\n", xp[0], xp[1]);
540 return NULL;
541 }
542 type = dp - devsw; // kerndev type
543
544 // Extract the optional unit number from the specification.
545 // hd(unit) or hd(unit, part).
546
547 i = 0;
548 while (*cp >= '0' && *cp <= '9')
549 {
550 i = i * 10 + *cp++ - '0';
551 unit = i;
552 }
553
554 // Extract the optional partition number from the specification.
555
556 if (*cp == ',')
557 part = atoi(++cp);
558
559 // Skip past the right paren.
560
561 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
562 if (*cp == RP) cp++;
563
564 biosdev = dp->biosdev + unit;
565 }
566 else
567 {
568 // Bad device specifier, skip past the right paren.
569
570 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
571 if (*cp == RP) cp++;
572 }
573
574 if ((bvr = newBootVolumeRef(biosdev, part)) == NULL)
575 {
576 // error("newBootVolumeRef() error\n");
577 return NULL;
578 }
579
580 // Record the most recent device parameters in the
581 // KernBootStruct.
582
583 bootArgs->kernDev = biosdev;
584
585 lastBVR = bvr;
586 lastKernDev = bootArgs->kernDev;
587
588 quick_exit:
589 // Returns the file path following the device spec.
590 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
591
592 *outPath = cp;
593
594 return bvr;
595 }
596
597 //==========================================================================
598
599 static BVRef newBootVolumeRef( int biosdev, int partno )
600 {
601 BVRef bvr, bvr1, bvrChain;
602
603 // Fetch the volume list from the device.
604
605 bvrChain = scanBootVolumes( biosdev, NULL );
606
607 // Look for a perfect match based on device and partition number.
608
609 for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
610 {
611 if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
612
613 bvr1 = bvr;
614 if ( bvr->part_no == partno ) break;
615 }
616
617 return bvr ? bvr : bvr1;
618 }