]> git.saurik.com Git - apple/boot.git/blame - i386/libsaio/sys.c
boot-111.1.tar.gz
[apple/boot.git] / i386 / libsaio / sys.c
CommitLineData
14c7c974
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
4f6e3300
A
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.
14c7c974
A
13 *
14 * The Original Code and all software distributed under the License are
4f6e3300 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14c7c974
A
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
4f6e3300
A
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.
14c7c974
A
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
14c7c974 57#include "libsaio.h"
f083c6c3
A
58#include "bootstruct.h"
59
75b89a82
A
60
61struct devsw {
62 const char * name;
63 unsigned char biosdev;
f083c6c3 64 int type;
14c7c974
A
65};
66
75b89a82
A
67static struct devsw devsw[] =
68{
f083c6c3
A
69 { "sd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_SD */
70 { "hd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_HD */
71 { "fd", 0x00, kBIOSDevTypeFloppy }, /* DEV_FD */
72 { "en", 0xE0, kBIOSDevTypeNetwork }, /* DEV_EN */
75b89a82
A
73 { 0, 0 }
74};
14c7c974 75
75b89a82
A
76/*
77 * Max number of file descriptors.
78 */
79#define NFILES 6
14c7c974 80
75b89a82 81static struct iob iob[NFILES];
14c7c974 82
75b89a82 83void * gFSLoadAddress = 0;
14c7c974 84
75b89a82
A
85static BVRef getBootVolumeRef( const char * path, const char ** outPath );
86static BVRef newBootVolumeRef( int biosdev, int partno );
14c7c974 87
75b89a82
A
88//==========================================================================
89// LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
90// Load the specified file to the load buffer at LOAD_ADDR.
f083c6c3 91// If the file is fat, load only the i386 portion.
14c7c974 92
75b89a82
A
93long LoadFile(const char * fileSpec)
94{
95 const char * filePath;
96 long fileSize;
97 BVRef bvr;
14c7c974 98
75b89a82 99 // Resolve the boot volume from the file spec.
14c7c974 100
75b89a82
A
101 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
102 return -1;
14c7c974 103
75b89a82
A
104 // Read file into load buffer. The data in the load buffer will be
105 // overwritten by the next LoadFile() call.
14c7c974 106
75b89a82 107 gFSLoadAddress = (void *) LOAD_ADDR;
14c7c974 108
75b89a82 109 fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
14c7c974 110
75b89a82 111 // Return the size of the file, or -1 if load failed.
14c7c974 112
75b89a82 113 return fileSize;
14c7c974
A
114}
115
75b89a82
A
116//==========================================================================
117// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
118// Fetch the next directory entry for the given directory.
119
120long GetDirEntry(const char * dirSpec, long * dirIndex, const char ** name,
121 long * flags, long * time)
14c7c974 122{
75b89a82
A
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)
14c7c974 129 return -1;
75b89a82
A
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 );
14c7c974
A
137}
138
75b89a82
A
139//==========================================================================
140// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
141// Get attributes for the specified file.
142
f083c6c3
A
143static char gMakeDirSpec[1024];
144
75b89a82
A
145long GetFileInfo(const char * dirSpec, const char * name,
146 long * flags, long * time)
14c7c974 147{
75b89a82
A
148 long index = 0;
149 const char * entryName;
150
f083c6c3
A
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
75b89a82
A
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
14c7c974
A
174}
175
75b89a82
A
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
182static struct iob * iob_from_fdesc(int fdesc)
14c7c974 183{
75b89a82
A
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;
14c7c974
A
191}
192
75b89a82
A
193//==========================================================================
194// openmem()
195
196int openmem(char * buf, int len)
14c7c974 197{
75b89a82
A
198 int fdesc;
199 struct iob * io;
14c7c974 200
75b89a82 201 // Locate a free descriptor slot.
14c7c974 202
75b89a82
A
203 for (fdesc = 0; fdesc < NFILES; fdesc++)
204 if (iob[fdesc].i_flgs == 0)
205 goto gotfile;
14c7c974 206
75b89a82 207 stop("Out of file descriptors");
14c7c974 208
75b89a82
A
209gotfile:
210 io = &iob[fdesc];
211 bzero(io, sizeof(*io));
14c7c974 212
75b89a82
A
213 // Mark the descriptor as taken. Set the F_MEM flag to indicate
214 // that the file buffer is provided by the caller.
14c7c974 215
75b89a82
A
216 io->i_flgs = F_ALLOC | F_MEM;
217 io->i_buf = buf;
218 io->i_filesize = len;
14c7c974 219
75b89a82 220 return fdesc;
14c7c974
A
221}
222
75b89a82
A
223//==========================================================================
224// open() - Open the file specified by 'path' for reading.
14c7c974 225
75b89a82 226int open(const char * path, int flags)
14c7c974 227{
75b89a82
A
228 int fdesc, i;
229 struct iob * io;
230 const char * filePath;
231 BVRef bvr;
14c7c974 232
75b89a82 233 // Locate a free descriptor slot.
14c7c974 234
75b89a82
A
235 for (fdesc = 0; fdesc < NFILES; fdesc++)
236 if (iob[fdesc].i_flgs == 0)
237 goto gotfile;
14c7c974 238
75b89a82 239 stop("Out of file descriptors");
14c7c974 240
75b89a82
A
241gotfile:
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;
14c7c974 257 for (i = 0; i < NFILES; i++)
75b89a82
A
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);
f083c6c3
A
268 if (io->i_filesize < 0) {
269 goto error;
270 }
75b89a82
A
271
272 return fdesc;
273
274error:
275 close(fdesc);
276 return -1;
14c7c974
A
277}
278
75b89a82
A
279//==========================================================================
280// close() - Close a file descriptor.
14c7c974 281
75b89a82 282int close(int fdesc)
14c7c974 283{
75b89a82 284 struct iob * io;
14c7c974 285
75b89a82
A
286 if ((io = iob_from_fdesc(fdesc)) == NULL)
287 return (-1);
14c7c974 288
75b89a82 289 io->i_flgs = 0;
14c7c974 290
75b89a82 291 return 0;
14c7c974 292}
75b89a82
A
293
294//==========================================================================
295// lseek() - Reposition the byte offset of the file descriptor from the
296// beginning of the file. Returns the relocated offset.
297
298int b_lseek(int fdesc, int offset, int ptr)
14c7c974 299{
75b89a82 300 struct iob * io;
14c7c974 301
75b89a82
A
302 if ((io = iob_from_fdesc(fdesc)) == NULL)
303 return (-1);
14c7c974 304
75b89a82 305 io->i_offset = offset;
14c7c974 306
75b89a82 307 return offset;
14c7c974
A
308}
309
75b89a82
A
310//==========================================================================
311// tell() - Returns the byte offset of the file descriptor.
14c7c974 312
75b89a82 313int tell(int fdesc)
14c7c974 314{
75b89a82 315 struct iob * io;
14c7c974 316
75b89a82
A
317 if ((io = iob_from_fdesc(fdesc)) == NULL)
318 return 0;
319
320 return io->i_offset;
14c7c974
A
321}
322
75b89a82
A
323//==========================================================================
324// read() - Read up to 'count' bytes of data from the file descriptor
325// into the buffer pointed to by buf.
326
327int read(int fdesc, char * buf, int count)
14c7c974 328{
75b89a82
A
329 struct iob * io;
330
331 if ((io = iob_from_fdesc(fdesc)) == NULL)
332 return (-1);
333
f083c6c3 334 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
75b89a82
A
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;
14c7c974
A
345}
346
75b89a82
A
347//==========================================================================
348// file_size() - Returns the size of the file described by the file
349// descriptor.
350
351int file_size(int fdesc)
14c7c974 352{
75b89a82
A
353 struct iob * io;
354
355 if ((io = iob_from_fdesc(fdesc)) == 0)
356 return 0;
357
358 return io->i_filesize;
14c7c974
A
359}
360
75b89a82
A
361//==========================================================================
362
363struct dirstuff * opendir(const char * path)
14c7c974 364{
75b89a82
A
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;
14c7c974 383
75b89a82
A
384error:
385 closedir(dirp);
386 return NULL;
14c7c974
A
387}
388
75b89a82 389//==========================================================================
14c7c974 390
75b89a82 391int closedir(struct dirstuff * dirp)
14c7c974 392{
75b89a82
A
393 if (dirp) {
394 if (dirp->dir_path) free(dirp->dir_path);
395 free(dirp);
396 }
397 return 0;
14c7c974
A
398}
399
75b89a82
A
400//==========================================================================
401
402int readdir(struct dirstuff * dirp, const char ** name, long * flags,
403 long * time)
14c7c974 404{
75b89a82
A
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 );
14c7c974
A
409}
410
75b89a82
A
411//==========================================================================
412
413int currentdev()
14c7c974 414{
f083c6c3 415 return bootArgs->kernDev;
14c7c974
A
416}
417
75b89a82
A
418//==========================================================================
419
420int switchdev(int dev)
14c7c974 421{
f083c6c3 422 bootArgs->kernDev = dev;
75b89a82
A
423 return dev;
424}
14c7c974 425
75b89a82 426//==========================================================================
14c7c974 427
75b89a82
A
428const char * usrDevices()
429{
f083c6c3
A
430 if (gBootFileType == kNetworkDeviceType)
431 return "";
432 return "/private/Drivers/i386";
75b89a82 433}
14c7c974 434
75b89a82 435//==========================================================================
14c7c974 436
f083c6c3
A
437const char * systemConfigDir()
438{
439 if (gBootFileType == kNetworkDeviceType)
440 return "";
441 return "/Library/Preferences/SystemConfiguration";
442}
443
444//==========================================================================
445
446int gBootFileType;
447
75b89a82
A
448BVRef scanBootVolumes( int biosdev, int * count )
449{
450 BVRef bvr = 0;
14c7c974 451
f083c6c3
A
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;
75b89a82
A
460 }
461 return bvr;
14c7c974
A
462}
463
75b89a82 464//==========================================================================
14c7c974 465
75b89a82 466void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen )
14c7c974 467{
75b89a82 468 bvr->description( bvr, str, strMaxLen );
14c7c974
A
469}
470
75b89a82 471//==========================================================================
14c7c974 472
75b89a82
A
473BVRef selectBootVolume( BVRef chain )
474{
475 BVRef bvr, bvr1 = 0, bvr2 = 0;
14c7c974 476
75b89a82
A
477 for ( bvr = chain; bvr; bvr = bvr->next )
478 {
479 if ( bvr->flags & kBVFlagNativeBoot ) bvr1 = bvr;
480 if ( bvr->flags & kBVFlagPrimary ) bvr2 = bvr;
481 }
14c7c974 482
f083c6c3
A
483 bvr = bvr2 ? bvr2 :
484 bvr1 ? bvr1 : chain;
14c7c974 485
75b89a82 486 return bvr;
14c7c974
A
487}
488
75b89a82
A
489//==========================================================================
490
14c7c974
A
491#define LP '('
492#define RP ')'
f083c6c3 493int gBIOSDev;
14c7c974 494
75b89a82 495static BVRef getBootVolumeRef( const char * path, const char ** outPath )
14c7c974 496{
75b89a82
A
497 const char * cp;
498 BVRef bvr;
f083c6c3
A
499 int type = B_TYPE( bootArgs->kernDev );
500 int unit = B_UNIT( bootArgs->kernDev );
501 int part = B_PARTITION( bootArgs->kernDev );
75b89a82
A
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;
14c7c974 510 }
14c7c974 511
75b89a82
A
512 if (*cp != LP) // no left paren found
513 {
514 cp = path;
f083c6c3 515 if ( lastBVR && lastKernDev == bootArgs->kernDev )
75b89a82
A
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
f083c6c3 563 biosdev = dp->biosdev + unit;
75b89a82
A
564 }
565 else
566 {
567 // Bad device specifier, skip past the right paren.
14c7c974 568
75b89a82
A
569 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
570 if (*cp == RP) cp++;
571 }
14c7c974 572
75b89a82
A
573 if ((bvr = newBootVolumeRef(biosdev, part)) == NULL)
574 {
575 // error("newBootVolumeRef() error\n");
576 return NULL;
577 }
14c7c974 578
75b89a82
A
579 // Record the most recent device parameters in the
580 // KernBootStruct.
14c7c974 581
f083c6c3 582 bootArgs->kernDev = biosdev;
14c7c974 583
75b89a82 584 lastBVR = bvr;
f083c6c3 585 lastKernDev = bootArgs->kernDev;
14c7c974 586
75b89a82
A
587quick_exit:
588 // Returns the file path following the device spec.
589 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
14c7c974 590
75b89a82 591 *outPath = cp;
14c7c974 592
75b89a82 593 return bvr;
14c7c974
A
594}
595
75b89a82 596//==========================================================================
14c7c974 597
75b89a82 598static BVRef newBootVolumeRef( int biosdev, int partno )
14c7c974 599{
75b89a82 600 BVRef bvr, bvr1, bvrChain;
14c7c974 601
75b89a82 602 // Fetch the volume list from the device.
14c7c974 603
75b89a82
A
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;
14c7c974 617}