Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / i386 / boot / biosboot / sys.c
1 /*
2  * Mach Operating System
3  * Copyright (c) 1992, 1991 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie Mellon
24  * the rights to redistribute these changes.
25  *
26  *      from: Mach, Revision 2.2  92/04/04  11:36:34  rpd
27  * $FreeBSD: src/sys/i386/boot/biosboot/sys.c,v 1.22 1999/08/28 00:43:14 peter Exp $
28  */
29
30 #include "boot.h"
31 #include <sys/dirent.h>
32 #include <sys/reboot.h>
33
34 #if 0
35 /* #define BUFSIZE 4096 */
36 #define BUFSIZE MAXBSIZE
37
38 static char buf[BUFSIZE], fsbuf[SBSIZE], iobuf[MAXBSIZE];
39 #endif
40
41 static char biosdrivedigit;
42
43 #define BUFSIZE 8192
44 #define MAPBUFSIZE BUFSIZE
45 static char buf[BUFSIZE], fsbuf[BUFSIZE], iobuf[BUFSIZE];
46
47 static char mapbuf[MAPBUFSIZE];
48 static int mapblock;
49
50 int poff;
51
52 #ifdef RAWBOOT
53 #define STARTBYTE       8192    /* Where on the media the kernel starts */
54 #endif
55
56 static int block_map(int file_block);
57 static int find(char *path);
58
59 void
60 xread(char *addr, int size)
61 {
62         int count = BUFSIZE;
63         while (size > 0) {
64                 if (BUFSIZE > size)
65                         count = size;
66                 read(buf, count);
67                 pcpy(buf, addr, count);
68                 size -= count;
69                 addr += count;
70         }
71 }
72
73 #ifndef RAWBOOT
74 void
75 read(char *buffer, int count)
76 {
77         int logno, off, size;
78         int cnt2, bnum2;
79         struct fs *fs_copy;
80
81         while (count > 0 && poff < inode.i_size) {
82                 fs_copy = fs;
83                 off = blkoff(fs_copy, poff);
84                 logno = lblkno(fs_copy, poff);
85                 cnt2 = size = blksize(fs_copy, &inode, logno);
86                 bnum2 = fsbtodb(fs_copy, block_map(logno)) + boff;
87                 if (    (!off)  && (size <= count)) {
88                         devread(buffer, bnum2, cnt2);
89                 } else {
90                         size -= off;
91                         if (size > count)
92                                 size = count;
93                         devread(iobuf, bnum2, cnt2);
94                         bcopy(iobuf+off, buffer, size);
95                 }
96                 buffer += size;
97                 count -= size;
98                 poff += size;
99         }
100 }
101 #else
102 void
103 read(char *buffer, int count)
104 {
105         int cnt, bnum, off, size;
106
107         off = STARTBYTE + poff;
108         poff += count;
109
110         /* Read any unaligned bit at the front */
111         cnt = off & 511;
112         if (cnt) {
113                 size = 512-cnt;
114                 if (count < size)
115                         size = count;
116                 devread(iobuf, off >> 9, 512);
117                 bcopy(iobuf+cnt, buffer, size);
118                 count -= size;
119                 off += size;
120                 buffer += size;
121         }
122         size = count & (~511);
123         if (size && (off & (~511))) {
124                 devread(buffer, off >> 9, size);
125                 off += size;
126                 count -= size;
127                 buffer += size;
128         }
129         if (count) {
130                 devread(iobuf, off >> 9, 512);
131                 bcopy(iobuf, buffer, count);
132         }
133 }
134 #endif
135
136 static int
137 find(char *path)
138 {
139         char *rest, ch;
140         int block, off, loc, ino = ROOTINO;
141         struct dirent *dp;
142         char list_only;
143
144         list_only = (path[0] == '?' && path[1] == '\0');
145 loop:
146         devread(iobuf, fsbtodb(fs, ino_to_fsba(fs, ino)) + boff, fs->fs_bsize);
147         bcopy((void *)&((struct dinode *)iobuf)[ino % fs->fs_inopb],
148               (void *)&inode.i_din,
149               sizeof (struct dinode));
150         if (!*path)
151                 return 1;
152         while (*path == '/')
153                 path++;
154         if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
155                 return 0;
156         for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
157         *rest = 0;
158         loc = 0;
159         do {
160                 if (loc >= inode.i_size) {
161                         if (list_only) {
162                                 putchar('\n');
163                                 return -1;
164                         } else {
165                                 return 0;
166                         }
167                 }
168                 if (!(off = blkoff(fs, loc))) {
169                         block = lblkno(fs, loc);
170                         devread(iobuf, fsbtodb(fs, block_map(block)) + boff,
171                                 blksize(fs, &inode, block));
172                 }
173                 dp = (struct dirent *)(iobuf + off);
174                 loc += dp->d_reclen;
175                 if (dp->d_fileno && list_only)
176                         printf("%s ", dp->d_name);
177         } while (!dp->d_fileno || strcmp(path, dp->d_name));
178         ino = dp->d_fileno;
179         *(path = rest) = ch;
180         goto loop;
181 }
182
183
184 static int
185 block_map(int file_block)
186 {
187         int bnum;
188         if (file_block < NDADDR)
189                 return(inode.i_db[file_block]);
190         if ((bnum=fsbtodb(fs, inode.i_ib[0])+boff) != mapblock) {
191                 devread(mapbuf, bnum, fs->fs_bsize);
192                 mapblock = bnum;
193         }
194         return (((int *)mapbuf)[(file_block - NDADDR) % NINDIR(fs)]);
195 }
196
197
198 int
199 openrd(void)
200 {
201         char **devp, *name0 = name, *cp = name0;
202         int biosdrive, dosdev_copy, ret;
203
204         /*******************************************************\
205         * If bracket given look for preceding device name       *
206         \*******************************************************/
207         while (*cp && *cp!='(')
208                 cp++;
209         if (!*cp)
210         {
211                 cp = name0;
212         }
213         else
214         {
215                 /*
216                  * Look for a BIOS drive number (a leading digit followed
217                  * by a colon).
218                  */
219                 biosdrivedigit = '\0';
220                 if (*(name0 + 1) == ':' && *name0 >= '0' && *name0 <= '9') {
221                         biosdrivedigit = *name0;
222                         name0 += 2;
223                 }
224
225                 if (cp++ != name0)
226                 {
227                         for (devp = devs; *devp; devp++)
228                                 if (name0[0] == (*devp)[0] &&
229                                     name0[1] == (*devp)[1])
230                                         break;
231                         if (!*devp)
232                         {
233                                 printf("Unknown device\n");
234                                 return 1;
235                         }
236                         maj = devp-devs;
237                 }
238                 /*******************************************************\
239                 * Look inside brackets for unit number, and partition   *
240                 \*******************************************************/
241                 /*
242                  * Allow any valid digit as the unit number, as the BIOS
243                  * will complain if the unit number is out of range.
244                  * Restricting the range here prevents the possibilty of using
245                  * BIOSes that support more than 2 units.
246                  * XXX Bad values may cause strange errors, need to check if
247                  * what happens when a value out of range is supplied.
248                  */
249                 if (*cp >= '0' && *cp <= '9')
250                         unit = *cp++ - '0';
251                 if (!*cp || (*cp == ',' && !*++cp))
252                         return 1;
253                 if (*cp >= 'a' && *cp <= 'p')
254                         part = *cp++ - 'a';
255                 while (*cp && *cp++!=')') ;
256                 if (!*cp)
257                         return 1;
258         }
259         biosdrive = biosdrivedigit - '0';
260         if (biosdrivedigit == '\0') {
261                 biosdrive = unit;
262 #if BOOT_HD_BIAS > 0
263                 /* XXX */
264                 if (maj == 4)
265                         biosdrive += BOOT_HD_BIAS;
266 #endif
267         }
268         switch(maj)
269         {
270         case 0:
271         case 4:
272                 dosdev_copy = biosdrive | 0x80;
273                 break;
274         case 2:
275                 dosdev_copy = biosdrive;
276                 break;
277         default:
278                 printf("Unknown device\n");
279                 return 1;
280         }
281         dosdev = dosdev_copy;
282 #if 0
283         /* XXX this is useful, but misplaced. */
284         printf("dosdev= %x, biosdrive = %d, unit = %d, maj = %d\n",
285                 dosdev_copy, biosdrive, unit, maj);
286 #endif
287
288         /***********************************************\
289         * Now we know the disk unit and part,           *
290         * Load disk info, (open the device)             *
291         \***********************************************/
292         if (devopen())
293                 return 1;
294
295 #ifndef RAWBOOT
296         /***********************************************\
297         * Load Filesystem info (mount the device)       *
298         \***********************************************/
299         devread((char *)(fs = (struct fs *)fsbuf), SBLOCK + boff, SBSIZE);
300         /***********************************************\
301         * Find the actual FILE on the mounted device    *
302         \***********************************************/
303         ret = find(cp);
304         name = cp;
305         if (ret == 0)
306                 return 1;
307         if (ret < 0) {
308                 name = NULL;
309                 return -1;
310         }
311         poff = 0;
312 #endif /* RAWBOOT */
313         return 0;
314 }