]>
git.saurik.com Git - apple/boot.git/blob - gen/libsaio/sys.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
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.
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
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.
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.
54 * @(#)sys.c 7.1 (Berkeley) 6/5/86
60 #import <sys/reboot.h>
61 #import <libkern/OSByteOrder.h>
64 #import "kernBootStruct.h"
68 static ino_t
dlook(char *s
, struct iob
*io
);
69 static char * xx(char *str
, struct iob
*file
);
70 volatile void stop(char *s
);
71 static int ffs(register long mask
);
73 extern int label_secsize
;
77 #define SYS_MESSAGES 1
78 #define CHECK_CAREFULLY 0
82 static cache_t
*icache
;
85 #define DEV_BSIZE label_secsize
87 static struct iob
*iob_from_fdesc(int fdesc
)
89 register struct iob
*file
;
91 if (fdesc
< 0 || fdesc
>= NFILES
||
92 ((file
= &iob
[fdesc
])->i_flgs
& F_ALLOC
) == 0)
99 openi(int n
, struct iob
*io
)
107 icache
= cacheInit(ICACHE_SIZE
, sizeof(struct icommon
));
111 io
->i_bn
= fsbtodb(io
->i_fs
, itod(io
->i_fs
, n
)) + io
->i_boff
;
112 io
->i_cc
= io
->i_fs
->fs_bsize
;
113 io
->i_ma
= io
->i_buf
;
116 if (cacheFind(icache
, n
, 0, (char **)&ip
) == 1) {
117 io
->i_ino
.i_ic
= *ip
;
122 dp
= (struct dinode
*)io
->i_buf
;
124 byte_swap_inode_in(&dp
[itoo(io
->i_fs
, n
)].di_ic
, &io
->i_ino
.i_ic
);
126 io
->i_ino
.i_ic
= dp
[itoo(io
->i_fs
, n
)].di_ic
;
129 *ip
= io
->i_ino
.i_ic
;
132 io
->i_ino
.i_number
= n
;
137 find(char *path
, struct iob
*file
)
144 if (path
==NULL
|| *path
=='\0') {
145 printf("null path\n");
148 #endif CHECK_CAREFULLY
149 if (openi((ino_t
) ROOTINO
, file
) < 0)
152 error("bad root inode\n");
161 while(*q
!= '/' && *q
!= '\0')
165 if (q
== path
) path
= "." ; /* "/" means "/." */
167 if ((n
= dlook(path
, file
)) != 0)
171 if (openi(n
, file
) < 0)
190 sbmap(struct iob
*io
, daddr_t bn
)
192 register struct inode
*ip
;
198 if (ip
->i_icflags
& IC_FASTLINK
)
200 error("fast symlinks unimplemented\n");
206 error("bn negative\n");
212 * blocks 0..NDADDR are direct blocks
221 * addresses NIADDR have single and double indirect blocks.
222 * the first step is to determine how many levels of indirection.
226 for (j
= NIADDR
; j
> 0; j
--) {
227 sh
*= NINDIR(io
->i_fs
);
234 error("bn ovf %d\n", bn
);
240 * fetch the first indirect block address from the inode
242 nb
= ip
->i_ib
[NIADDR
- j
];
245 error("bn void %d\n",bn
);
251 * fetch through the indirect blocks
253 for (; j
<= NIADDR
; j
++) {
254 if (blknos
[j
] != nb
) {
255 io
->i_bn
= fsbtodb(io
->i_fs
, nb
) + io
->i_boff
;
256 if (b
[j
] == (char *)0)
257 b
[j
] = malloc(MAXBSIZE
);
259 io
->i_cc
= io
->i_fs
->fs_bsize
;
260 if (devread(io
) != io
->i_fs
->fs_bsize
) {
262 error("bn %d: read error\n", io
->i_bn
);
268 bap
= (daddr_t
*)b
[j
];
269 sh
/= NINDIR(io
->i_fs
);
270 i
= (bn
/ sh
) % NINDIR(io
->i_fs
);
273 // for now it is little endian FS for intel
276 nb
= OSSwapBigToHostInt32(bap
[i
]);
283 error("bn void %d\n",bn
);
299 register struct inode
*ip
;
300 struct dirstuff dirp
;
303 if (s
== NULL
|| *s
== '\0')
306 if ((ip
->i_mode
& IFMT
) != IFDIR
) {
308 error(". before %s not a dir\n", s
);
312 if (ip
->i_size
== 0) {
314 error("%s: 0 length dir\n", s
);
321 io
->dirbuf_blkno
= -1;
323 for (dp
= readdir(&dirp
); dp
!= NULL
; dp
= readdir(&dirp
)) {
325 printf("checking name %s\n", dp
->d_name
);
329 if (dp
->d_namlen
== len
&& !strcmp(s
, dp
->d_name
))
338 register struct dirstuff
*dirp
;
341 dirp
= (struct dirstuff
*)malloc(sizeof(struct dirstuff
));
342 if (dirp
== (struct dirstuff
*)-1)
351 iob
[fd
].dirbuf_blkno
= -1;
356 closedir(struct dirstuff
*dirp
)
358 close(iob
- dirp
->io
);
364 static cache_t
*dcache
;
365 #define DCACHE_SIZE 6
369 * get next entry in a directory.
372 readdir(struct dirstuff
*dirp
)
375 register struct iob
*io
;
383 dcache
= cacheInit(DCACHE_SIZE
, DIRBLKSIZ
);
388 if (dirp
->loc
>= io
->i_ino
.i_size
)
390 off
= blkoff(io
->i_fs
, dirp
->loc
);
391 lbn
= lblkno(io
->i_fs
, dirp
->loc
);
394 dirblkno
= dirp
->loc
/ DIRBLKSIZ
;
395 if (cacheFind(dcache
, io
->i_ino
.i_number
, dirblkno
, &bp
)) {
396 dp
= (struct direct
*)(bp
+ (dirp
->loc
% DIRBLKSIZ
));
399 if (io
->dirbuf_blkno
!= lbn
)
402 if((d
= sbmap(io
, lbn
)) == 0)
404 io
->i_bn
= fsbtodb(io
->i_fs
, d
) + io
->i_boff
;
405 io
->i_ma
= io
->i_buf
;
406 io
->i_cc
= blksize(io
->i_fs
, &io
->i_ino
, lbn
);
411 error("bn %d: directory read error\n",
417 byte_swap_dir_block_in(io
->i_buf
, io
->i_cc
);
420 bcopy(io
->i_buf
+ dirblkno
* DIRBLKSIZ
, bp
, DIRBLKSIZ
);
421 dp
= (struct direct
*)(io
->i_buf
+ off
);
425 dp
= (struct direct
*)(io
->i_buf
+ off
);
427 dirp
->loc
+= dp
->d_reclen
;
429 if (dp
->d_ino
!= 0) return (dp
);
434 b_lseek(int fdesc
, unsigned int addr
, int ptr
)
436 register struct iob
*io
;
440 error("Seek not from beginning of file\n");
443 #endif CHECK_CAREFULLY
444 if ((io
= iob_from_fdesc(fdesc
)) == 0) {
448 io
->i_bn
= addr
/ DEV_BSIZE
;
456 return iob
[fdesc
].i_offset
;
459 static int getch(int fdesc
)
461 register struct iob
*io
;
464 int c
, lbn
, off
, size
, diff
;
466 if ((io
= iob_from_fdesc(fdesc
)) == 0) {
471 if ((io
->i_flgs
& F_FILE
) != 0) {
472 diff
= io
->i_ino
.i_size
- io
->i_offset
;
476 lbn
= lblkno(fs
, io
->i_offset
);
477 io
->i_bn
= fsbtodb(fs
, sbmap(io
, lbn
)) + io
->i_boff
;
478 off
= blkoff(fs
, io
->i_offset
);
479 size
= blksize(fs
, &io
->i_ino
, lbn
);
483 io
->i_bn
= io
->i_offset
/ DEV_BSIZE
;
488 io
->i_ma
= io
->i_buf
;
490 if (devread(io
) < 0) {
493 if ((io
->i_flgs
& F_FILE
) != 0) {
494 if (io
->i_offset
- off
+ size
>= io
->i_ino
.i_size
)
495 io
->i_cc
= diff
+ off
;
508 read(int fdesc
, char *buf
, int count
)
511 register struct iob
*file
;
515 if ((file
= iob_from_fdesc(fdesc
)) == 0) {
518 if ((file
->i_flgs
&F_READ
) == 0) {
522 if ((file
->i_flgs
& F_FILE
) == 0) {
525 file
->i_bn
= file
->i_boff
+ (file
->i_offset
/ DEV_BSIZE
);
527 file
->i_offset
+= count
;
531 if (file
->i_offset
+count
> file
->i_ino
.i_size
)
532 count
= file
->i_ino
.i_size
- file
->i_offset
;
533 if ((i
= count
) <= 0)
536 * While reading full blocks, do I/O into user buffer.
537 * Anything else uses getc().
541 off
= blkoff(fs
, file
->i_offset
);
542 lbn
= lblkno(fs
, file
->i_offset
);
543 size
= blksize(fs
, &file
->i_ino
, lbn
);
544 if (off
== 0 && size
<= i
) {
545 file
->i_bn
= fsbtodb(fs
, sbmap(file
, lbn
)) +
549 if (devread(file
) < 0) {
552 file
->i_offset
+= size
;
562 *buf
++ = getch(fdesc
);
570 static int open_init
;
571 #endif CHECK_CAREFULLY
572 static struct fs
*fs_block
;
573 static int fs_block_valid
;
575 #define SUPERBLOCK_ERROR "Bad superblock: error %d\n"
578 open(char *str
, int how
)
581 register struct iob
*file
;
584 #if CHECK_CAREFULLY /* iob[] is in BSS, so it is guaranteed to be zero. */
585 if (open_init
== 0) {
586 for (i
= 0; i
< NFILES
; i
++)
592 for (fdesc
= 0; fdesc
< NFILES
; fdesc
++)
593 if (iob
[fdesc
].i_flgs
== 0)
595 stop("Out of file descriptor slots");
598 (file
= &iob
[fdesc
])->i_flgs
|= F_ALLOC
;
600 if ((cp
= xx(str
, file
)) == (char *) -1)
607 file
->i_flgs
|= how
+1;
613 file
->i_bn
= (SBLOCK
/ DEV_BSIZE
) + file
->i_boff
;
616 if (file
->i_fs
== 0) {
618 fs_block
= (struct fs
*)malloc(SBSIZE
);
620 if (fs_block_valid
== 0) {
621 file
->i_ma
= (char *)fs_block
;
622 if (devread(file
) < 0) {
624 error(SUPERBLOCK_ERROR
, 1);
629 byte_swap_superblock(fs_block
);
632 file
->i_fs
= fs_block
;
633 file
->i_buf
= malloc(MAXBSIZE
);
637 if (file
->i_fs
->fs_magic
!= FS_MAGIC
) {
638 error(SUPERBLOCK_ERROR
, 2);
643 * The following is a gross hack to boot disks that have an actual
644 * blocksize of 512 bytes but were written with a theoretical 1024
645 * byte blocksize (fsbtodb == 0).
647 * We can make this assumption because we can only boot disks with
648 * a 512 byte sector size.
650 if (file
->i_fs
->fs_fsize
== 0) {
651 error(SUPERBLOCK_ERROR
,3);
655 file
->i_fs
->fs_fsbtodb
= ffs(file
->i_fs
->fs_fsize
/ DEV_BSIZE
) - 1;
658 if ((i
= find(cp
, file
)) == 0) {
664 error("Can't write files\n");
668 #endif CHECK_CAREFULLY
670 if (openi(i
, file
) < 0) {
676 file
->i_flgs
|= F_FILE
| (how
+1);
684 static char * xx(char *str
, struct iob
*file
)
686 register char *cp
= str
, *xp
;
688 int old_dev
= kernBootStruct
->kernDev
;
689 int dev
= (kernBootStruct
->kernDev
>> B_TYPESHIFT
) & B_TYPEMASK
;
690 int unit
= (kernBootStruct
->kernDev
>> B_UNITSHIFT
) & B_UNITMASK
;
691 int part
= (kernBootStruct
->kernDev
>> B_PARTITIONSHIFT
) &
697 biosOffset
= unit
; // set the device
699 for (; *cp
&& *cp
!= LP
; cp
++) ;
700 if (no_dev
= !*cp
) { // no paren found
703 } else if (cp
== str
) { // paren but no device
711 for (dp
= devsw
; *dp
; dp
++)
713 if ((xp
[0] == *dp
[0]) && (xp
[1] == *(dp
[0] + 1)))
717 error("Unknown device '%c%c'\n",xp
[0],xp
[1]);
724 while (*cp
>= '0' && *cp
<= '9')
726 i
= i
* 10 + *cp
++ - '0';
730 biosOffset
= unit
; // set the device
732 if (*cp
== RP
|| no_dev
)
733 /* do nothing since ptol(")") returns 0 */ ;
734 else if (*cp
== ',' )
736 else if (cp
[-1] == LP
)
740 error("Missing offset specification\n");
753 file
->i_ino
.i_dev
= dev
= dp
-devsw
;
754 file
->partition
= part
;
755 file
->biosdev
= (BIOSDEV(dev
)) + biosOffset
;
757 file
->biosdev
+= kernBootStruct
->numIDEs
;
758 } else if (dev
== DEV_HD
&& kernBootStruct
->numIDEs
== 0) {
759 error("No IDE drives detected\n");
763 kernBootStruct
->kernDev
= (dev
<< B_TYPESHIFT
) |
764 (unit
<< B_UNITSHIFT
) |
765 (part
<< B_PARTITIONSHIFT
);
767 if (kernBootStruct
->kernDev
!= old_dev
)
774 if (!no_dev
&& *cp
) cp
++;
784 register struct iob
*file
;
787 if ((file
= iob_from_fdesc(fdesc
)) == 0) {
790 // free((char *)file->i_fs);
792 free(file
->i_buf
); file
->i_buf
= NULL
;
793 for (i
=0;i
<NBUFS
;i
++)
806 volatile void stop(char *s
)
811 for (i
= 0; i
< NFILES
; i
++)
812 if (iob
[i
].i_flgs
!= 0)
814 #endif CHECK_CAREFULLY
815 /* textMode();*/ // can't call this function from here
817 sleep(4); // about to halt
821 static int ffs(register long mask
)
825 if (mask
== 0) return(0);
826 for (cnt
= 1; !(mask
& 1); cnt
++)
831 int file_size(int fdesc
)
833 register struct iob
*io
;
835 if ((io
= iob_from_fdesc(fdesc
)) == 0) {
838 return io
->i_ino
.i_size
;
841 /* ensure that all device caches are flushed,
842 * because we are about to change the device media
850 for (i
= 0; i
< NFILES
; i
++)
851 if (iob
[i
].i_flgs
& (F_READ
| F_WRITE
))
852 printf("flushdev: fd %d is open\n",i
);