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