main.c revision 181436
1251881Speter/*-
2251881Speter * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3251881Speter * All rights reserved.
4251881Speter *
5251881Speter * Redistribution and use in source and binary forms, with or without
6251881Speter * modification, are permitted provided that the following conditions
7251881Speter * are met:
8251881Speter * 1. Redistributions of source code must retain the above copyright
9251881Speter *    notice, this list of conditions and the following disclaimer.
10251881Speter * 2. Redistributions in binary form must reproduce the above copyright
11251881Speter *    notice, this list of conditions and the following disclaimer in the
12251881Speter *    documentation and/or other materials provided with the distribution.
13251881Speter *
14251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17251881Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24251881Speter * SUCH DAMAGE.
25251881Speter */
26251881Speter
27251881Speter#include <sys/cdefs.h>
28251881Speter__FBSDID("$FreeBSD: head/sys/boot/pc98/loader/main.c 181436 2008-08-08 19:41:20Z jhb $");
29251881Speter
30251881Speter/*
31251881Speter * MD bootstrap main() and assorted miscellaneous
32251881Speter * commands.
33251881Speter */
34251881Speter
35251881Speter#include <stand.h>
36251881Speter#include <string.h>
37251881Speter#include <machine/bootinfo.h>
38251881Speter#include <machine/psl.h>
39251881Speter#include <sys/reboot.h>
40251881Speter
41251881Speter#include "bootstrap.h"
42251881Speter#include "libi386/libi386.h"
43251881Speter#include "btxv86.h"
44251881Speter
45251881Speter#define	KARGS_FLAGS_CD		0x1
46251881Speter#define	KARGS_FLAGS_PXE		0x2
47251881Speter
48251881Speter/* Arguments passed in from the boot1/boot2 loader */
49251881Speterstatic struct
50251881Speter{
51251881Speter    u_int32_t	howto;
52251881Speter    u_int32_t	bootdev;
53251881Speter    u_int32_t	bootflags;
54251881Speter    u_int32_t	pxeinfo;
55251881Speter    u_int32_t	res2;
56251881Speter    u_int32_t	bootinfo;
57251881Speter} *kargs;
58251881Speter
59251881Speterstatic u_int32_t	initial_howto;
60251881Speterstatic u_int32_t	initial_bootdev;
61251881Speterstatic struct bootinfo	*initial_bootinfo;
62251881Speter
63251881Speterstruct arch_switch	archsw;		/* MI/MD interface boundary */
64251881Speter
65251881Speterstatic void		extract_currdev(void);
66251881Speterstatic int		isa_inb(int port);
67251881Speterstatic void		isa_outb(int port, int value);
68251881Spetervoid			exit(int code);
69251881Speter
70251881Speter/* from vers.c */
71251881Speterextern	char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
72251881Speter
73251881Speter/* XXX debugging */
74251881Speterextern char end[];
75251881Speter
76251881Speterstatic void *heap_top;
77251881Speterstatic void *heap_bottom;
78251881Speter
79251881Speterint
80251881Spetermain(void)
81251881Speter{
82251881Speter    int			i;
83251881Speter
84251881Speter    /* Pick up arguments */
85251881Speter    kargs = (void *)__args;
86251881Speter    initial_howto = kargs->howto;
87251881Speter    initial_bootdev = kargs->bootdev;
88251881Speter    initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL;
89251881Speter
90251881Speter    /* Initialize the v86 register set to a known-good state. */
91251881Speter    bzero(&v86, sizeof(v86));
92251881Speter    v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
93251881Speter
94251881Speter    /*
95251881Speter     * Initialise the heap as early as possible.  Once this is done, malloc() is usable.
96251881Speter     */
97251881Speter    bios_getmem();
98251881Speter
99251881Speter#ifdef LOADER_BZIP2_SUPPORT
100251881Speter    heap_top = PTOV(memtop_copyin);
101251881Speter    memtop_copyin -= 0x300000;
102251881Speter    heap_bottom = PTOV(memtop_copyin);
103251881Speter#else
104251881Speter    heap_top = (void *)bios_basemem;
105251881Speter    heap_bottom = (void *)end;
106251881Speter#endif
107251881Speter    setheap(heap_bottom, heap_top);
108251881Speter
109251881Speter    /*
110251881Speter     * XXX Chicken-and-egg problem; we want to have console output early, but some
111251881Speter     * console attributes may depend on reading from eg. the boot device, which we
112251881Speter     * can't do yet.
113251881Speter     *
114251881Speter     * We can use printf() etc. once this is done.
115251881Speter     * If the previous boot stage has requested a serial console, prefer that.
116251881Speter     */
117251881Speter    bi_setboothowto(initial_howto);
118251881Speter    if (initial_howto & RB_MULTIPLE) {
119251881Speter	if (initial_howto & RB_SERIAL)
120251881Speter	    setenv("console", "comconsole vidconsole", 1);
121251881Speter	else
122251881Speter	    setenv("console", "vidconsole comconsole", 1);
123251881Speter    } else if (initial_howto & RB_SERIAL)
124251881Speter	setenv("console", "comconsole", 1);
125251881Speter    else if (initial_howto & RB_MUTE)
126251881Speter	setenv("console", "nullconsole", 1);
127251881Speter    cons_probe();
128251881Speter
129251881Speter    /*
130251881Speter     * Initialise the block cache
131251881Speter     */
132251881Speter    bcache_init(32, 512);	/* 16k cache XXX tune this */
133251881Speter
134251881Speter    /*
135251881Speter     * Special handling for PXE and CD booting.
136251881Speter     */
137251881Speter    if (kargs->bootinfo == 0) {
138251881Speter	/*
139251881Speter	 * We only want the PXE disk to try to init itself in the below
140251881Speter	 * walk through devsw if we actually booted off of PXE.
141251881Speter	 */
142251881Speter	if (kargs->bootflags & KARGS_FLAGS_PXE)
143251881Speter	    pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL);
144251881Speter	else if (kargs->bootflags & KARGS_FLAGS_CD)
145251881Speter	    bc_add(initial_bootdev);
146251881Speter    }
147251881Speter
148251881Speter    /*
149251881Speter     * March through the device switch probing for things.
150251881Speter     */
151251881Speter    for (i = 0; devsw[i] != NULL; i++)
152251881Speter	if (devsw[i]->dv_init != NULL)
153251881Speter	    (devsw[i]->dv_init)();
154251881Speter    printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024);
155251881Speter    if (initial_bootinfo != NULL) {
156251881Speter	initial_bootinfo->bi_basemem = bios_basemem / 1024;
157251881Speter	initial_bootinfo->bi_extmem = bios_extmem / 1024;
158251881Speter    }
159251881Speter
160251881Speter    printf("\n");
161251881Speter    printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
162251881Speter    printf("(%s, %s)\n", bootprog_maker, bootprog_date);
163251881Speter
164251881Speter    extract_currdev();				/* set $currdev and $loaddev */
165251881Speter    setenv("LINES", "24", 1);			/* optional */
166251881Speter
167251881Speter    archsw.arch_autoload = i386_autoload;
168251881Speter    archsw.arch_getdev = i386_getdev;
169251881Speter    archsw.arch_copyin = i386_copyin;
170251881Speter    archsw.arch_copyout = i386_copyout;
171251881Speter    archsw.arch_readin = i386_readin;
172251881Speter    archsw.arch_isainb = isa_inb;
173251881Speter    archsw.arch_isaoutb = isa_outb;
174251881Speter
175251881Speter    interact();			/* doesn't return */
176251881Speter
177251881Speter    /* if we ever get here, it is an error */
178251881Speter    return (1);
179251881Speter}
180251881Speter
181251881Speter/*
182251881Speter * Set the 'current device' by (if possible) recovering the boot device as
183251881Speter * supplied by the initial bootstrap.
184251881Speter *
185251881Speter * XXX should be extended for netbooting.
186251881Speter */
187251881Speterstatic void
188251881Speterextract_currdev(void)
189251881Speter{
190251881Speter    struct i386_devdesc	new_currdev;
191251881Speter    int			major, biosdev = -1;
192251881Speter
193251881Speter    /* Assume we are booting from a BIOS disk by default */
194251881Speter    new_currdev.d_dev = &biosdisk;
195251881Speter
196251881Speter    /* new-style boot loaders such as pxeldr and cdldr */
197251881Speter    if (kargs->bootinfo == 0) {
198251881Speter        if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) {
199251881Speter	    /* we are booting from a CD with cdboot */
200251881Speter	    new_currdev.d_dev = &bioscd;
201251881Speter	    new_currdev.d_unit = bc_bios2unit(initial_bootdev);
202251881Speter	} else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) {
203251881Speter	    /* we are booting from pxeldr */
204251881Speter	    new_currdev.d_dev = &pxedisk;
205251881Speter	    new_currdev.d_unit = 0;
206251881Speter	} else {
207251881Speter	    /* we don't know what our boot device is */
208251881Speter	    new_currdev.d_kind.biosdisk.slice = -1;
209251881Speter	    new_currdev.d_kind.biosdisk.partition = 0;
210251881Speter	    biosdev = -1;
211251881Speter	}
212251881Speter    } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) {
213251881Speter	/* The passed-in boot device is bad */
214251881Speter	new_currdev.d_kind.biosdisk.slice = -1;
215251881Speter	new_currdev.d_kind.biosdisk.partition = 0;
216251881Speter	biosdev = -1;
217251881Speter    } else {
218251881Speter	new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1;
219251881Speter	new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev);
220251881Speter	biosdev = initial_bootinfo->bi_bios_dev;
221251881Speter	major = B_TYPE(initial_bootdev);
222251881Speter
223251881Speter	/*
224251881Speter	 * If we are booted by an old bootstrap, we have to guess at the BIOS
225251881Speter	 * unit number.  We will lose if there is more than one disk type
226251881Speter	 * and we are not booting from the lowest-numbered disk type
227251881Speter	 * (ie. SCSI when IDE also exists).
228251881Speter	 */
229251881Speter	if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) {	/* biosdev doesn't match major */
230251881Speter	    if (B_TYPE(initial_bootdev) == 6)
231251881Speter		biosdev = 0x30 + B_UNIT(initial_bootdev);
232251881Speter	    else
233251881Speter		biosdev = (major << 3) + 0x80 + B_UNIT(initial_bootdev);
234251881Speter	}
235251881Speter    }
236251881Speter    new_currdev.d_type = new_currdev.d_dev->dv_type;
237251881Speter
238251881Speter    /*
239251881Speter     * If we are booting off of a BIOS disk and we didn't succeed in determining
240251881Speter     * which one we booted off of, just use disk0: as a reasonable default.
241251881Speter     */
242251881Speter    if ((new_currdev.d_type == biosdisk.dv_type) &&
243251881Speter	((new_currdev.d_unit = bd_bios2unit(biosdev)) == -1)) {
244251881Speter	printf("Can't work out which disk we are booting from.\n"
245251881Speter	       "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev);
246251881Speter	new_currdev.d_unit = 0;
247251881Speter    }
248251881Speter    env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev),
249251881Speter	       i386_setcurrdev, env_nounset);
250251881Speter    env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset,
251251881Speter	       env_nounset);
252251881Speter}
253251881Speter
254251881SpeterCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
255251881Speter
256251881Speterstatic int
257251881Spetercommand_reboot(int argc, char *argv[])
258251881Speter{
259251881Speter    int i;
260251881Speter
261251881Speter    for (i = 0; devsw[i] != NULL; ++i)
262251881Speter	if (devsw[i]->dv_cleanup != NULL)
263251881Speter	    (devsw[i]->dv_cleanup)();
264251881Speter
265251881Speter    printf("Rebooting...\n");
266251881Speter    delay(1000000);
267251881Speter    __exit(0);
268251881Speter}
269251881Speter
270251881Speter/* provide this for panic, as it's not in the startup code */
271251881Spetervoid
272251881Speterexit(int code)
273251881Speter{
274251881Speter    __exit(code);
275251881Speter}
276251881Speter
277251881SpeterCOMMAND_SET(heap, "heap", "show heap usage", command_heap);
278251881Speter
279251881Speterstatic int
280251881Spetercommand_heap(int argc, char *argv[])
281251881Speter{
282251881Speter    mallocstats();
283251881Speter    printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom,
284251881Speter      sbrk(0), heap_top);
285251881Speter    return(CMD_OK);
286251881Speter}
287251881Speter
288251881Speter/* ISA bus access functions for PnP, derived from <machine/cpufunc.h> */
289251881Speterstatic int
290251881Speterisa_inb(int port)
291251881Speter{
292251881Speter    u_char	data;
293251881Speter
294251881Speter    if (__builtin_constant_p(port) &&
295251881Speter	(((port) & 0xffff) < 0x100) &&
296251881Speter	((port) < 0x10000)) {
297251881Speter	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
298251881Speter    } else {
299251881Speter	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
300251881Speter    }
301251881Speter    return(data);
302251881Speter}
303251881Speter
304251881Speterstatic void
305251881Speterisa_outb(int port, int value)
306251881Speter{
307251881Speter    u_char	al = value;
308251881Speter
309251881Speter    if (__builtin_constant_p(port) &&
310251881Speter	(((port) & 0xffff) < 0x100) &&
311251881Speter	((port) < 0x10000)) {
312251881Speter	__asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port)));
313251881Speter    } else {
314251881Speter        __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
315251881Speter    }
316251881Speter}
317251881Speter
318251881Speter