Merge from vendor branch GCC:
[dragonfly.git] / sys / i386 / boot / biosboot / boot.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, [92/04/03  16:51:14  rvb]
27  * $FreeBSD: src/sys/i386/boot/biosboot/boot.c,v 1.76 1999/12/08 09:32:47 phk Exp $
28  * $DragonFly: src/sys/i386/boot/biosboot/Attic/boot.c,v 1.2 2003/06/17 04:28:34 dillon Exp $
29  */
30
31
32 /*
33   Copyright 1988, 1989, 1990, 1991, 1992
34    by Intel Corporation, Santa Clara, California.
35
36                 All Rights Reserved
37
38 Permission to use, copy, modify, and distribute this software and
39 its documentation for any purpose and without fee is hereby
40 granted, provided that the above copyright notice appears in all
41 copies and that both the copyright notice and this permission notice
42 appear in supporting documentation, and that the name of Intel
43 not be used in advertising or publicity pertaining to distribution
44 of the software without specific, written prior permission.
45
46 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
47 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
48 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
49 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
50 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
51 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
52 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
53 */
54
55 #include <sys/param.h>
56 #include "boot.h"
57 #include <a.out.h>
58 #include <sys/reboot.h>
59 #include <machine/bootinfo.h>
60
61 #define ouraddr (BOOTSEG << 4)          /* XXX */
62
63 #define BOOT_CONFIG_SIZE        512
64 #define BOOT_HELP_SIZE          2048
65 #define KERNEL_CONFIG_SIZE      512
66 #define NAMEBUF_LEN             1024    /* oversized to defend against gets() */
67
68 static char boot_config[BOOT_CONFIG_SIZE];
69 static char boot_help[BOOT_HELP_SIZE];
70 #ifdef NAMEBLOCK
71 char *dflt_name;
72 #endif
73 char *name;
74 static char kernel_config[KERNEL_CONFIG_SIZE];
75 static char kernel_config_namebuf[NAMEBUF_LEN + sizeof "config"];
76 static char linebuf[NAMEBUF_LEN];
77 static char namebuf[NAMEBUF_LEN];
78 static struct bootinfo bootinfo;
79 int loadflags;
80
81 static void getbootdev(char *ptr, int *howto);
82 static void loadprog(void);
83 static void readfile(char *path, char *buf, size_t nbytes);
84
85 /* NORETURN */
86 void
87 boot(int drive)
88 {
89         int ret;
90
91         /* Pick up the story from the Bios on geometry of disks */
92
93         for(ret = 0; ret < N_BIOS_GEOM; ret ++)
94                 bootinfo.bi_bios_geom[ret] = get_diskinfo(ret + 0x80);
95
96         bootinfo.bi_basemem = memsize(0);
97         bootinfo.bi_extmem = memsize(1);
98         bootinfo.bi_memsizes_valid = 1;
99
100         gateA20();
101
102         /*
103          * The default boot device is the first partition in the
104          * compatibility slice on the boot drive.
105          */
106         dosdev = drive;
107         maj = 2;
108         unit = drive & 0x7f;
109 #ifdef dontneed
110         slice = 0;
111         part = 0;
112 #endif
113         if (drive & 0x80) {
114                 /* Hard drive.  Adjust. */
115                 maj = 0;
116 #if BOOT_HD_BIAS > 0
117                 if (unit >= BOOT_HD_BIAS) {
118                         /*
119                          * The drive is probably a SCSI drive with a unit
120                          * number BOOT_HD_BIAS less than the BIOS drive
121                          * number.
122                          */
123                         maj = 4;
124                         unit -= BOOT_HD_BIAS;
125                 }
126 #endif
127         }
128 #ifndef RAWBOOT
129         readfile("boot.config", boot_config, BOOT_CONFIG_SIZE);
130         readfile("boot.help", boot_help, BOOT_HELP_SIZE);
131 #endif
132 #ifdef  NAMEBLOCK
133         /*
134          * XXX
135          * DAMN! I don't understand why this is not being set 
136          * by the code in boot2.S
137          */
138         dflt_name= (char *)0x0000ffb0;
139         if( (*dflt_name++ == 'D') && (*dflt_name++ == 'N')) {
140                 name = dflt_name;
141         } else
142 #endif  /*NAMEBLOCK*/
143                 name = "kernel";
144         if (boot_config[0] != '\0') {
145                 printf("boot.config: %s", boot_config);
146                 getbootdev(boot_config, &loadflags);
147                 if (openrd() != 0)
148                         name = "kernel";
149         }
150 loadstart:
151         /* print this all each time.. (saves space to do so) */
152         /* If we have looped, use the previous entries as defaults */
153         printf("\r \n>> FreeBSD BOOT @ 0x%x: %d/%d k of memory, %s%s console\n"
154                "Boot default: %d:%s(%d,%c)%s\n"
155                "%s\n"
156                "boot: ",
157                ouraddr, bootinfo.bi_basemem, bootinfo.bi_extmem,
158                (loadflags & RB_SERIAL) ? "serial" : "internal",
159                (loadflags & RB_DUAL) ? "/dual" : "",
160                dosdev & 0x7f, devs[maj], unit, 'a' + part,
161                name ? name : "*specify_a_kernel_name*",
162                boot_help);
163
164         /*
165          * Ignore flags from previous attempted boot, if any.
166          * XXX this is now too strict.  Settings given in boot.config should
167          * not be changed.
168          */
169         loadflags &= (RB_DUAL | RB_SERIAL);
170
171         /*
172          * Be paranoid and make doubly sure that the input buffer is empty.
173          */
174         if (loadflags & (RB_DUAL | RB_SERIAL))
175                 init_serial();
176
177         if (!gets(linebuf))
178                 putchar('\n');
179         else
180                 getbootdev(linebuf, &loadflags);
181         if (name == NULL)
182                 goto loadstart;
183         ret = openrd();
184         if (ret != 0) {
185                 if (ret > 0)
186                         printf("Can't find %s\n", name);
187                 goto loadstart;
188         }
189 /*      if (inode.i_mode&IEXEC)
190                 loadflags |= RB_KDB;
191 */
192         loadprog();
193         goto loadstart;
194 }
195
196 static void
197 loadprog(void)
198 {
199         struct exec head;
200         int startaddr;
201         int addr;       /* physical address.. not directly useable */
202         int bootdev;
203         int i;
204         unsigned pad;
205         char *s, *t;
206
207         read((void *)&head, sizeof(head));
208         if ( N_BADMAG(head)) {
209                 printf("Invalid format!\n");
210                 return;
211         }
212
213         poff = N_TXTOFF(head);
214         /*if(poff==0)
215                 poff = 32;*/
216
217         /*
218          * We assume that the entry address is the same as the lowest text
219          * address and that the kernel startup code handles relocation by
220          * this address rounded down to a multiple of 16M.
221          */
222         startaddr = head.a_entry & 0x00FFFFFF;
223         addr =  startaddr;
224         printf("Booting %d:%s(%d,%c)%s @ 0x%x\n"
225                         , dosdev & 0x7f
226                         , devs[maj]
227                         , unit
228                         , 'a'+part
229                         , name
230                         , addr);
231         if(addr < 0x00100000)
232         {
233                 /*
234                  * Bail out, instead of risking to damage the BIOS
235                  * variables, the loader, or the adapter memory area.
236                  * We don't support loading below 1 MB any more.
237                  */
238                 printf("Start address too low\n");
239                 return;
240         }
241         printf("text=0x%x ", head.a_text);
242         /********************************************************/
243         /* LOAD THE TEXT SEGMENT                                */
244         /********************************************************/
245         xread((void *)addr, head.a_text);
246         addr += head.a_text;
247
248         /********************************************************/
249         /* Load the Initialised data after the text             */
250         /********************************************************/
251         while (addr & PAGE_MASK)
252                 *(char *)addr++ = 0;
253
254         printf("data=0x%x ", head.a_data);
255         xread((void *)addr, head.a_data);
256         addr += head.a_data;
257
258         /********************************************************/
259         /* Skip over the uninitialised data                     */
260         /* (but clear it)                                       */
261         /********************************************************/
262         printf("bss=0x%x ", head.a_bss);
263
264 /*
265  * XXX however, we should be checking that we don't load ... into
266  * nonexistent memory.  A full symbol table is unlikely to fit on 4MB
267  * machines.
268  */
269         /* kzip & kernel will zero their own bss */
270         addr += head.a_bss;
271
272         /* Pad to a page boundary. */
273         pad = (unsigned)addr & PAGE_MASK;
274         if (pad != 0) {
275                 pad = PAGE_SIZE - pad;
276                 addr += pad;
277         }
278         bootinfo.bi_symtab = addr;
279
280         /********************************************************/
281         /* Copy the symbol table size                           */
282         /********************************************************/
283         pcpy(&head.a_syms, (void *)addr, sizeof(head.a_syms));
284         addr += sizeof(head.a_syms);
285
286         /********************************************************/
287         /* Load the symbol table                                */
288         /********************************************************/
289         printf("symbols=[+0x%x+0x%x+0x%x", pad, sizeof(head.a_syms),
290                head.a_syms);
291         xread((void *)addr, head.a_syms);
292         addr += head.a_syms;
293
294         /********************************************************/
295         /* Load the string table size                           */
296         /********************************************************/
297         read((void *)&i, sizeof(int));
298         pcpy(&i, (void *)addr, sizeof(int));
299         i -= sizeof(int);
300         addr += sizeof(int);
301
302         /********************************************************/
303         /* Load the string table                                */
304         /********************************************************/
305        printf("+0x%x+0x%x]\n", sizeof(int), i);
306         xread((void *)addr, i);
307         addr += i;
308
309         bootinfo.bi_esymtab = addr;
310
311         /*
312          * For backwards compatibility, use the previously-unused adaptor
313          * and controller bitfields to hold the slice number.
314          */
315         bootdev = MAKEBOOTDEV(maj, (slice >> 4), slice & 0xf, unit, part);
316
317         bootinfo.bi_version = BOOTINFO_VERSION;
318         bootinfo.bi_kernelname = (u_int32_t)(name + ouraddr);
319         bootinfo.bi_nfs_diskless = 0;
320         bootinfo.bi_size = sizeof(bootinfo);
321         bootinfo.bi_bios_dev = dosdev;
322
323         /*
324          * Load the kernel config file (if any).  Its name is given by
325          * appending ".config" to the kernel name.  Build the name inline
326          * because no str*() functions are available.  The file has to be
327          * copied to &disklabel for userconfig.  It can't be loaded there
328          * directly because the label is used late in readfile() in some
329          * unusual cases.
330          */
331         s = name;
332         t = kernel_config_namebuf;
333         do
334                 ;
335         while ((*t++ = *s++) != '\0');
336         s = ".config";
337         --t;
338         do
339                 ;
340         while ((*t++ = *s++) != '\0');
341         readfile(kernel_config_namebuf, kernel_config, KERNEL_CONFIG_SIZE);
342         pcpy(kernel_config, (char *)&disklabel + ouraddr, KERNEL_CONFIG_SIZE);
343
344         printf("total=0x%x entry point=0x%x\n", addr, startaddr);
345         startprog(startaddr, loadflags | RB_BOOTINFO, bootdev,
346                   (unsigned)&bootinfo + ouraddr);
347 }
348
349 static void
350 readfile(char *path, char *buf, size_t nbytes)
351 {
352         int openstatus;
353
354         buf[0] = '\0';
355         name = path;
356         openstatus = openrd();
357         if (openstatus != 0) {
358                 if (openstatus > 0)
359                         printf("Can't find file %s\n", name);
360         } else {
361                 /* XXX no way to determine file size. */
362                 read(buf, nbytes);
363         }
364         buf[nbytes - 1] = '\0';
365 }
366
367 static void
368 getbootdev(char *ptr, int *howto)
369 {
370         char c;
371         int f;
372         char *p;
373
374         /* Copy the flags to save some bytes. */
375         f = *howto;
376
377         c = *ptr;
378         for (;;) {
379 nextarg:
380                 while (c == ' ' || c == '\n')
381                         c = *++ptr;
382                 if (c == '-')
383                         while ((c = *++ptr) != '\0') {
384                                 if (c == ' ' || c == '\n')
385                                         goto nextarg;
386                                 if (c == 'a')
387                                         f |= RB_ASKNAME;
388                                 if (c == 'C')
389                                         f |= RB_CDROM;
390                                 if (c == 'c')
391                                         f |= RB_CONFIG;
392                                 if (c == 'D')
393                                         f ^= RB_DUAL;
394                                 if (c == 'd')
395                                         f |= RB_KDB;
396                                 if (c == 'g')
397                                         f |= RB_GDB;
398                                 if (c == 'h')
399                                         f ^= RB_SERIAL;
400                                 if (c == 'P')
401                                         f |= RB_PROBEKBD;
402                                 if (c == 'r')
403                                         f |= RB_DFLTROOT;
404                                 if (c == 's')
405                                         f |= RB_SINGLE;
406                                 if (c == 'v')
407                                         f |= RB_VERBOSE;
408                         }
409                 if (c == '\0')
410                         break;
411                 p = name = namebuf;
412                 while (c != '\0' && c != ' ' && c != '\n') {
413                         *p++ = c;
414                         c = *++ptr;
415                 }
416                 *p = '\0';
417         }
418         if (f & RB_PROBEKBD) {
419                 if (probe_keyboard()) {
420                         f |= RB_DUAL | RB_SERIAL;
421                         printf("No keyboard found\n");
422                 } else
423                         printf("Keyboard found\n");
424         }
425         if (f & (RB_DUAL | RB_SERIAL))
426                 init_serial();
427         *howto = f;
428 }