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