main.c revision 58871
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/boot/pc98/loader/main.c 58871 2000-03-31 16:03:02Z kato $
27 */
28
29/*
30 * MD bootstrap main() and assorted miscellaneous
31 * commands.
32 */
33
34#include <stand.h>
35#include <string.h>
36#include <machine/bootinfo.h>
37#include <sys/reboot.h>
38
39#include "bootstrap.h"
40#include "libi386/libi386.h"
41#include "btxv86.h"
42
43#define	KARGS_FLAGS_CD		0x1
44#define	KARGS_FLAGS_PXE		0x2
45
46/* Arguments passed in from the boot1/boot2 loader */
47static struct
48{
49    u_int32_t	howto;
50    u_int32_t	bootdev;
51    u_int32_t	bootflags;
52    u_int32_t	pxeinfo;
53    u_int32_t	res2;
54    u_int32_t	bootinfo;
55} *kargs;
56
57static u_int32_t	initial_howto;
58static u_int32_t	initial_bootdev;
59static struct bootinfo	*initial_bootinfo;
60
61struct arch_switch	archsw;		/* MI/MD interface boundary */
62
63static void		extract_currdev(void);
64static int		isa_inb(int port);
65static void		isa_outb(int port, int value);
66
67/* from vers.c */
68extern	char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
69
70/* XXX debugging */
71extern char end[];
72
73void
74main(void)
75{
76    int			i;
77
78    /* Pick up arguments */
79    kargs = (void *)__args;
80    initial_howto = kargs->howto;
81    initial_bootdev = kargs->bootdev;
82    initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL;
83
84    /*
85     * Initialise the heap as early as possible.  Once this is done, malloc() is usable.
86     */
87    bios_getmem();
88    setheap((void *)end, (void *)bios_basemem);
89
90    /*
91     * XXX Chicken-and-egg problem; we want to have console output early, but some
92     * console attributes may depend on reading from eg. the boot device, which we
93     * can't do yet.
94     *
95     * We can use printf() etc. once this is done.
96     * If the previous boot stage has requested a serial console, prefer that.
97     */
98    if (initial_howto & RB_SERIAL)
99	setenv("console", "comconsole", 1);
100    cons_probe();
101
102    /*
103     * Initialise the block cache
104     */
105    bcache_init(32, 512);	/* 16k cache XXX tune this */
106
107    /*
108     * We only want the PXE disk to try to init itself in the below walk through
109     * devsw if we actually booted off of PXE.
110     */
111    if((kargs->bootinfo == NULL) &&
112       ((kargs->bootflags & KARGS_FLAGS_PXE) != 0)) {
113      pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL);
114    }
115
116    /*
117     * March through the device switch probing for things.
118     */
119    for (i = 0; devsw[i] != NULL; i++)
120	if (devsw[i]->dv_init != NULL)
121	    (devsw[i]->dv_init)();
122    printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024);
123
124    printf("\n");
125    printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
126    printf("(%s, %s)\n", bootprog_maker, bootprog_date);
127
128    extract_currdev();				/* set $currdev and $loaddev */
129    setenv("LINES", "24", 1);			/* optional */
130
131    archsw.arch_autoload = i386_autoload;
132    archsw.arch_getdev = i386_getdev;
133    archsw.arch_copyin = i386_copyin;
134    archsw.arch_copyout = i386_copyout;
135    archsw.arch_readin = i386_readin;
136    archsw.arch_isainb = isa_inb;
137    archsw.arch_isaoutb = isa_outb;
138
139    interact();			/* doesn't return */
140}
141
142/*
143 * Set the 'current device' by (if possible) recovering the boot device as
144 * supplied by the initial bootstrap.
145 *
146 * XXX should be extended for netbooting.
147 */
148static void
149extract_currdev(void)
150{
151    struct i386_devdesc	currdev;
152    int			major, biosdev;
153
154    /* Assume we are booting from a BIOS disk by default */
155    currdev.d_dev = &biosdisk;
156    currdev.d_type = currdev.d_dev->dv_type;
157
158    /* new-style boot loaders such as pxeldr and cdldr */
159    if (kargs->bootinfo == NULL) {
160        if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) {
161	    /* we are booting from a CD with cdldr */
162	    currdev.d_kind.biosdisk.slice = -1;
163	    currdev.d_kind.biosdisk.partition = 0;
164	    biosdev = initial_bootdev;
165	} else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) {
166	    /* we are booting from pxeldr */
167	    currdev.d_dev = &pxedisk;
168	    currdev.d_type = currdev.d_dev->dv_type;
169	    currdev.d_kind.netif.unit = 0;
170	} else {
171	    /* we don't know what our boot device is */
172	    currdev.d_kind.biosdisk.slice = -1;
173	    currdev.d_kind.biosdisk.partition = 0;
174	    biosdev = -1;
175	}
176    } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) {
177	/* The passed-in boot device is bad */
178	currdev.d_kind.biosdisk.slice = -1;
179	currdev.d_kind.biosdisk.partition = 0;
180	biosdev = -1;
181    } else {
182	currdev.d_kind.biosdisk.slice = (B_ADAPTOR(initial_bootdev) << 4) +
183					 B_CONTROLLER(initial_bootdev) - 1;
184	currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev);
185	biosdev = initial_bootinfo->bi_bios_dev;
186	major = B_TYPE(initial_bootdev);
187
188	/*
189	 * If we are booted by an old bootstrap, we have to guess at the BIOS
190	 * unit number.  We will loose if there is more than one disk type
191	 * and we are not booting from the lowest-numbered disk type
192	 * (ie. SCSI when IDE also exists).
193	 */
194#ifdef PC98
195	if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) {	/* biosdev doesn't match major */
196	    if (B_TYPE(initial_bootdev) == 6)
197		biosdev = 0x30 + B_UNIT(initial_bootdev);
198	    else
199		biosdev = (major << 3) + 0x80 + B_UNIT(initial_bootdev);
200	}
201#else
202	if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2))	/* biosdev doesn't match major */
203	    biosdev = 0x80 + B_UNIT(initial_bootdev);		/* assume harddisk */
204#endif
205    }
206
207    /*
208     * If we are booting off of a BIOS disk and we didn't succeed in determining
209     * which one we booted off of, just use disk0: as a reasonable default.
210     */
211    if ((currdev.d_type == devsw[0]->dv_type) &&
212	((currdev.d_kind.biosdisk.unit = bd_bios2unit(biosdev)) == -1)) {
213	printf("Can't work out which disk we are booting from.\n"
214	       "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev);
215	currdev.d_kind.biosdisk.unit = 0;
216    }
217    env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&currdev), i386_setcurrdev, env_nounset);
218    env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&currdev), env_noset, env_nounset);
219}
220
221COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
222
223static int
224command_reboot(int argc, char *argv[])
225{
226
227    printf("Rebooting...\n");
228    delay(1000000);
229    __exit(0);
230}
231
232/* provide this for panic, as it's not in the startup code */
233void
234exit(int code)
235{
236    __exit(code);
237}
238
239COMMAND_SET(heap, "heap", "show heap usage", command_heap);
240
241static int
242command_heap(int argc, char *argv[])
243{
244    mallocstats();
245    printf("heap base at %p, top at %p\n", end, sbrk(0));
246    return(CMD_OK);
247}
248
249/* ISA bus access functions for PnP, derived from <machine/cpufunc.h> */
250static int
251isa_inb(int port)
252{
253    u_char	data;
254
255    if (__builtin_constant_p(port) &&
256	(((port) & 0xffff) < 0x100) &&
257	((port) < 0x10000)) {
258	__asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
259    } else {
260	__asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
261    }
262    return(data);
263}
264
265static void
266isa_outb(int port, int value)
267{
268    u_char	al = value;
269
270    if (__builtin_constant_p(port) &&
271	(((port) & 0xffff) < 0x100) &&
272	((port) < 0x10000)) {
273	__asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port)));
274    } else {
275        __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
276    }
277}
278
279