]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/sys.c
b4e88ed56b0d9d3aeb812240e6ea3ff7b237fb14
[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 * Portions Copyright (c) 1999 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 1.1 (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
59 struct devsw {
60 const char * name;
61 unsigned char biosdev;
62 };
63
64 static struct devsw devsw[] =
65 {
66 { "sd", 0x80 }, /* DEV_SD */
67 { "hd", 0x80 }, /* DEV_HD */
68 { "fd", 0x00 }, /* DEV_FD */
69 { "en", 0xE0 }, /* DEV_EN */
70 { 0, 0 }
71 };
72
73 /*
74 * Max number of file descriptors.
75 */
76 #define NFILES 6
77
78 static struct iob iob[NFILES];
79
80 void * gFSLoadAddress = 0;
81
82 static BVRef getBootVolumeRef( const char * path, const char ** outPath );
83 static BVRef newBootVolumeRef( int biosdev, int partno );
84
85 //==========================================================================
86 // LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
87 // Load the specified file to the load buffer at LOAD_ADDR.
88
89 long LoadFile(const char * fileSpec)
90 {
91 const char * filePath;
92 long fileSize;
93 BVRef bvr;
94
95 // Resolve the boot volume from the file spec.
96
97 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
98 return -1;
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 // GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
114 // Fetch the next directory entry for the given directory.
115
116 long GetDirEntry(const char * dirSpec, long * dirIndex, const char ** name,
117 long * flags, long * time)
118 {
119 const char * dirPath;
120 BVRef bvr;
121
122 // Resolve the boot volume from the dir spec.
123
124 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
125 return -1;
126
127 // Return 0 on success, or -1 if there are no additional entries.
128
129 return bvr->fs_getdirentry( bvr,
130 /* dirPath */ (char *)dirPath,
131 /* dirIndex */ dirIndex,
132 /* dirEntry */ (char **)name, flags, time );
133 }
134
135 //==========================================================================
136 // GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
137 // Get attributes for the specified file.
138
139 long GetFileInfo(const char * dirSpec, const char * name,
140 long * flags, long * time)
141 {
142 long index = 0;
143 const char * entryName;
144
145 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
146 {
147 if (strcmp(entryName, name) == 0)
148 return 0; // success
149 }
150 return -1; // file not found
151 }
152
153 //==========================================================================
154 // iob_from_fdesc()
155 //
156 // Return a pointer to an allocated 'iob' based on the file descriptor
157 // provided. Returns NULL if the file descriptor given is invalid.
158
159 static struct iob * iob_from_fdesc(int fdesc)
160 {
161 register struct iob * io;
162
163 if (fdesc < 0 || fdesc >= NFILES ||
164 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
165 return NULL;
166 else
167 return io;
168 }
169
170 //==========================================================================
171 // openmem()
172
173 int openmem(char * buf, int len)
174 {
175 int fdesc;
176 struct iob * io;
177
178 // Locate a free descriptor slot.
179
180 for (fdesc = 0; fdesc < NFILES; fdesc++)
181 if (iob[fdesc].i_flgs == 0)
182 goto gotfile;
183
184 stop("Out of file descriptors");
185
186 gotfile:
187 io = &iob[fdesc];
188 bzero(io, sizeof(*io));
189
190 // Mark the descriptor as taken. Set the F_MEM flag to indicate
191 // that the file buffer is provided by the caller.
192
193 io->i_flgs = F_ALLOC | F_MEM;
194 io->i_buf = buf;
195 io->i_filesize = len;
196
197 return fdesc;
198 }
199
200 //==========================================================================
201 // open() - Open the file specified by 'path' for reading.
202
203 int open(const char * path, int flags)
204 {
205 int fdesc, i;
206 struct iob * io;
207 const char * filePath;
208 BVRef bvr;
209
210 // Locate a free descriptor slot.
211
212 for (fdesc = 0; fdesc < NFILES; fdesc++)
213 if (iob[fdesc].i_flgs == 0)
214 goto gotfile;
215
216 stop("Out of file descriptors");
217
218 gotfile:
219 io = &iob[fdesc];
220 bzero(io, sizeof(*io));
221
222 // Mark the descriptor as taken.
223
224 io->i_flgs = F_ALLOC;
225
226 // Resolve the boot volume from the file spec.
227
228 if ((bvr = getBootVolumeRef(path, &filePath)) == NULL)
229 goto error;
230
231 // Find the next available memory block in the download buffer.
232
233 io->i_buf = (char *) LOAD_ADDR;
234 for (i = 0; i < NFILES; i++)
235 {
236 if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) continue;
237 io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
238 }
239
240 // Load entire file into memory. Unnecessary open() calls must
241 // be avoided.
242
243 gFSLoadAddress = io->i_buf;
244 io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
245 if (io->i_filesize < 0) goto error;
246
247 return fdesc;
248
249 error:
250 close(fdesc);
251 return -1;
252 }
253
254 //==========================================================================
255 // close() - Close a file descriptor.
256
257 int close(int fdesc)
258 {
259 struct iob * io;
260
261 if ((io = iob_from_fdesc(fdesc)) == NULL)
262 return (-1);
263
264 io->i_flgs = 0;
265
266 return 0;
267 }
268
269 //==========================================================================
270 // lseek() - Reposition the byte offset of the file descriptor from the
271 // beginning of the file. Returns the relocated offset.
272
273 int b_lseek(int fdesc, int offset, int ptr)
274 {
275 struct iob * io;
276
277 if ((io = iob_from_fdesc(fdesc)) == NULL)
278 return (-1);
279
280 io->i_offset = offset;
281
282 return offset;
283 }
284
285 //==========================================================================
286 // tell() - Returns the byte offset of the file descriptor.
287
288 int tell(int fdesc)
289 {
290 struct iob * io;
291
292 if ((io = iob_from_fdesc(fdesc)) == NULL)
293 return 0;
294
295 return io->i_offset;
296 }
297
298 //==========================================================================
299 // read() - Read up to 'count' bytes of data from the file descriptor
300 // into the buffer pointed to by buf.
301
302 int read(int fdesc, char * buf, int count)
303 {
304 struct iob * io;
305
306 if ((io = iob_from_fdesc(fdesc)) == NULL)
307 return (-1);
308
309 if (io->i_offset + count > io->i_filesize)
310 count = io->i_filesize - io->i_offset;
311
312 if (count <= 0)
313 return 0; // end of file
314
315 bcopy(io->i_buf + io->i_offset, buf, count);
316
317 io->i_offset += count;
318
319 return count;
320 }
321
322 //==========================================================================
323 // file_size() - Returns the size of the file described by the file
324 // descriptor.
325
326 int file_size(int fdesc)
327 {
328 struct iob * io;
329
330 if ((io = iob_from_fdesc(fdesc)) == 0)
331 return 0;
332
333 return io->i_filesize;
334 }
335
336 //==========================================================================
337
338 struct dirstuff * opendir(const char * path)
339 {
340 struct dirstuff * dirp = 0;
341 const char * dirPath;
342 BVRef bvr;
343
344 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
345 goto error;
346
347 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
348 if (dirp == NULL)
349 goto error;
350
351 dirp->dir_path = newString(dirPath);
352 if (dirp->dir_path == NULL)
353 goto error;
354
355 dirp->dir_bvr = bvr;
356
357 return dirp;
358
359 error:
360 closedir(dirp);
361 return NULL;
362 }
363
364 //==========================================================================
365
366 int closedir(struct dirstuff * dirp)
367 {
368 if (dirp) {
369 if (dirp->dir_path) free(dirp->dir_path);
370 free(dirp);
371 }
372 return 0;
373 }
374
375 //==========================================================================
376
377 int readdir(struct dirstuff * dirp, const char ** name, long * flags,
378 long * time)
379 {
380 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
381 /* dirPath */ dirp->dir_path,
382 /* dirIndex */ &dirp->dir_index,
383 /* dirEntry */ (char **)name, flags, time );
384 }
385
386 //==========================================================================
387
388 int currentdev()
389 {
390 return kernBootStruct->kernDev;
391 }
392
393 //==========================================================================
394
395 int switchdev(int dev)
396 {
397 kernBootStruct->kernDev = dev;
398 return dev;
399 }
400
401 //==========================================================================
402
403 const char * usrDevices()
404 {
405 return (B_TYPE(currentdev()) == DEV_EN) ? "" : "/private/Drivers/i386";
406 }
407
408 //==========================================================================
409
410 BVRef scanBootVolumes( int biosdev, int * count )
411 {
412 BVRef bvr = 0;
413
414 switch ( BIOS_DEV_TYPE( biosdev ) )
415 {
416 case kBIOSDevTypeFloppy:
417 case kBIOSDevTypeHardDrive:
418 bvr = diskScanBootVolumes( biosdev, count );
419 break;
420 case kBIOSDevTypeNetwork:
421 bvr = nbpScanBootVolumes( biosdev, count );
422 break;
423 }
424 return bvr;
425 }
426
427 //==========================================================================
428
429 void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen )
430 {
431 bvr->description( bvr, str, strMaxLen );
432 }
433
434 //==========================================================================
435
436 BVRef selectBootVolume( BVRef chain )
437 {
438 BVRef bvr, bvr1 = 0, bvr2 = 0;
439
440 for ( bvr = chain; bvr; bvr = bvr->next )
441 {
442 if ( bvr->flags & kBVFlagNativeBoot ) bvr1 = bvr;
443 if ( bvr->flags & kBVFlagPrimary ) bvr2 = bvr;
444 }
445
446 bvr = bvr1 ? bvr1 :
447 bvr2 ? bvr2 : chain;
448
449 return bvr;
450 }
451
452 //==========================================================================
453
454 #define LP '('
455 #define RP ')'
456 extern int gBIOSDev;
457
458 static BVRef getBootVolumeRef( const char * path, const char ** outPath )
459 {
460 const char * cp;
461 BVRef bvr;
462 int type = B_TYPE( kernBootStruct->kernDev );
463 int unit = B_UNIT( kernBootStruct->kernDev );
464 int part = B_PARTITION( kernBootStruct->kernDev );
465 int biosdev = gBIOSDev;
466 static BVRef lastBVR = 0;
467 static int lastKernDev;
468
469 // Search for left parenthesis in the path specification.
470
471 for (cp = path; *cp; cp++) {
472 if (*cp == LP || *cp == '/') break;
473 }
474
475 if (*cp != LP) // no left paren found
476 {
477 cp = path;
478 if ( lastBVR && lastKernDev == kernBootStruct->kernDev )
479 {
480 bvr = lastBVR;
481 goto quick_exit;
482 }
483 }
484 else if ((cp - path) == 2) // found "xx("
485 {
486 const struct devsw * dp;
487 const char * xp = path;
488 int i;
489
490 cp++;
491
492 // Check the 2 character device name pointed by 'xp'.
493
494 for (dp = devsw; dp->name; dp++)
495 {
496 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
497 break; // found matching entry
498 }
499 if (dp->name == NULL)
500 {
501 error("Unknown device '%c%c'\n", xp[0], xp[1]);
502 return NULL;
503 }
504 type = dp - devsw; // kerndev type
505
506 // Extract the optional unit number from the specification.
507 // hd(unit) or hd(unit, part).
508
509 i = 0;
510 while (*cp >= '0' && *cp <= '9')
511 {
512 i = i * 10 + *cp++ - '0';
513 unit = i;
514 }
515
516 // Extract the optional partition number from the specification.
517
518 if (*cp == ',')
519 part = atoi(++cp);
520
521 // Skip past the right paren.
522
523 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
524 if (*cp == RP) cp++;
525
526 biosdev = dp->biosdev;
527 }
528 else
529 {
530 // Bad device specifier, skip past the right paren.
531
532 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
533 if (*cp == RP) cp++;
534 }
535
536 biosdev += (unit & kBIOSDevUnitMask);
537
538 if ((bvr = newBootVolumeRef(biosdev, part)) == NULL)
539 {
540 // error("newBootVolumeRef() error\n");
541 return NULL;
542 }
543
544 // Record the most recent device parameters in the
545 // KernBootStruct.
546
547 kernBootStruct->kernDev = MAKEKERNDEV(type, unit, bvr->part_no);
548
549 lastBVR = bvr;
550 lastKernDev = kernBootStruct->kernDev;
551
552 quick_exit:
553 // Returns the file path following the device spec.
554 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
555
556 *outPath = cp;
557
558 return bvr;
559 }
560
561 //==========================================================================
562
563 static BVRef newBootVolumeRef( int biosdev, int partno )
564 {
565 BVRef bvr, bvr1, bvrChain;
566
567 // Fetch the volume list from the device.
568
569 bvrChain = scanBootVolumes( biosdev, NULL );
570
571 // Look for a perfect match based on device and partition number.
572
573 for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
574 {
575 if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
576
577 bvr1 = bvr;
578 if ( bvr->part_no == partno ) break;
579 }
580
581 return bvr ? bvr : bvr1;
582 }