Merge from vendor branch LESS:
[dragonfly.git] / sys / i386 / boot / cdboot / 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/cdboot/boot.c,v 1.3 1999/08/28 00:43:17 peter Exp $
28  * $DragonFly: src/sys/i386/boot/cdboot/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 /*
56  * Extensions for El Torito CD-ROM booting:
57  *
58  * Copyright © 1997 Pluto Technologies International, Inc.  Boulder CO
59  * Copyright © 1997 interface business GmbH, Dresden.
60  *      All rights reserved.
61  *
62  * This code was written by Jörg Wunsch, Dresden.
63  * Direct comments to <joerg_wunsch@interface-business.de>.
64  *
65  * Redistribution and use in source and binary forms, with or without
66  * modification, are permitted provided that the following conditions
67  * are met:
68  * 1. Redistributions of source code must retain the above copyright
69  *    notice, this list of conditions and the following disclaimer.
70  * 2. Redistributions in binary form must reproduce the above copyright
71  *    notice, this list of conditions and the following disclaimer in the
72  *    documentation and/or other materials provided with the distribution.
73  *
74  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
75  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
76  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
77  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
78  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
79  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
80  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
81  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
82  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
83  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
84  * POSSIBILITY OF SUCH DAMAGE.
85  */
86
87 #include <sys/param.h>
88 #include "boot.h"
89 #include <a.out.h>
90 #include <sys/reboot.h>
91 #include <machine/bootinfo.h>
92 #ifdef PROBE_KEYBOARD_LOCK
93 #include <machine/cpufunc.h>
94 #endif
95
96 #define ouraddr (BOOTSEG << 4)          /* XXX */
97
98 int loadflags;
99
100 /*
101  * XXX
102  * By now, only "cd".  How do we learn from the BIOS we've been booted off
103  * an ATAPI CD-ROM?  Do the non-{cd,wcd} drivers implement El Torito booting
104  * at all?
105  */
106 static int maj = 6;
107 static struct specpacket spkt = { 0x13 };
108 static char *name;
109 static char namebuf[128];
110 static struct bootinfo bootinfo;
111
112 static void getbootdev(char *ptr, int *howto);
113 static void loadprog(void);
114
115 /* NORETURN */
116 void
117 boot(int drive)
118 {
119         int ret, i;
120
121 #ifdef PROBE_KEYBOARD
122         if (probe_keyboard()) {
123                 init_serial();
124                 loadflags |= RB_SERIAL;
125                 printf("\nNo keyboard found.");
126         }
127 #endif
128
129 #ifdef PROBE_KEYBOARD_LOCK
130         if (!(inb(0x64) & 0x10)) {
131                 init_serial();
132                 loadflags |= RB_SERIAL;
133                 printf("\nKeyboard locked.");
134         }
135 #endif
136
137 #ifdef FORCE_COMCONSOLE
138         init_serial();
139         loadflags |= RB_SERIAL;
140         printf("\nSerial console forced.");
141 #endif
142
143         /* Pick up the story from the Bios on geometry of disks */
144
145         /*
146          * XXX
147          * Do we need to defer this until we can relinguish the
148          * BIOS emulation?
149          */
150
151         for(ret = 0; ret < N_BIOS_GEOM; ret ++)
152                 bootinfo.bi_bios_geom[ret] = get_diskinfo(ret + 0x80);
153
154         bootinfo.bi_basemem = memsize(0);
155         bootinfo.bi_extmem = memsize(1);
156         bootinfo.bi_memsizes_valid = 1;
157
158         gateA20();
159
160         ret = getbootspec(&spkt);
161         if (ret != 0) {
162                 printf("Your BIOS int 0x13 extensions seem to be disabled.\n"
163                        "It's impossible to boot a CD-ROM without them.\n"
164                        "(BIOS int 0x13 fn 0x4b01 yielded error %d)\n",
165                        ret);
166                 while (1)
167                         ;
168         }
169
170         if (devopen(sessionstart) == -1)
171                 printf("Warning: cannot open default session.\n"
172                        "Maybe your BIOS int 0x13 extensions are disabled?\n"
173                        "You need them in order to boot a CD-ROM.\n");
174
175         for (;;) {
176                 
177                 /*
178                  * The El Torito specification stinks.  Not only this
179                  * crappy idea of `emulation booting' (and at least
180                  * earlier versions of the AHA-2940 BIOS didn't
181                  * implement anything else than floppy emulation
182                  * booting), but note also that there's absolutely no
183                  * way via the BIOS to obtain the starting LBA of your
184                  * session.  All you can get ahold of is the LBA of
185                  * that funny emulated disk.  Since this one just
186                  * happens to be a file hidden inside the ISO9660
187                  * filesystem, it is located at a varying offset from
188                  * the start of the session.  We therefore allow to
189                  * specify the starting block of the session to use in
190                  * the boot string, so the operator can specify the
191                  * session to boot from.  However, (s)he needs to know
192                  * the RBA for the session from the CD-ROM TOC.
193                  */
194                 DPRINTF(("using session at sector %d\n", sessionstart));
195
196                 name = "/kernel";
197                 printf("\n>> FreeBSD CD-ROM BOOT\n"
198                        "Usage: [@%d]%s[-abcCdghrsv]\n"
199                        "Use ? for file list or press Enter for defaults\n"
200                        "\nBoot: ",
201                        sessionstart, name);
202
203                 loadflags &= RB_SERIAL; /* clear all, but leave serial console */
204                 loadflags |= RB_CDROM;  /* ...and default to CD-ROM root. */
205
206                 getbootdev(namebuf, &loadflags);
207
208                 DPRINTF(("Selected: name=`%s', loadflags=0x%x\n",
209                          name, loadflags));
210
211                 ret = openrd(name);
212
213                 DPRINTF(("openrd() = %d\n", ret));
214
215                 if (ret != 0) {
216                         if (ret > 0)
217                                 printf("Can't find %s\n", name);
218                         continue;
219                 }
220                 loadprog();
221         }
222 }
223
224 static void
225 loadprog(void)
226 {
227         struct exec head;
228         u_int32_t startaddr, addr, bootdev;
229         int i;
230         unsigned pad;
231
232         seek(0);
233         if (read((void *)&head, sizeof(head)) == -1 ||
234             N_BADMAG(head)) {
235                 printf("Invalid format!\n");
236                 return;
237         }
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 CD-ROM [@%d]%s @ 0x%x\n", sessionstart, name, addr);
247         if(addr < 0x00100000)
248         {
249                 /*
250                  * Bail out, instead of risking to damage the BIOS
251                  * variables, the loader, or the adapter memory area.
252                  * We don't support loading below 1 MB any more.
253                  */
254                 printf("Start address too low\n");
255                 return;
256         }
257         printf("text=0x%x ", head.a_text);
258
259         /* load the text segment */
260         seek(N_TXTOFF(head));
261         if (xread((void *)addr, head.a_text) == -1)
262                 return;
263         addr += head.a_text;
264
265         /* Pad to a page boundary. */
266         pad = (unsigned)addr & PAGE_MASK;
267         if (pad != 0) {
268                 pad = PAGE_SIZE - pad;
269                 pbzero((void *)addr, pad);
270                 addr += pad;
271         }
272
273         /* load the initialised data after the text */
274         printf("data=0x%x ", head.a_data);
275         if (xread((void *)addr, head.a_data) == -1)
276                 return;
277         addr += head.a_data;
278
279         /* Skip over the uninitialised data (but clear it) */
280         printf("bss=0x%x ", head.a_bss);
281
282 /*
283  * XXX however, we should be checking that we don't load ... into
284  * nonexistent memory.  A full symbol table is unlikely to fit on 4MB
285  * machines.
286  */
287         pbzero((void *)addr, head.a_bss);
288         addr += head.a_bss;
289
290         /* Pad to a page boundary. */
291         pad = (unsigned)addr & PAGE_MASK;
292         if (pad != 0) {
293                 pad = PAGE_SIZE - pad;
294                 addr += pad;
295         }
296         bootinfo.bi_symtab = addr;
297
298         /* Copy the symbol table size */
299         pcpy(&head.a_syms, (void *)addr, sizeof(head.a_syms));
300         addr += sizeof(head.a_syms);
301
302         /* Load the symbol table */
303         printf("symbols=[+0x%x+0x%x+0x%x", pad, sizeof(head.a_syms),
304                head.a_syms);
305         if (xread((void *)addr, head.a_syms) == -1)
306                 return;
307         addr += head.a_syms;
308
309         /* Load the string table size */
310         if (read((void *)&i, sizeof(int)) == -1)
311                 return;
312         pcpy(&i, (void *)addr, sizeof(int));
313         i -= sizeof(int);
314         addr += sizeof(int);
315
316         /* Load the string table */
317         printf("+0x%x+0x%x]\n", sizeof(int), i);
318         if (xread((void *)addr, i) == -1)
319                 return;
320         addr += i;
321
322         bootinfo.bi_esymtab = addr;
323
324         /* XXX what else can we say about a CD-ROM? */
325         bootdev = MAKEBOOTDEV(maj, 0, 0, 0, 0);
326
327         bootinfo.bi_version = BOOTINFO_VERSION;
328         bootinfo.bi_kernelname = (u_int32_t)(name + ouraddr);
329         bootinfo.bi_nfs_diskless = 0;
330         bootinfo.bi_size = sizeof(bootinfo);
331         printf("total=0x%x entry point=0x%x\n", (int)addr, (int)startaddr);
332         startprog((int)startaddr, loadflags | RB_BOOTINFO, bootdev,
333                   (int)&bootinfo + ouraddr);
334 }
335
336 static void
337 getbootdev(char *ptr, int *howto)
338 {
339         char c;
340
341         /*
342          * Be paranoid and make doubly sure that the input buffer is empty.
343          */
344         if (*howto & RB_SERIAL)
345                 init_serial();
346
347         if (!gets(ptr)) {
348                 putchar('\n');
349                 return;
350         }
351         while ((c = *ptr) != '\0') {
352 nextarg:
353                 while (c == ' ')
354                         c = *++ptr;
355                 if (c == '-')
356                         while ((c = *++ptr) != '\0') {
357                                 if (c == ' ')
358                                         goto nextarg;
359                                 if (c == 'C')
360                                         *howto &= ~RB_CDROM;
361                                 if (c == 'a')
362                                         *howto |= RB_ASKNAME;
363                                 if (c == 'b')
364                                         *howto |= RB_HALT;
365                                 if (c == 'c')
366                                         *howto |= RB_CONFIG;
367                                 if (c == 'd')
368                                         *howto |= RB_KDB;
369                                 if (c == 'h') {
370                                         *howto ^= RB_SERIAL;
371                                         if (*howto & RB_SERIAL)
372                                                 init_serial();
373                                         continue;
374                                 }
375                                 if (c == 'g')
376                                         *howto |= RB_GDB;
377                                 if (c == 'r')
378                                         *howto |= RB_DFLTROOT;
379                                 if (c == 's')
380                                         *howto |= RB_SINGLE;
381                                 if (c == 'v')
382                                         *howto |= RB_VERBOSE;
383                         }
384                 if (c == '\0')
385                         return;
386                 name = ptr;
387                 while (*++ptr != '\0') {
388                         if (*ptr == ' ') {
389                                 *ptr++ = '\0';
390                                 break;
391                         }
392                 }
393         }
394 }