]>
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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1990 Carnegie-Mellon University
28 * Copyright (c) 1989 Carnegie-Mellon University
29 * Copyright (c) 1988 Carnegie-Mellon University
30 * Copyright (c) 1987 Carnegie-Mellon University
31 * All rights reserved. The CMU software License Agreement specifies
32 * the terms and conditions for use and redistribution.
37 * Revision 2.3 88/08/08 13:47:07 rvb
38 * Allocate buffers dynamically vs statically.
39 * Now b[i] and i_fs and i_buf, are allocated dynamically.
40 * boot_calloc(size) allocates and zeros a buffer rounded to a NPG
42 * Generalize boot spec to allow, xx()/mach, xx(n,[a..h])/mach,
43 * xx([a..h])/mach, ...
44 * Also default "xx" if unspecified and alloc just "/mach",
45 * where everything is defaulted
46 * Add routine, ptol(), to parse partition letters.
51 * Copyright (c) 1982, 1986 Regents of the University of California.
52 * All rights reserved. The Berkeley software License Agreement
53 * specifies the terms and conditions for redistribution.
55 * @(#)sys.c 7.1 (Berkeley) 6/5/86
61 #import <sys/reboot.h>
62 #import <libkern/OSByteOrder.h>
65 #import "kernBootStruct.h"
69 static ino_t
dlook(char *s
, struct iob
*io
);
70 static char * xx(char *str
, struct iob
*file
);
71 volatile void stop(char *s
);
72 static int ffs(register long mask
);
74 extern int label_secsize
;
78 #define SYS_MESSAGES 1
79 #define CHECK_CAREFULLY 0
83 static cache_t
*icache
;
86 #define DEV_BSIZE label_secsize
88 static struct iob
*iob_from_fdesc(int fdesc
)
90 register struct iob
*file
;
92 if (fdesc
< 0 || fdesc
>= NFILES
||
93 ((file
= &iob
[fdesc
])->i_flgs
& F_ALLOC
) == 0)
100 openi(int n
, struct iob
*io
)
108 icache
= cacheInit(ICACHE_SIZE
, sizeof(struct icommon
));
112 io
->i_bn
= fsbtodb(io
->i_fs
, itod(io
->i_fs
, n
)) + io
->i_boff
;
113 io
->i_cc
= io
->i_fs
->fs_bsize
;
114 io
->i_ma
= io
->i_buf
;
117 if (cacheFind(icache
, n
, 0, (char **)&ip
) == 1) {
118 io
->i_ino
.i_ic
= *ip
;
123 dp
= (struct dinode
*)io
->i_buf
;
125 byte_swap_inode_in(&dp
[itoo(io
->i_fs
, n
)].di_ic
, &io
->i_ino
.i_ic
);
127 io
->i_ino
.i_ic
= dp
[itoo(io
->i_fs
, n
)].di_ic
;
130 *ip
= io
->i_ino
.i_ic
;
133 io
->i_ino
.i_number
= n
;
138 find(char *path
, struct iob
*file
)
145 if (path
==NULL
|| *path
=='\0') {
146 printf("null path\n");
149 #endif CHECK_CAREFULLY
150 if (openi((ino_t
) ROOTINO
, file
) < 0)
153 error("bad root inode\n");
162 while(*q
!= '/' && *q
!= '\0')
166 if (q
== path
) path
= "." ; /* "/" means "/." */
168 if ((n
= dlook(path
, file
)) != 0)
172 if (openi(n
, file
) < 0)
191 sbmap(struct iob
*io
, daddr_t bn
)
193 register struct inode
*ip
;
199 if (ip
->i_icflags
& IC_FASTLINK
)
201 error("fast symlinks unimplemented\n");
207 error("bn negative\n");
213 * blocks 0..NDADDR are direct blocks
222 * addresses NIADDR have single and double indirect blocks.
223 * the first step is to determine how many levels of indirection.
227 for (j
= NIADDR
; j
> 0; j
--) {
228 sh
*= NINDIR(io
->i_fs
);
235 error("bn ovf %d\n", bn
);
241 * fetch the first indirect block address from the inode
243 nb
= ip
->i_ib
[NIADDR
- j
];
246 error("bn void %d\n",bn
);
252 * fetch through the indirect blocks
254 for (; j
<= NIADDR
; j
++) {
255 if (blknos
[j
] != nb
) {
256 io
->i_bn
= fsbtodb(io
->i_fs
, nb
) + io
->i_boff
;
257 if (b
[j
] == (char *)0)
258 b
[j
] = malloc(MAXBSIZE
);
260 io
->i_cc
= io
->i_fs
->fs_bsize
;
261 if (devread(io
) != io
->i_fs
->fs_bsize
) {
263 error("bn %d: read error\n", io
->i_bn
);
269 bap
= (daddr_t
*)b
[j
];
270 sh
/= NINDIR(io
->i_fs
);
271 i
= (bn
/ sh
) % NINDIR(io
->i_fs
);
274 // for now it is little endian FS for intel
277 nb
= OSSwapBigToHostInt32(bap
[i
]);
284 error("bn void %d\n",bn
);
300 register struct inode
*ip
;
301 struct dirstuff dirp
;
304 if (s
== NULL
|| *s
== '\0')
307 if ((ip
->i_mode
& IFMT
) != IFDIR
) {
309 error(". before %s not a dir\n", s
);
313 if (ip
->i_size
== 0) {
315 error("%s: 0 length dir\n", s
);
322 io
->dirbuf_blkno
= -1;
324 for (dp
= readdir(&dirp
); dp
!= NULL
; dp
= readdir(&dirp
)) {
326 printf("checking name %s\n", dp
->d_name
);
330 if (dp
->d_namlen
== len
&& !strcmp(s
, dp
->d_name
))
339 register struct dirstuff
*dirp
;
342 dirp
= (struct dirstuff
*)malloc(sizeof(struct dirstuff
));
343 if (dirp
== (struct dirstuff
*)-1)
352 iob
[fd
].dirbuf_blkno
= -1;
357 closedir(struct dirstuff
*dirp
)
359 close(iob
- dirp
->io
);
365 static cache_t
*dcache
;
366 #define DCACHE_SIZE 6
370 * get next entry in a directory.
373 readdir(struct dirstuff
*dirp
)
376 register struct iob
*io
;
384 dcache
= cacheInit(DCACHE_SIZE
, DIRBLKSIZ
);
389 if (dirp
->loc
>= io
->i_ino
.i_size
)
391 off
= blkoff(io
->i_fs
, dirp
->loc
);
392 lbn
= lblkno(io
->i_fs
, dirp
->loc
);
395 dirblkno
= dirp
->loc
/ DIRBLKSIZ
;
396 if (cacheFind(dcache
, io
->i_ino
.i_number
, dirblkno
, &bp
)) {
397 dp
= (struct direct
*)(bp
+ (dirp
->loc
% DIRBLKSIZ
));
400 if (io
->dirbuf_blkno
!= lbn
)
403 if((d
= sbmap(io
, lbn
)) == 0)
405 io
->i_bn
= fsbtodb(io
->i_fs
, d
) + io
->i_boff
;
406 io
->i_ma
= io
->i_buf
;
407 io
->i_cc
= blksize(io
->i_fs
, &io
->i_ino
, lbn
);
412 error("bn %d: directory read error\n",
418 byte_swap_dir_block_in(io
->i_buf
, io
->i_cc
);
421 bcopy(io
->i_buf
+ dirblkno
* DIRBLKSIZ
, bp
, DIRBLKSIZ
);
422 dp
= (struct direct
*)(io
->i_buf
+ off
);
426 dp
= (struct direct
*)(io
->i_buf
+ off
);
428 dirp
->loc
+= dp
->d_reclen
;
430 if (dp
->d_ino
!= 0) return (dp
);
435 b_lseek(int fdesc
, unsigned int addr
, int ptr
)
437 register struct iob
*io
;
441 error("Seek not from beginning of file\n");
444 #endif CHECK_CAREFULLY
445 if ((io
= iob_from_fdesc(fdesc
)) == 0) {
449 io
->i_bn
= addr
/ DEV_BSIZE
;
457 return iob
[fdesc
].i_offset
;
460 static int getch(int fdesc
)
462 register struct iob
*io
;
465 int c
, lbn
, off
, size
, diff
;
467 if ((io
= iob_from_fdesc(fdesc
)) == 0) {
472 if ((io
->i_flgs
& F_FILE
) != 0) {
473 diff
= io
->i_ino
.i_size
- io
->i_offset
;
477 lbn
= lblkno(fs
, io
->i_offset
);
478 io
->i_bn
= fsbtodb(fs
, sbmap(io
, lbn
)) + io
->i_boff
;
479 off
= blkoff(fs
, io
->i_offset
);
480 size
= blksize(fs
, &io
->i_ino
, lbn
);
484 io
->i_bn
= io
->i_offset
/ DEV_BSIZE
;
489 io
->i_ma
= io
->i_buf
;
491 if (devread(io
) < 0) {
494 if ((io
->i_flgs
& F_FILE
) != 0) {
495 if (io
->i_offset
- off
+ size
>= io
->i_ino
.i_size
)
496 io
->i_cc
= diff
+ off
;
509 read(int fdesc
, char *buf
, int count
)
512 register struct iob
*file
;
516 if ((file
= iob_from_fdesc(fdesc
)) == 0) {
519 if ((file
->i_flgs
&F_READ
) == 0) {
523 if ((file
->i_flgs
& F_FILE
) == 0) {
526 file
->i_bn
= file
->i_boff
+ (file
->i_offset
/ DEV_BSIZE
);
528 file
->i_offset
+= count
;
532 if (file
->i_offset
+count
> file
->i_ino
.i_size
)
533 count
= file
->i_ino
.i_size
- file
->i_offset
;
534 if ((i
= count
) <= 0)
537 * While reading full blocks, do I/O into user buffer.
538 * Anything else uses getc().
542 off
= blkoff(fs
, file
->i_offset
);
543 lbn
= lblkno(fs
, file
->i_offset
);
544 size
= blksize(fs
, &file
->i_ino
, lbn
);
545 if (off
== 0 && size
<= i
) {
546 file
->i_bn
= fsbtodb(fs
, sbmap(file
, lbn
)) +
550 if (devread(file
) < 0) {
553 file
->i_offset
+= size
;
563 *buf
++ = getch(fdesc
);
571 static int open_init
;
572 #endif CHECK_CAREFULLY
573 static struct fs
*fs_block
;
574 static int fs_block_valid
;
576 #define SUPERBLOCK_ERROR "Bad superblock: error %d\n"
579 open(char *str
, int how
)
582 register struct iob
*file
;
585 #if CHECK_CAREFULLY /* iob[] is in BSS, so it is guaranteed to be zero. */
586 if (open_init
== 0) {
587 for (i
= 0; i
< NFILES
; i
++)
593 for (fdesc
= 0; fdesc
< NFILES
; fdesc
++)
594 if (iob
[fdesc
].i_flgs
== 0)
596 stop("Out of file descriptor slots");
599 (file
= &iob
[fdesc
])->i_flgs
|= F_ALLOC
;
601 if ((cp
= xx(str
, file
)) == (char *) -1)
608 file
->i_flgs
|= how
+1;
614 file
->i_bn
= (SBLOCK
/ DEV_BSIZE
) + file
->i_boff
;
617 if (file
->i_fs
== 0) {
619 fs_block
= (struct fs
*)malloc(SBSIZE
);
621 if (fs_block_valid
== 0) {
622 file
->i_ma
= (char *)fs_block
;
623 if (devread(file
) < 0) {
625 error(SUPERBLOCK_ERROR
, 1);
630 byte_swap_superblock(fs_block
);
633 file
->i_fs
= fs_block
;
634 file
->i_buf
= malloc(MAXBSIZE
);
638 if (file
->i_fs
->fs_magic
!= FS_MAGIC
) {
639 error(SUPERBLOCK_ERROR
, 2);
644 * The following is a gross hack to boot disks that have an actual
645 * blocksize of 512 bytes but were written with a theoretical 1024
646 * byte blocksize (fsbtodb == 0).
648 * We can make this assumption because we can only boot disks with
649 * a 512 byte sector size.
651 if (file
->i_fs
->fs_fsize
== 0) {
652 error(SUPERBLOCK_ERROR
,3);
656 file
->i_fs
->fs_fsbtodb
= ffs(file
->i_fs
->fs_fsize
/ DEV_BSIZE
) - 1;
659 if ((i
= find(cp
, file
)) == 0) {
665 error("Can't write files\n");
669 #endif CHECK_CAREFULLY
671 if (openi(i
, file
) < 0) {
677 file
->i_flgs
|= F_FILE
| (how
+1);
685 static char * xx(char *str
, struct iob
*file
)
687 register char *cp
= str
, *xp
;
689 int old_dev
= kernBootStruct
->kernDev
;
690 int dev
= (kernBootStruct
->kernDev
>> B_TYPESHIFT
) & B_TYPEMASK
;
691 int unit
= (kernBootStruct
->kernDev
>> B_UNITSHIFT
) & B_UNITMASK
;
692 int part
= (kernBootStruct
->kernDev
>> B_PARTITIONSHIFT
) &
698 biosOffset
= unit
; // set the device
700 for (; *cp
&& *cp
!= LP
; cp
++) ;
701 if (no_dev
= !*cp
) { // no paren found
704 } else if (cp
== str
) { // paren but no device
712 for (dp
= devsw
; *dp
; dp
++)
714 if ((xp
[0] == *dp
[0]) && (xp
[1] == *(dp
[0] + 1)))
718 error("Unknown device '%c%c'\n",xp
[0],xp
[1]);
725 while (*cp
>= '0' && *cp
<= '9')
727 i
= i
* 10 + *cp
++ - '0';
731 biosOffset
= unit
; // set the device
733 if (*cp
== RP
|| no_dev
)
734 /* do nothing since ptol(")") returns 0 */ ;
735 else if (*cp
== ',' )
737 else if (cp
[-1] == LP
)
741 error("Missing offset specification\n");
754 file
->i_ino
.i_dev
= dev
= dp
-devsw
;
755 file
->partition
= part
;
756 file
->biosdev
= (BIOSDEV(dev
)) + biosOffset
;
758 file
->biosdev
+= kernBootStruct
->numIDEs
;
759 } else if (dev
== DEV_HD
&& kernBootStruct
->numIDEs
== 0) {
760 error("No IDE drives detected\n");
764 kernBootStruct
->kernDev
= (dev
<< B_TYPESHIFT
) |
765 (unit
<< B_UNITSHIFT
) |
766 (part
<< B_PARTITIONSHIFT
);
768 if (kernBootStruct
->kernDev
!= old_dev
)
775 if (!no_dev
&& *cp
) cp
++;
785 register struct iob
*file
;
788 if ((file
= iob_from_fdesc(fdesc
)) == 0) {
791 // free((char *)file->i_fs);
793 free(file
->i_buf
); file
->i_buf
= NULL
;
794 for (i
=0;i
<NBUFS
;i
++)
807 volatile void stop(char *s
)
812 for (i
= 0; i
< NFILES
; i
++)
813 if (iob
[i
].i_flgs
!= 0)
815 #endif CHECK_CAREFULLY
816 /* textMode();*/ // can't call this function from here
818 sleep(4); // about to halt
822 static int ffs(register long mask
)
826 if (mask
== 0) return(0);
827 for (cnt
= 1; !(mask
& 1); cnt
++)
832 int file_size(int fdesc
)
834 register struct iob
*io
;
836 if ((io
= iob_from_fdesc(fdesc
)) == 0) {
839 return io
->i_ino
.i_size
;
842 /* ensure that all device caches are flushed,
843 * because we are about to change the device media
851 for (i
= 0; i
< NFILES
; i
++)
852 if (iob
[i
].i_flgs
& (F_READ
| F_WRITE
))
853 printf("flushdev: fd %d is open\n",i
);