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