Merge from vendor branch GCC:
[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  * $DragonFly: src/sys/i386/boot/biosboot/Attic/sys.c,v 1.2 2003/06/17 04:28:34 dillon Exp $
29  */
30
31 #include "boot.h"
32 #include <sys/dirent.h>
33 #include <sys/reboot.h>
34
35 #if 0
36 /* #define BUFSIZE 4096 */
37 #define BUFSIZE MAXBSIZE
38
39 static char buf[BUFSIZE], fsbuf[SBSIZE], iobuf[MAXBSIZE];
40 #endif
41
42 static char biosdrivedigit;
43
44 #define BUFSIZE 8192
45 #define MAPBUFSIZE BUFSIZE
46 static char buf[BUFSIZE], fsbuf[BUFSIZE], iobuf[BUFSIZE];
47
48 static char mapbuf[MAPBUFSIZE];
49 static int mapblock;
50
51 int poff;
52
53 #ifdef RAWBOOT
54 #define STARTBYTE       8192    /* Where on the media the kernel starts */
55 #endif
56
57 static int block_map(int file_block);
58 static int find(char *path);
59
60 void
61 xread(char *addr, int size)
62 {
63         int count = BUFSIZE;
64         while (size > 0) {
65                 if (BUFSIZE > size)
66                         count = size;
67                 read(buf, count);
68                 pcpy(buf, addr, count);
69                 size -= count;
70                 addr += count;
71         }
72 }
73
74 #ifndef RAWBOOT
75 void
76 read(char *buffer, int count)
77 {
78         int logno, off, size;
79         int cnt2, bnum2;
80         struct fs *fs_copy;
81
82         while (count > 0 && poff < inode.i_size) {
83                 fs_copy = fs;
84                 off = blkoff(fs_copy, poff);
85                 logno = lblkno(fs_copy, poff);
86                 cnt2 = size = blksize(fs_copy, &inode, logno);
87                 bnum2 = fsbtodb(fs_copy, block_map(logno)) + boff;
88                 if (    (!off)  && (size <= count)) {
89                         devread(buffer, bnum2, cnt2);
90                 } else {
91                         size -= off;
92                         if (size > count)
93                                 size = count;
94                         devread(iobuf, bnum2, cnt2);
95                         bcopy(iobuf+off, buffer, size);
96                 }
97                 buffer += size;
98                 count -= size;
99                 poff += size;
100         }
101 }
102 #else
103 void
104 read(char *buffer, int count)
105 {
106         int cnt, bnum, off, size;
107
108         off = STARTBYTE + poff;
109         poff += count;
110
111         /* Read any unaligned bit at the front */
112         cnt = off & 511;
113         if (cnt) {
114                 size = 512-cnt;
115                 if (count < size)
116                         size = count;
117                 devread(iobuf, off >> 9, 512);
118                 bcopy(iobuf+cnt, buffer, size);
119                 count -= size;
120                 off += size;
121                 buffer += size;
122         }
123         size = count & (~511);
124         if (size && (off & (~511))) {
125                 devread(buffer, off >> 9, size);
126                 off += size;
127                 count -= size;
128                 buffer += size;
129         }
130         if (count) {
131                 devread(iobuf, off >> 9, 512);
132                 bcopy(iobuf, buffer, count);
133         }
134 }
135 #endif
136
137 static int
138 find(char *path)
139 {
140         char *rest, ch;
141         int block, off, loc, ino = ROOTINO;
142         struct dirent *dp;
143         char list_only;
144
145         list_only = (path[0] == '?' && path[1] == '\0');
146 loop:
147         devread(iobuf, fsbtodb(fs, ino_to_fsba(fs, ino)) + boff, fs->fs_bsize);
148         bcopy((void *)&((struct dinode *)iobuf)[ino % fs->fs_inopb],
149               (void *)&inode.i_din,
150               sizeof (struct dinode));
151         if (!*path)
152                 return 1;
153         while (*path == '/')
154                 path++;
155         if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
156                 return 0;
157         for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
158         *rest = 0;
159         loc = 0;
160         do {
161                 if (loc >= inode.i_size) {
162                         if (list_only) {
163                                 putchar('\n');
164                                 return -1;
165                         } else {
166                                 return 0;
167                         }
168                 }
169                 if (!(off = blkoff(fs, loc))) {
170                         block = lblkno(fs, loc);
171                         devread(iobuf, fsbtodb(fs, block_map(block)) + boff,
172                                 blksize(fs, &inode, block));
173                 }
174                 dp = (struct dirent *)(iobuf + off);
175                 loc += dp->d_reclen;
176                 if (dp->d_fileno && list_only)
177                         printf("%s ", dp->d_name);
178         } while (!dp->d_fileno || strcmp(path, dp->d_name));
179         ino = dp->d_fileno;
180         *(path = rest) = ch;
181         goto loop;
182 }
183
184
185 static int
186 block_map(int file_block)
187 {
188         int bnum;
189         if (file_block < NDADDR)
190                 return(inode.i_db[file_block]);
191         if ((bnum=fsbtodb(fs, inode.i_ib[0])+boff) != mapblock) {
192                 devread(mapbuf, bnum, fs->fs_bsize);
193                 mapblock = bnum;
194         }
195         return (((int *)mapbuf)[(file_block - NDADDR) % NINDIR(fs)]);
196 }
197
198
199 int
200 openrd(void)
201 {
202         char **devp, *name0 = name, *cp = name0;
203         int biosdrive, dosdev_copy, ret;
204
205         /*******************************************************\
206         * If bracket given look for preceding device name       *
207         \*******************************************************/
208         while (*cp && *cp!='(')
209                 cp++;
210         if (!*cp)
211         {
212                 cp = name0;
213         }
214         else
215         {
216                 /*
217                  * Look for a BIOS drive number (a leading digit followed
218                  * by a colon).
219                  */
220                 biosdrivedigit = '\0';
221                 if (*(name0 + 1) == ':' && *name0 >= '0' && *name0 <= '9') {
222                         biosdrivedigit = *name0;
223                         name0 += 2;
224                 }
225
226                 if (cp++ != name0)
227                 {
228                         for (devp = devs; *devp; devp++)
229                                 if (name0[0] == (*devp)[0] &&
230                                     name0[1] == (*devp)[1])
231                                         break;
232                         if (!*devp)
233                         {
234                                 printf("Unknown device\n");
235                                 return 1;
236                         }
237                         maj = devp-devs;
238                 }
239                 /*******************************************************\
240                 * Look inside brackets for unit number, and partition   *
241                 \*******************************************************/
242                 /*
243                  * Allow any valid digit as the unit number, as the BIOS
244                  * will complain if the unit number is out of range.
245                  * Restricting the range here prevents the possibilty of using
246                  * BIOSes that support more than 2 units.
247                  * XXX Bad values may cause strange errors, need to check if
248                  * what happens when a value out of range is supplied.
249                  */
250                 if (*cp >= '0' && *cp <= '9')
251                         unit = *cp++ - '0';
252                 if (!*cp || (*cp == ',' && !*++cp))
253                         return 1;
254                 if (*cp >= 'a' && *cp <= 'p')
255                         part = *cp++ - 'a';
256                 while (*cp && *cp++!=')') ;
257                 if (!*cp)
258                         return 1;
259         }
260         biosdrive = biosdrivedigit - '0';
261         if (biosdrivedigit == '\0') {
262                 biosdrive = unit;
263 #if BOOT_HD_BIAS > 0
264                 /* XXX */
265                 if (maj == 4)
266                         biosdrive += BOOT_HD_BIAS;
267 #endif
268         }
269         switch(maj)
270         {
271         case 0:
272         case 4:
273                 dosdev_copy = biosdrive | 0x80;
274                 break;
275         case 2:
276                 dosdev_copy = biosdrive;
277                 break;
278         default:
279                 printf("Unknown device\n");
280                 return 1;
281         }
282         dosdev = dosdev_copy;
283 #if 0
284         /* XXX this is useful, but misplaced. */
285         printf("dosdev= %x, biosdrive = %d, unit = %d, maj = %d\n",
286                 dosdev_copy, biosdrive, unit, maj);
287 #endif
288
289         /***********************************************\
290         * Now we know the disk unit and part,           *
291         * Load disk info, (open the device)             *
292         \***********************************************/
293         if (devopen())
294                 return 1;
295
296 #ifndef RAWBOOT
297         /***********************************************\
298         * Load Filesystem info (mount the device)       *
299         \***********************************************/
300         devread((char *)(fs = (struct fs *)fsbuf), SBLOCK + boff, SBSIZE);
301         /***********************************************\
302         * Find the actual FILE on the mounted device    *
303         \***********************************************/
304         ret = find(cp);
305         name = cp;
306         if (ret == 0)
307                 return 1;
308         if (ret < 0) {
309                 name = NULL;
310                 return -1;
311         }
312         poff = 0;
313 #endif /* RAWBOOT */
314         return 0;
315 }