]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/sys.c
e8b75b449d8ebe82fdb136a1932f4156f14ccff6
[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 <sys/param.h>
58 #include <ufs/ufs/dir.h>
59 #include <sys/reboot.h>
60 #include <architecture/byte_order.h>
61 #include "ufs_byteorder.h"
62 #include "libsaio.h"
63 #include "cache.h"
64 #include "kernBootStruct.h"
65 #include "stringConstants.h"
66 #include <ufs/ffs/fs.h>
67 #include "nbp.h"
68 #include "memory.h"
69
70 char * gFilename;
71
72 extern int ram_debug_sarld; // in load.c
73
74 #define DCACHE 1
75 #define ICACHE 1
76 #define SYS_MESSAGES 1
77 #define CHECK_CAREFULLY 0
78 #define COMPRESSION 1
79
80 // #define DEBUG 1
81
82 #ifdef DEBUG
83 #define DPRINT(x) { printf x; }
84 #define DSPRINT(x) { printf x; sleep(2); }
85 #define RDPRINT(x) { if (ram_debug_sarld) printf x; }
86 #define RDSPRINT(x) { if (ram_debug_sarld) printf x; sleep(2); }
87 #else
88 #define DPRINT(x)
89 #define DSPRINT(x)
90 #define RDPRINT(x)
91 #define RDSPRINT(x)
92 #endif
93
94 char * devsw[] = {
95 "sd",
96 "hd",
97 "fd",
98 "en",
99 NULL
100 };
101
102 //#############################################################################
103 //#
104 //# Disk filesystem functions.
105 //#
106 //#############################################################################
107
108 static ino_t dlook(char *s, struct iob *io);
109 static char * xx(char *str, struct iob *file);
110 static int ffs(register long mask);
111
112 extern int label_secsize;
113
114 #define BIG_ENDIAN_INTEL_FS __LITTLE_ENDIAN__
115
116 #if ICACHE
117 #define ICACHE_SIZE 256
118 #define ICACHE_READAHEAD 8 // read behind and read ahead
119 static cache_t * icache;
120 #endif ICACHE
121
122 #if DCACHE
123 #define DCACHE_SIZE 16 // 1k (DIRBLKSIZ) blocks
124 static cache_t * dcache;
125 #endif
126
127 #define DEV_BSIZE label_secsize
128
129 #if CHECK_CAREFULLY
130 static int open_init;
131 #endif
132
133 static struct fs * fs_block;
134 static int fs_block_valid;
135
136 #define SUPERBLOCK_ERROR "Bad superblock: error %d\n"
137
138 /*==========================================================================
139 *
140 *
141 */
142 static struct iob * iob_from_fdesc(int fdesc)
143 {
144 register struct iob * file;
145
146 if (fdesc < 0 || fdesc >= NFILES ||
147 ((file = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
148 return NULL;
149 else
150 return file;
151 }
152
153
154 /***************************************************************************
155 *
156 * Disk functions.
157 *
158 ***************************************************************************/
159
160 /*==========================================================================
161 *
162 *
163 */
164 static int
165 openi(int n, struct iob * io)
166 {
167 struct dinode * dp;
168 int cc, i, j, n_round;
169
170 #if ICACHE
171 struct dinode *ip;
172
173 if (icache == 0) {
174 icache = cacheInit(ICACHE_SIZE, sizeof(struct dinode));
175 }
176 #endif /* ICACHE */
177
178 io->i_offset = 0;
179 io->i_bn = fsbtodb(io->i_ffs, ino_to_fsba(io->i_ffs, n)) + io->i_boff;
180 io->i_cc = io->i_ffs->fs_bsize;
181 io->i_ma = io->i_buf;
182
183 #if ICACHE
184 if (cacheFind(icache, n, 0, (char **)&ip) == 1) {
185 io->i_ino.i_din = *ip;
186 cc = 0;
187 } else {
188 #endif ICACHE
189 cc = devread(io);
190 dp = (struct dinode *)io->i_buf;
191 n_round = (n / INOPB(io->i_ffs)) * INOPB(io->i_ffs);
192 #if ICACHE
193 /* Read multiple inodes into cache */
194 for (i = max(ino_to_fsbo(io->i_ffs, n) - ICACHE_READAHEAD, 0),
195 j = min(i+2*ICACHE_READAHEAD, INOPB(io->i_ffs)); i < j; i++) {
196 cacheFind(icache, n_round + i, 0, (char **)&ip);
197
198 #if BIG_ENDIAN_INTEL_FS
199 #warning Building with Big Endian changes
200 byte_swap_dinode_in(&dp[i]);
201 #endif /* BIG_ENDIAN_INTEL_FS */
202
203 *ip = dp[i];
204 if (i == ino_to_fsbo(io->i_ffs, n)) {
205 io->i_ino.i_din = *ip;
206 }
207 }
208 }
209 #else ICACHE
210
211 #if BIG_ENDIAN_INTEL_FS
212 byte_swap_dinode_in(&dp[ino_to_fsbo(io->i_ffs, n)]);
213 #endif /* BIG_ENDIAN_INTEL_FS */
214
215 io->i_ino.i_din = dp[ino_to_fsbo(io->i_ffs, n)];
216 #endif ICACHE
217
218 io->i_ino.i_number = n;
219 return (cc);
220 }
221
222 /*==========================================================================
223 *
224 *
225 */
226 static int
227 readlink(struct iob * io, char * buf, int len)
228 {
229 register struct inode * ip;
230
231 ip = &io->i_ino;
232 #if 1
233 /* read contents */
234 io->i_offset = 0;
235 io->i_cc = 0;
236 io->i_flgs |= F_FILE;
237 if (read(io - iob, buf, len) < 0)
238 return -1;
239 #else
240 if (ip->i_icflags & IC_FASTLINK) {
241 if (ip->i_size > len)
242 return -1;
243 bcopy(ip->i_symlink, buf, ip->i_size);
244 } else {
245 /* read contents */
246 io->i_offset = 0;
247 io->i_cc = 0;
248 io->i_flgs |= F_FILE;
249 if (read(io - iob, buf, len) < 0)
250 return -1;
251 }
252 #endif
253 return 0;
254 }
255
256 /*==========================================================================
257 *
258 *
259 */
260 static int
261 find(char * path, struct iob * file)
262 {
263 char * q;
264 char c;
265 int n, parent;
266 char * lbuf = malloc(MAXPATHLEN + 1);
267 int ret;
268
269 #if CHECK_CAREFULLY
270 if (path==NULL || *path=='\0') {
271 error("null path\n");
272 ret = 0; goto out;
273 }
274 #endif CHECK_CAREFULLY
275
276 DSPRINT(("in find: path=%s\n", path));
277
278 root:
279 n = ROOTINO;
280 if (openi(n, file) < 0)
281 {
282 DPRINT(("openi failed\n"));
283
284 #if SYS_MESSAGES
285 error("bad root inode\n");
286 #endif
287
288 ret = 0; goto out;
289 }
290 DPRINT(("openi ok\n"));
291
292 while (*path)
293 {
294 while (*path == '/')
295 path++;
296 q = path;
297 while(*q != '/' && *q != '\0')
298 q++;
299 c = *q;
300 *q = '\0';
301 if (q == path) path = "." ; /* "/" means "/." */
302
303 parent = n;
304 if ((n = dlook(path, file)) != 0)
305 {
306 if (c == '\0')
307 break;
308 if (openi(n, file) < 0)
309 {
310 *q = c;
311 ret = 0; goto out;
312 }
313 *q = c;
314 path = q;
315
316 /* Check for symlinks */
317 if (file->i_ino.i_mode & IFLNK) {
318 char *buf = malloc(MAXPATHLEN + 1);
319 if (readlink(file, buf, MAXPATHLEN + 1) < 0)
320 return -1;
321 strcat(buf, q);
322 strcpy(lbuf, buf);
323 free(buf);
324 path = lbuf;
325 if (*path == '/')
326 goto root;
327 if (openi(parent, file) < 0) {
328 ret = 0; goto out;
329 }
330 }
331 continue;
332 }
333 else
334 {
335 *q = c;
336 ret = 0; goto out;
337 }
338 }
339 ret = n;
340 out:
341 free(lbuf);
342 return (ret);
343 }
344
345 /*==========================================================================
346 *
347 *
348 */
349 static daddr_t
350 sbmap(struct iob * io, daddr_t bn)
351 {
352 register struct inode * ip;
353 int i, j, sh;
354 daddr_t nb, * bap;
355
356 ip = &io->i_ino;
357
358 if (bn < 0) {
359 #if SYS_MESSAGES
360 error("bn negative\n");
361 #endif
362 return ((daddr_t)0);
363 }
364
365 /*
366 * blocks 0..NDADDR are direct blocks
367 */
368 if (bn < NDADDR)
369 {
370 nb = ip->i_db[bn];
371 return (nb);
372 }
373
374 /*
375 * addresses NIADDR have single and double indirect blocks.
376 * the first step is to determine how many levels of indirection.
377 */
378 RDPRINT(("In NINADDR\n"));
379
380 sh = 1;
381 bn -= NDADDR;
382 for (j = NIADDR; j > 0; j--) {
383 sh *= NINDIR(io->i_ffs);
384 if (bn < sh)
385 break;
386 bn -= sh;
387 }
388
389 if (j == 0) {
390 #if SYS_MESSAGES
391 error("bn ovf %d\n", bn);
392 #endif
393 return ((daddr_t)0);
394 }
395
396 /*
397 * fetch the first indirect block address from the inode
398 */
399 nb = ip->i_ib[NIADDR - j];
400 if (nb == 0) {
401 #if SYS_MESSAGES
402 error("bn void %d\n",bn);
403 #endif
404 return ((daddr_t)0);
405 }
406
407 /*
408 * fetch through the indirect blocks
409 */
410 for (; j <= NIADDR; j++) {
411 if (blknos[j] != nb) {
412 io->i_bn = fsbtodb(io->i_ffs, nb) + io->i_boff;
413 if (b[j] == (char *)0)
414 b[j] = malloc(MAXBSIZE);
415 io->i_ma = b[j];
416 io->i_cc = io->i_ffs->fs_bsize;
417
418 RDPRINT(("Indir block read\n"));
419
420 if (devread(io) != io->i_ffs->fs_bsize) {
421 #if SYS_MESSAGES
422 error("bn %d: read error\n", io->i_bn);
423 #endif
424 return ((daddr_t)0);
425 }
426 blknos[j] = nb;
427 }
428 bap = (daddr_t *)b[j];
429 sh /= NINDIR(io->i_ffs);
430 i = (bn / sh) % NINDIR(io->i_ffs);
431 #if BIG_ENDIAN_INTEL_FS
432 nb = NXSwapBigLongToHost(bap[i]);
433 #else /* BIG_ENDIAN_INTEL_FS */
434 nb = bap[i];
435 #endif /* BIG_ENDIAN_INTEL_FS */
436 if (nb == 0) {
437 #if SYS_MESSAGES
438 error("bn void %d\n",bn);
439 #endif
440 return ((daddr_t)0);
441 }
442 }
443
444 return (nb);
445 }
446
447 /*==========================================================================
448 *
449 *
450 */
451 static struct dirstuff *
452 disk_opendir(char * path)
453 {
454 register struct dirstuff * dirp;
455 register int fd;
456
457 dirp = (struct dirstuff *)malloc(sizeof(struct dirstuff));
458 if (dirp == (struct dirstuff *)-1)
459 return 0;
460
461 DPRINT(("Calling open in opendir\n"));
462 fd = open(path,0);
463 if (fd == -1) {
464 DPRINT(("open failed \n"));
465 free((void *)dirp);
466 return 0;
467 }
468
469 DPRINT(("open ok fd is %d \n", fd));
470 dirp->io = &iob[fd];
471 dirp->loc = 0;
472 iob[fd].dirbuf_blkno = -1;
473
474 return dirp;
475 }
476
477 /*==========================================================================
478 *
479 *
480 */
481 static int
482 disk_closedir(struct dirstuff * dirp)
483 {
484 close(dirp->io - iob);
485 free((void *)dirp);
486 return 0;
487 }
488
489 /*==========================================================================
490 * get next entry in a directory.
491 */
492 static struct direct *
493 disk_readdir(struct dirstuff * dirp)
494 {
495 struct direct * dp;
496 register struct iob * io;
497 daddr_t lbn, d;
498 int off;
499 #if DCACHE
500 char * bp;
501 int dirblkno;
502
503 if (dcache == 0)
504 dcache = cacheInit(DCACHE_SIZE, DIRBLKSIZ);
505 #endif DCACHE
506
507 io = dirp->io;
508 for(;;)
509 {
510 if (dirp->loc >= io->i_ino.i_size)
511 return (NULL);
512 off = blkoff(io->i_ffs, dirp->loc);
513 lbn = lblkno(io->i_ffs, dirp->loc);
514
515 #if DCACHE
516 dirblkno = dirp->loc / DIRBLKSIZ;
517 if (cacheFind(dcache, io->i_ino.i_number, dirblkno, &bp)) {
518 dp = (struct direct *)(bp + (dirp->loc % DIRBLKSIZ));
519 } else
520 #else DCACHE
521 if (io->dirbuf_blkno != lbn)
522 #endif DCACHE
523 {
524 if((d = sbmap(io, lbn)) == 0)
525 return NULL;
526 io->i_bn = fsbtodb(io->i_ffs, d) + io->i_boff;
527 io->i_ma = io->i_buf;
528 io->i_cc = blksize(io->i_ffs, &io->i_ino, lbn);
529
530 if (devread(io) < 0)
531 {
532 #if SYS_MESSAGES
533 error("bn %d: directory read error\n", io->i_bn);
534 #endif
535 return (NULL);
536 }
537 #if BIG_ENDIAN_INTEL_FS
538 byte_swap_dir_block_in(io->i_buf, io->i_cc);
539 #endif /* BIG_ENDIAN_INTEL_FS */
540
541 #if DCACHE
542 bcopy(io->i_buf + dirblkno * DIRBLKSIZ, bp, DIRBLKSIZ);
543 dp = (struct direct *)(io->i_buf + off);
544 #endif
545 }
546 #if !DCACHE
547 dp = (struct direct *)(io->i_buf + off);
548 #endif
549 dirp->loc += dp->d_reclen;
550
551 if (dp->d_ino != 0) return (dp);
552 }
553 }
554
555 /*==========================================================================
556 *
557 *
558 */
559 static ino_t
560 dlook(
561 char * s,
562 struct iob * io
563 )
564 {
565 struct direct * dp;
566 register struct inode * ip;
567 struct dirstuff dirp;
568 int len;
569
570 if (s == NULL || *s == '\0')
571 return (0);
572 ip = &io->i_ino;
573 if ((ip->i_mode & IFMT) != IFDIR) {
574 #if SYS_MESSAGES
575 error(". before %s not a dir\n", s);
576 #endif
577 return (0);
578 }
579 if (ip->i_size == 0) {
580 #if SYS_MESSAGES
581 error("%s: 0 length dir\n", s);
582 #endif
583 return (0);
584 }
585 len = strlen(s);
586 dirp.loc = 0;
587 dirp.io = io;
588 io->dirbuf_blkno = -1;
589
590 for (dp = disk_readdir(&dirp); dp != NULL; dp = disk_readdir(&dirp)) {
591 DPRINT(("checking name %s\n", dp->d_name));
592 if(dp->d_ino == 0)
593 continue;
594 if (dp->d_namlen == len && !strcmp(s, dp->d_name))
595 return (dp->d_ino);
596 }
597 return (0);
598 }
599
600 /*==========================================================================
601 *
602 *
603 */
604 static int
605 getch(int fdesc)
606 {
607 register struct iob * io;
608 struct fs * fs;
609 char * p;
610 int c, lbn, off, size, diff;
611
612 if ((io = iob_from_fdesc(fdesc)) == 0) {
613 return (-1);
614 }
615
616 RDPRINT(("In getch\n"));
617
618 p = io->i_ma;
619 if (io->i_cc <= 0) {
620 if ((io->i_flgs & F_FILE) != 0) {
621 diff = io->i_ino.i_size - io->i_offset;
622 if (diff <= 0)
623 return (-1);
624 fs = io->i_ffs;
625 lbn = lblkno(fs, io->i_offset);
626 #if 1
627 io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff;
628 #else
629 io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff;
630 #endif
631 off = blkoff(fs, io->i_offset);
632 size = blksize(fs, &io->i_ino, lbn);
633 } else {
634 diff = 0;
635 #ifndef SMALL
636 io->i_bn = io->i_offset / DEV_BSIZE;
637 off = 0;
638 size = DEV_BSIZE;
639 #endif SMALL
640 }
641
642 RDPRINT(("gc: bn=%x; off=%x\n",io->i_bn, io->i_offset));
643
644 io->i_ma = io->i_buf;
645 io->i_cc = size;
646 if (devread(io) < 0) {
647 return (-1);
648 }
649 if ((io->i_flgs & F_FILE) != 0) {
650 if (io->i_offset - off + size >= io->i_ino.i_size)
651 io->i_cc = diff + off;
652 io->i_cc -= off;
653 }
654 p = &io->i_buf[off];
655 }
656 io->i_cc--;
657 io->i_offset++;
658 c = (unsigned)*p++;
659 io->i_ma = p;
660 return (c);
661 }
662
663 /*==========================================================================
664 *
665 */
666 static int
667 disk_read(int fdesc, char * buf, int count)
668 {
669 int i, size;
670 register struct iob * file;
671 struct fs * fs;
672 int lbn, off;
673
674 RDSPRINT(("IN READ\n"));
675
676 if ((file = iob_from_fdesc(fdesc)) == 0) {
677 return (-1);
678 }
679 #if CHECK_CAREFULLY
680 if ((file->i_flgs&F_READ) == 0) {
681 return (-1);
682 }
683 #endif
684 if ((file->i_flgs & F_MEM) != 0) {
685
686 RDSPRINT(("In read FMEM\n"));
687
688 if (file->i_offset < file->i_boff) {
689 if (count > (file->i_boff - file->i_offset))
690 count = file->i_boff - file->i_offset;
691 bcopy(file->i_buf + file->i_offset, buf, count);
692 file->i_offset += count;
693 } else {
694 count = 0;
695 }
696 return count;
697 }
698
699 #ifndef SMALL
700 if ((file->i_flgs & F_FILE) == 0) {
701 file->i_cc = count;
702 file->i_ma = buf;
703 file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE);
704
705 RDPRINT(("In read nsmall fbn=%x; offset=%x;", file->i_bn,
706 file->i_offset));
707 RDSPRINT(("boff=%x\n", file->i_boff));
708
709 i = devread(file);
710 file->i_offset += count;
711 return (i);
712 }
713 #endif /* SMALL */
714
715 if (file->i_offset+count > file->i_ino.i_size)
716 count = file->i_ino.i_size - file->i_offset;
717
718 RDSPRINT(("In read nsmall count=%x;", count));
719
720 if ((i = count) <= 0)
721 return (0);
722
723 /*
724 * While reading full blocks, do I/O into user buffer.
725 * Anything else uses getc().
726 */
727 fs = file->i_ffs;
728 while (i) {
729 RDSPRINT(("In lread while\n"));
730 off = blkoff(fs, file->i_offset);
731 lbn = lblkno(fs, file->i_offset);
732 size = blksize(fs, &file->i_ino, lbn);
733 if (off == 0 && size <= i) {
734 file->i_bn = fsbtodb(fs, sbmap(file, lbn)) +
735 file->i_boff;
736 file->i_cc = size;
737 file->i_ma = buf;
738
739 RDPRINT(("In read->devread\n"));
740 RDPRINT(("In read fbn=%x; offset=%x;", file->i_bn,
741 file->i_offset));
742 RDSPRINT((" boff=%x\n", file->i_boff));
743
744 if (devread(file) < 0) {
745 return (-1);
746 }
747 file->i_offset += size;
748 file->i_cc = 0;
749 buf += size;
750 i -= size;
751 }
752 else {
753 RDSPRINT(("IN while nonread\n"));
754 size -= off;
755 if (size > i)
756 size = i;
757 i -= size;
758 do {
759 *buf++ = getch(fdesc);
760 } while (--size);
761 }
762 }
763
764 return (count);
765 }
766
767 /*==========================================================================
768 * Disk (block device) functions.
769 */
770 static BOOL
771 disk_open(char * name, struct iob * file, int how)
772 {
773 int i;
774
775 file->i_cc = SBSIZE;
776 // file->i_bn = (SBLOCK / DEV_BSIZE) + file->i_boff;
777 file->i_bn = (SBOFF/label_secsize) + file->i_boff;
778 file->i_offset = 0;
779
780 if (file->i_ffs == 0) {
781 if (fs_block == 0) {
782 DPRINT(("No super block; reading one \n"));
783 fs_block = (struct fs *) malloc(SBSIZE);
784 }
785 if (fs_block_valid == 0) {
786 file->i_ma = (char *)fs_block;
787 if (devread(file) < 0) {
788 #ifndef SMALL
789 error(SUPERBLOCK_ERROR, 1);
790 #endif
791 return NO;
792 }
793 #if BIG_ENDIAN_INTEL_FS
794 byte_swap_superblock(fs_block);
795 #endif /* BIG_ENDIAN_INTEL_FS */
796 DPRINT(("Read SB \n"));
797 fs_block_valid = 1;
798 }
799 file->i_ffs = fs_block;
800 file->i_buf = malloc(MAXBSIZE);
801 }
802 #if BIG_ENDIAN_INTEL_FS
803 DPRINT(("IN BE_FS code \n"));
804
805 if (file->i_ffs->fs_magic != FS_MAGIC) {
806 DPRINT(("Bad magic in FS %d ; got %d\n", FS_MAGIC,
807 file->i_ffs->fs_magic));
808 error(SUPERBLOCK_ERROR, 2);
809 return NO;
810 }
811 /*
812 * The following is a gross hack to boot disks that have an actual
813 * blocksize of 512 bytes but were written with a theoretical 1024
814 * byte blocksize (fsbtodb == 0).
815 *
816 * We can make this assumption because we can only boot disks with
817 * a 512 byte sector size.
818 */
819 DPRINT(("SB magic ok \n"));
820 if (file->i_ffs->fs_fsize == 0) {
821 error(SUPERBLOCK_ERROR,3);
822 return NO;
823 }
824 file->i_ffs->fs_fsbtodb = ffs(file->i_ffs->fs_fsize / DEV_BSIZE) - 1;
825 #endif /* BIG_ENDIAN_INTEL_FS */
826
827 if ((i = find(name, file)) == 0) {
828 DPRINT(("find() failed\n"));
829 return NO;
830 }
831
832 #if CHECK_CAREFULLY
833 if (how != 0) {
834 error("Can't write files\n");
835 return NO;
836 }
837 #endif CHECK_CAREFULLY
838
839 DPRINT(("calling openi \n"));
840 if (openi(i, file) < 0) {
841 DPRINT(("openi failed \n"));
842 return NO;
843 }
844
845 DPRINT(("openi ok \n"));
846
847 file->i_offset = 0;
848 file->i_cc = 0;
849 file->i_flgs |= F_FILE | (how+1);
850
851 return YES;
852 }
853
854 /*==========================================================================
855 *
856 *
857 */
858 static int
859 ffs(register long mask)
860 {
861 register int cnt;
862
863 if (mask == 0) return(0);
864
865 for (cnt = 1; !(mask & 1); cnt++)
866 mask >>= 1;
867 return(cnt);
868 }
869
870 /*==========================================================================
871 *
872 *
873 */
874 static void
875 disk_flushdev()
876 {
877 register int i;
878
879 devflush();
880 for (i = 0; i < NFILES; i++)
881 if (iob[i].i_flgs & (F_READ | F_WRITE))
882 error("flushdev: fd %d is open\n",i);
883
884 fs_block_valid = 0;
885 #if ICACHE
886 cacheFlush(icache);
887 #endif
888 #if DCACHE
889 cacheFlush(dcache);
890 #endif
891 }
892
893 /***************************************************************************
894 *
895 * Network functions.
896 *
897 ***************************************************************************/
898
899 static int
900 en_read(int fdesc, char * buf, int count)
901 {
902 struct iob * file;
903
904 if ((file = iob_from_fdesc(fdesc)) == 0)
905 return (-1);
906
907 DSPRINT(("read[%d]: %x %x %d\n",
908 fdesc, TFTP_ADDR + file->i_offset, (unsigned) buf, count));
909
910 bcopy((char *)(TFTP_ADDR + file->i_offset), buf, count);
911 file->i_offset += count;
912
913 return count;
914 }
915
916 static BOOL
917 en_open(char * name, struct iob * file, int how)
918 {
919 unsigned long txferSize = TFTP_LEN;
920
921 if (nbpTFTPReadFile(name, &txferSize, TFTP_ADDR) != nbpStatusSuccess)
922 return NO;
923
924 file->i_buf = NULL;
925 file->i_offset = 0;
926 file->i_ino.i_size = txferSize; // update the real size
927
928 return YES;
929 }
930
931 static void
932 en_devopen(char * name, struct iob * io)
933 {
934 io->i_error = 0;
935 }
936
937 /***************************************************************************
938 *
939 * Dispatch functions.
940 *
941 ***************************************************************************/
942
943 /*==========================================================================
944 *
945 */
946 static int
947 gen_read(int fdesc, char * buf, int count)
948 {
949 struct iob * file;
950
951 if ((file = iob_from_fdesc(fdesc)) == 0)
952 return (-1);
953
954 return (file->i_ino.i_dev == DEV_EN) ?
955 en_read(fdesc, buf, count) :
956 disk_read(fdesc, buf, count);
957 }
958
959 /*==========================================================================
960 *
961 */
962 static int
963 gen_open(char * name, struct iob * file, int how)
964 {
965 return (file->i_ino.i_dev == DEV_EN) ?
966 en_open(name, file, how) : disk_open(name, file, how);
967 }
968
969 /*==========================================================================
970 *
971 */
972 static void
973 gen_devopen(char * name, struct iob * io)
974 {
975 return (io->i_ino.i_dev == DEV_EN) ?
976 en_devopen(name, io) : devopen(name, io);
977 }
978
979 /*==========================================================================
980 *
981 */
982 static void
983 gen_flushdev()
984 {
985 return disk_flushdev();
986 }
987
988 /*==========================================================================
989 *
990 */
991 static char *
992 gen_usrDevices()
993 {
994 #define NET_ARCH_DEVICES ""
995
996 return (((currentdev() >> B_TYPESHIFT) & B_TYPEMASK) == DEV_EN) ?
997 NET_ARCH_DEVICES : ARCH_DEVICES;
998 }
999
1000 /***************************************************************************
1001 *
1002 * External functions.
1003 *
1004 ***************************************************************************/
1005
1006 /*==========================================================================
1007 *
1008 */
1009 struct dirstuff *
1010 opendir(char * path)
1011 {
1012 return disk_opendir(path);
1013 }
1014
1015 /*==========================================================================
1016 *
1017 */
1018 int
1019 closedir(struct dirstuff * dirp)
1020 {
1021 return disk_closedir(dirp);
1022 }
1023
1024 /*==========================================================================
1025 * get next entry in a directory.
1026 */
1027 struct direct *
1028 readdir(struct dirstuff * dirp)
1029 {
1030 return disk_readdir(dirp);
1031 }
1032
1033 /*==========================================================================
1034 *
1035 */
1036 int
1037 b_lseek(int fdesc, unsigned int addr, int ptr)
1038 {
1039 register struct iob * io;
1040
1041 RDPRINT(("In lseek addr= %x\n", addr));
1042
1043 #if CHECK_CAREFULLY
1044 if (ptr != 0) {
1045 error("Seek not from beginning of file\n");
1046 return (-1);
1047 }
1048 #endif /* CHECK_CAREFULLY */
1049
1050 if ((io = iob_from_fdesc(fdesc)) == 0) {
1051 return (-1);
1052 }
1053 io->i_offset = addr;
1054 io->i_bn = addr / DEV_BSIZE;
1055 io->i_cc = 0;
1056
1057 RDPRINT(("In end of lseek offset %x; bn %x\n", io->i_offset,io->i_bn));
1058
1059 return (0);
1060 }
1061
1062 /*==========================================================================
1063 *
1064 */
1065 int
1066 tell(int fdesc)
1067 {
1068 return iob[fdesc].i_offset;
1069 }
1070
1071 /*==========================================================================
1072 *
1073 */
1074 int
1075 read(int fdesc, char * buf, int count)
1076 {
1077 return gen_read(fdesc, buf, count);
1078 }
1079
1080 /*==========================================================================
1081 *
1082 */
1083 int
1084 openmem(char * buf, int len)
1085 {
1086 register struct iob * file;
1087 int fdesc;
1088
1089 for (fdesc = 0; fdesc < NFILES; fdesc++)
1090 if (iob[fdesc].i_flgs == 0)
1091 goto gotfile;
1092 stop("Out of file descriptor slots");
1093
1094 gotfile:
1095 (file = &iob[fdesc])->i_flgs |= F_ALLOC;
1096 file->i_buf = buf;
1097 file->i_boff = len;
1098 file->i_offset = 0;
1099 file->i_flgs |= F_MEM;
1100 return fdesc;
1101 }
1102
1103 /*==========================================================================
1104 * Generic open call.
1105 */
1106 int
1107 open(char * str, int how)
1108 {
1109 register char * cp;
1110 register struct iob * file;
1111 int fdesc;
1112
1113 DSPRINT(("In open %s\n", str));
1114
1115 #if CHECK_CAREFULLY /* iob[] is in BSS, so it is guaranteed to be zero. */
1116 if (open_init == 0) {
1117 int i;
1118 for (i = 0; i < NFILES; i++)
1119 iob[i].i_flgs = 0;
1120 open_init = 1;
1121 }
1122 #endif
1123
1124 for (fdesc = 0; fdesc < NFILES; fdesc++)
1125 if (iob[fdesc].i_flgs == 0)
1126 goto gotfile;
1127 stop("Out of file descriptor slots");
1128
1129 gotfile:
1130 (file = &iob[fdesc])->i_flgs |= F_ALLOC;
1131
1132 if ((cp = xx(str, file)) == (char *) -1)
1133 {
1134 close(fdesc);
1135 return -1;
1136 }
1137
1138 if (*cp == '\0') {
1139 file->i_flgs |= how+1;
1140 file->i_cc = 0;
1141 file->i_offset = 0;
1142 return (fdesc);
1143 }
1144
1145 if (gen_open(cp, file, how) == NO) {
1146 close(fdesc);
1147 return -1;
1148 }
1149 return (fdesc);
1150 }
1151
1152 /*==========================================================================
1153 *
1154 */
1155 #define LP '('
1156 #define RP ')'
1157
1158 static char * xx(char *str, struct iob *file)
1159 {
1160 register char *cp = str, *xp;
1161 char ** dp;
1162 int old_dev = kernBootStruct->kernDev;
1163 int dev = (kernBootStruct->kernDev >> B_TYPESHIFT) & B_TYPEMASK;
1164 int unit = (kernBootStruct->kernDev >> B_UNITSHIFT) & B_UNITMASK;
1165 int part = (kernBootStruct->kernDev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
1166 int i;
1167 int no_dev;
1168 int biosOffset;
1169
1170 biosOffset = unit; // set the device
1171
1172 for (; *cp && *cp != LP; cp++) ;
1173 if (no_dev = !*cp) { // no left paren found
1174 cp = str;
1175 xp = devsw[dev];
1176 } else if (cp == str) { // paren but no device
1177 cp++;
1178 xp = devsw[dev];
1179 } else {
1180 xp = str;
1181 cp++;
1182 }
1183
1184 for (dp = devsw; *dp; dp++)
1185 {
1186 if ((xp[0] == *dp[0]) && (xp[1] == *(dp[0] + 1)))
1187 goto gotdev;
1188 }
1189
1190 error("Unknown device '%c%c'\n",xp[0],xp[1]);
1191 return ((char *)-1);
1192
1193 gotdev:
1194 if (no_dev)
1195 goto none;
1196 i = 0;
1197 while (*cp >= '0' && *cp <= '9')
1198 {
1199 i = i * 10 + *cp++ - '0';
1200 unit = i; // get the specified unit number
1201 }
1202
1203 biosOffset = unit; // set the device
1204
1205 if (*cp == RP || no_dev)
1206 /* do nothing since ptol(")") returns 0 */ ;
1207 else if (*cp == ',')
1208 part = ptol(++cp); // get the specified partition number
1209 else if (cp[-1] == LP)
1210 part = ptol(cp);
1211 else {
1212 badoff:
1213 error("Missing offset specification\n");
1214 return ((char *)-1);
1215 }
1216
1217 for ( ;!no_dev ;) { // skip after the right paren
1218 if (*cp == RP)
1219 break;
1220 if (*cp++)
1221 continue;
1222 goto badoff;
1223 }
1224
1225 none:
1226 file->i_ino.i_dev = dev = dp - devsw;
1227 file->partition = part;
1228 file->biosdev = (BIOSDEV(dev)) + biosOffset;
1229
1230 if (dev == DEV_SD) {
1231 file->biosdev += kernBootStruct->numIDEs;
1232 }
1233 else if (dev == DEV_EN) {
1234 file->biosdev = BIOS_DEV_EN;
1235 }
1236 else if (dev == DEV_HD && kernBootStruct->numIDEs == 0) {
1237 error("No IDE drives detected\n");
1238 return ((char *)-1);
1239 }
1240
1241 kernBootStruct->kernDev = (dev << B_TYPESHIFT) |
1242 (unit << B_UNITSHIFT) |
1243 (part << B_PARTITIONSHIFT);
1244
1245 if (kernBootStruct->kernDev != old_dev)
1246 flushdev();
1247
1248 gen_devopen(str, file);
1249
1250 if (file->i_error)
1251 return (char *)-1;
1252 if (!no_dev && *cp) cp++;
1253
1254 gFilename = cp;
1255
1256 return cp;
1257 }
1258
1259 /*==========================================================================
1260 *
1261 */
1262 int
1263 close(int fdesc)
1264 {
1265 register struct iob * file;
1266 register int i;
1267
1268 if ((file = iob_from_fdesc(fdesc)) == 0)
1269 return (-1);
1270
1271 if ((file->i_flgs & F_MEM) == 0) {
1272 // free((char *)file->i_ffs);
1273 file->i_ffs = NULL;
1274 if (file->i_buf) {
1275 free(file->i_buf);
1276 file->i_buf = NULL;
1277 }
1278 for (i=0;i<NBUFS;i++)
1279 {
1280 if (b[i])
1281 { free(b[i]);
1282 b[i] = NULL;
1283 }
1284 blknos[i] = 0;
1285 }
1286 }
1287
1288 file->i_flgs = 0;
1289 return (0);
1290 }
1291
1292 /*==========================================================================
1293 *
1294 */
1295 int
1296 file_size(int fdesc)
1297 {
1298 register struct iob * io;
1299
1300 if ((io = iob_from_fdesc(fdesc)) == 0)
1301 return (-1);
1302
1303 return io->i_ino.i_size;
1304 }
1305
1306 /*==========================================================================
1307 * ensure that all device caches are flushed,
1308 * because we are about to change the device media
1309 */
1310 void
1311 flushdev()
1312 {
1313 gen_flushdev();
1314 }
1315
1316 /*==========================================================================
1317 *
1318 */
1319 void
1320 stop(char * s)
1321 {
1322 #if CHECK_CAREFULLY
1323 register int i;
1324
1325 for (i = 0; i < NFILES; i++)
1326 if (iob[i].i_flgs != 0)
1327 close(i);
1328 #endif CHECK_CAREFULLY
1329
1330 /* textMode(); */ // can't call this function from here
1331 error("\n%s\n", s);
1332 sleep(4); // about to halt
1333 halt();
1334 }
1335
1336 /*==========================================================================
1337 *
1338 */
1339 int currentdev()
1340 {
1341 return kernBootStruct->kernDev;
1342 }
1343
1344 /*==========================================================================
1345 *
1346 */
1347 int
1348 switchdev(int dev)
1349 {
1350 flushdev();
1351 kernBootStruct->kernDev = dev;
1352 return dev;
1353 }
1354
1355 /*==========================================================================
1356 *
1357 */
1358 char *
1359 usrDevices()
1360 {
1361 return gen_usrDevices();
1362 }