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