Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / boot / pc98 / boot2 / 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/boot/pc98/boot2/boot.c,v 1.6.2.3 2003/01/13 08:52:53 nyan 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 char *name;
70 static char kernel_config[KERNEL_CONFIG_SIZE];
71 static char kernel_config_namebuf[NAMEBUF_LEN + sizeof "config"];
72 static char linebuf[NAMEBUF_LEN];
73 static char namebuf[NAMEBUF_LEN];
74 static struct bootinfo bootinfo;
75 int loadflags;
76
77 static void getbootdev(char *ptr, int *howto);
78 static void loadprog(void);
79 static void readfile(char *path, char *buf, size_t nbytes);
80
81 /* NORETURN */
82 void
83 boot(int drive)
84 {
85         int ret;
86 #ifdef PC98
87         int i;
88         unsigned char disk_equips;
89 #endif
90
91         /* Pick up the story from the Bios on geometry of disks */
92
93 #ifdef PC98
94         for(ret = 0; ret < 2; ret ++) {
95                 if (*(unsigned char*)V(0xA155d) & (1 << ret)) {
96                         bootinfo.bi_bios_geom[ret] = get_diskinfo(ret + 0x80);
97                 }
98         }
99 #else /* IBM-PC */
100         for(ret = 0; ret < N_BIOS_GEOM; ret ++)
101                 bootinfo.bi_bios_geom[ret] = get_diskinfo(ret + 0x80);
102 #endif /* PC98 */
103
104         bootinfo.bi_basemem = memsize(0);
105         bootinfo.bi_extmem = memsize(1);
106         bootinfo.bi_memsizes_valid = 1;
107
108         gateA20();
109
110 #ifdef PC98
111         /* set machine type to PC98_SYSTEM_PARAMETER */
112         machine_check();
113 #endif /* PC98 */
114
115         /*
116          * The default boot device is the first partition in the
117          * compatibility slice on the boot drive.
118          */
119         dosdev = drive;
120 #ifdef PC98
121         maj = (drive&0x70) >> 3;                /* a good first bet */
122         if (maj == 4) { /* da */
123                 disk_equips = *(unsigned char *)V(0xA1482);
124                 unit = 0;
125                 for (i=0; i<(drive&0x0f); i++) {
126                         int media = ((unsigned *)V(0xA1460))[i] & 0x1F;
127
128                         if ((disk_equips >> i) & 1)     /* HD */
129                                 unit++;
130                         else if (media == 7)            /* MO */
131                                 unit++;
132                 }
133         } else {
134                 unit = drive & 0x0f;
135         }
136 #else /* IBM-PC */
137         maj = 2;
138         unit = drive & 0x7f;
139 #ifdef dontneed
140         slice = 0;
141         part = 0;
142 #endif
143         if (drive & 0x80) {
144                 /* Hard drive.  Adjust. */
145                 maj = 0;
146 #if BOOT_HD_BIAS > 0
147                 if (unit >= BOOT_HD_BIAS) {
148                         /*
149                          * The drive is probably a SCSI drive with a unit
150                          * number BOOT_HD_BIAS less than the BIOS drive
151                          * number.
152                          */
153                         maj = 4;
154                         unit -= BOOT_HD_BIAS;
155                 }
156 #endif
157         }
158 #endif /* PC98 */
159         readfile("boot.config", boot_config, BOOT_CONFIG_SIZE);
160                 name = "/boot/loader";
161         if (boot_config[0] != '\0') {
162                 printf("boot.config: %s", boot_config);
163                 getbootdev(boot_config, &loadflags);
164                 if (openrd() != 0)
165                         name = "kernel";
166         }
167 loadstart:
168         /* print this all each time.. (saves space to do so) */
169         /* If we have looped, use the previous entries as defaults */
170         printf("\r \n>> FreeBSD BOOT @ 0x%x: %d/%d k of memory, %s%s console\n"
171                "Boot default: %d:%s(%d,%c)%s\n"
172                "%s\n"
173                "boot: ",
174                ouraddr, bootinfo.bi_basemem, bootinfo.bi_extmem,
175                (loadflags & RB_SERIAL) ? "serial" : "internal",
176                (loadflags & RB_DUAL) ? "/dual" : "",
177 #ifdef PC98
178                dosdev & 0x0f, devs[maj], unit, 'a' + part,
179 #else
180                dosdev & 0x7f, devs[maj], unit, 'a' + part,
181 #endif
182                name ? name : "*specify_a_kernel_name*",
183                boot_help);
184
185         /*
186          * Ignore flags from previous attempted boot, if any.
187          * XXX this is now too strict.  Settings given in boot.config should
188          * not be changed.
189          */
190         loadflags &= (RB_DUAL | RB_SERIAL);
191
192         /*
193          * Be paranoid and make doubly sure that the input buffer is empty.
194          */
195         if (loadflags & (RB_DUAL | RB_SERIAL))
196                 init_serial();
197
198         if (!gets(linebuf))
199                 putchar('\n');
200         else
201                 getbootdev(linebuf, &loadflags);
202         if (name == NULL)
203                 goto loadstart;
204         ret = openrd();
205         if (ret != 0) {
206                 if (ret > 0)
207                         printf("Can't find %s\n", name);
208                 goto loadstart;
209         }
210 /*      if (inode.i_mode&IEXEC)
211                 loadflags |= RB_KDB;
212 */
213         loadprog();
214         goto loadstart;
215 }
216
217 static void
218 loadprog(void)
219 {
220         struct exec head;
221         int startaddr;
222         int addr;       /* physical address.. not directly useable */
223         int bootdev;
224         int i;
225         unsigned pad;
226         char *s, *t;
227
228         read((void *)&head, sizeof(head));
229         if ( N_BADMAG(head)) {
230                 printf("Invalid format!\n");
231                 return;
232         }
233
234         poff = N_TXTOFF(head);
235         /*if(poff==0)
236                 poff = 32;*/
237
238         /*
239          * We assume that the entry address is the same as the lowest text
240          * address and that the kernel startup code handles relocation by
241          * this address rounded down to a multiple of 16M.
242          */
243         startaddr = head.a_entry & 0x00FFFFFF;
244         addr =  startaddr;
245         printf("Booting %d:%s(%d,%c)%s @ 0x%x\n"
246 #ifdef PC98
247                         , dosdev & 0x0f
248 #else
249                         , dosdev & 0x7f
250 #endif
251                         , devs[maj]
252                         , unit
253                         , 'a'+part
254                         , name
255                         , addr);
256         if(addr < 0x00100000)
257         {
258                 /*
259                  * Bail out, instead of risking to damage the BIOS
260                  * variables, the loader, or the adapter memory area.
261                  * We don't support loading below 1 MB any more.
262                  */
263                 printf("Start address too low\n");
264                 return;
265         }
266         printf("text=0x%x ", head.a_text);
267         /********************************************************/
268         /* LOAD THE TEXT SEGMENT                                */
269         /********************************************************/
270         xread((void *)addr, head.a_text);
271         addr += head.a_text;
272
273         /********************************************************/
274         /* Load the Initialised data after the text             */
275         /********************************************************/
276         while (addr & PAGE_MASK)
277                 *(char *)addr++ = 0;
278
279         printf("data=0x%x ", head.a_data);
280         xread((void *)addr, head.a_data);
281         addr += head.a_data;
282
283         /********************************************************/
284         /* Skip over the uninitialised data                     */
285         /* (but clear it)                                       */
286         /********************************************************/
287         printf("bss=0x%x ", head.a_bss);
288
289 /*
290  * XXX however, we should be checking that we don't load ... into
291  * nonexistent memory.  A full symbol table is unlikely to fit on 4MB
292  * machines.
293  */
294         /* kzip & kernel will zero their own bss */
295         addr += head.a_bss;
296
297         /* Pad to a page boundary. */
298         pad = (unsigned)addr & PAGE_MASK;
299         if (pad != 0) {
300                 pad = PAGE_SIZE - pad;
301                 addr += pad;
302         }
303         bootinfo.bi_symtab = addr;
304
305         /********************************************************/
306         /* Copy the symbol table size                           */
307         /********************************************************/
308         pcpy(&head.a_syms, (void *)addr, sizeof(head.a_syms));
309         addr += sizeof(head.a_syms);
310
311         /********************************************************/
312         /* Load the symbol table                                */
313         /********************************************************/
314         printf("symbols=[+0x%x+0x%x+0x%x", pad, sizeof(head.a_syms),
315                head.a_syms);
316         xread((void *)addr, head.a_syms);
317         addr += head.a_syms;
318
319         /********************************************************/
320         /* Load the string table size                           */
321         /********************************************************/
322         read((void *)&i, sizeof(int));
323         pcpy(&i, (void *)addr, sizeof(int));
324         i -= sizeof(int);
325         addr += sizeof(int);
326
327         /********************************************************/
328         /* Load the string table                                */
329         /********************************************************/
330        printf("+0x%x+0x%x]\n", sizeof(int), i);
331         xread((void *)addr, i);
332         addr += i;
333
334         bootinfo.bi_esymtab = addr;
335
336         /*
337          * For backwards compatibility, use the previously-unused adaptor
338          * and controller bitfields to hold the slice number.
339          */
340         bootdev = MAKEBOOTDEV(maj, (slice >> 4), slice & 0xf, unit, part);
341
342         bootinfo.bi_version = BOOTINFO_VERSION;
343         bootinfo.bi_kernelname = (u_int32_t)(name + ouraddr);
344         bootinfo.bi_nfs_diskless = 0;
345         bootinfo.bi_size = sizeof(bootinfo);
346         bootinfo.bi_bios_dev = dosdev;
347
348         /*
349          * Load the kernel config file (if any).  Its name is given by
350          * appending ".config" to the kernel name.  Build the name inline
351          * because no str*() functions are available.  The file has to be
352          * copied to &disklabel for userconfig.  It can't be loaded there
353          * directly because the label is used late in readfile() in some
354          * unusual cases.
355          */
356         s = name;
357         t = kernel_config_namebuf;
358         do
359                 ;
360         while ((*t++ = *s++) != '\0');
361         s = ".config";
362         --t;
363         do
364                 ;
365         while ((*t++ = *s++) != '\0');
366         readfile(kernel_config_namebuf, kernel_config, KERNEL_CONFIG_SIZE);
367         pcpy(kernel_config, (char *)&disklabel + ouraddr, KERNEL_CONFIG_SIZE);
368
369         printf("total=0x%x entry point=0x%x\n", addr, startaddr);
370         startprog(startaddr, loadflags | RB_BOOTINFO, bootdev,
371                   (unsigned)&bootinfo + ouraddr);
372 }
373
374 static void
375 readfile(char *path, char *buf, size_t nbytes)
376 {
377         int openstatus;
378
379         buf[0] = '\0';
380         name = path;
381         openstatus = openrd();
382         if (openstatus == 0) {
383                 /* XXX no way to determine file size. */
384                 read(buf, nbytes);
385         }
386         buf[nbytes - 1] = '\0';
387 }
388
389 static void
390 getbootdev(char *ptr, int *howto)
391 {
392         char c;
393         int f;
394         char *p;
395
396         /* Copy the flags to save some bytes. */
397         f = *howto;
398
399         c = *ptr;
400         for (;;) {
401 nextarg:
402                 while (c == ' ' || c == '\n')
403                         c = *++ptr;
404                 if (c == '-')
405                         while ((c = *++ptr) != '\0') {
406                                 if (c == ' ' || c == '\n')
407                                         goto nextarg;
408                                 if (c == 'a')
409                                         f |= RB_ASKNAME;
410                                 if (c == 'C')
411                                         f |= RB_CDROM;
412                                 if (c == 'c')
413                                         f |= RB_CONFIG;
414                                 if (c == 'D')
415                                         f ^= RB_DUAL;
416                                 if (c == 'd')
417                                         f |= RB_KDB;
418                                 if (c == 'g')
419                                         f |= RB_GDB;
420                                 if (c == 'h')
421                                         f ^= RB_SERIAL;
422                                 if (c == 'P')
423                                         f |= RB_PROBEKBD;
424                                 if (c == 'r')
425                                         f |= RB_DFLTROOT;
426                                 if (c == 's')
427                                         f |= RB_SINGLE;
428                                 if (c == 'v')
429                                         f |= RB_VERBOSE;
430                         }
431                 if (c == '\0')
432                         break;
433                 p = name = namebuf;
434                 while (c != '\0' && c != ' ' && c != '\n') {
435                         *p++ = c;
436                         c = *++ptr;
437                 }
438                 *p = '\0';
439         }
440         if (f & RB_PROBEKBD) {
441                 if (probe_keyboard()) {
442                         f |= RB_DUAL | RB_SERIAL;
443                         printf("No keyboard found\n");
444                 } else
445                         printf("Keyboard found\n");
446         }
447         if (f & (RB_DUAL | RB_SERIAL))
448                 init_serial();
449         *howto = f;
450 }