main.c revision 240854
1234285Sdim/*-
2234285Sdim * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3234285Sdim * All rights reserved.
4234285Sdim *
5234285Sdim * Redistribution and use in source and binary forms, with or without
6234285Sdim * modification, are permitted provided that the following conditions
7234285Sdim * are met:
8234285Sdim * 1. Redistributions of source code must retain the above copyright
9234285Sdim *    notice, this list of conditions and the following disclaimer.
10234285Sdim * 2. Redistributions in binary form must reproduce the above copyright
11234285Sdim *    notice, this list of conditions and the following disclaimer in the
12234285Sdim *    documentation and/or other materials provided with the distribution.
13234285Sdim *
14234285Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15234285Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16234285Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17234285Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18234285Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19234285Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20234285Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21234285Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22249423Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23234285Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24249423Sdim * SUCH DAMAGE.
25249423Sdim */
26249423Sdim
27234285Sdim#include <sys/cdefs.h>
28234285Sdim__FBSDID("$FreeBSD: head/sys/boot/pc98/loader/main.c 240854 2012-09-23 08:50:54Z nyan $");
29234285Sdim
30234285Sdim/*
31234285Sdim * MD bootstrap main() and assorted miscellaneous
32234285Sdim * commands.
33249423Sdim */
34249423Sdim
35249423Sdim#include <stand.h>
36249423Sdim#include <stddef.h>
37249423Sdim#include <string.h>
38234285Sdim#include <machine/bootinfo.h>
39234285Sdim#include <machine/cpufunc.h>
40234285Sdim#include <sys/param.h>
41234285Sdim#include <sys/reboot.h>
42234285Sdim
43234285Sdim#include "bootstrap.h"
44234285Sdim#include "common/bootargs.h"
45234285Sdim#include "libi386/libi386.h"
46249423Sdim#include "libpc98/libpc98.h"
47234285Sdim#include "btxv86.h"
48234285Sdim
49249423SdimCTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE);
50249423SdimCTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO);
51234285SdimCTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS);
52234285SdimCTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE);
53249423Sdim
54234285Sdim/* Arguments passed in from the boot1/boot2 loader */
55249423Sdimstatic struct bootargs *kargs;
56234285Sdim
57234285Sdimstatic u_int32_t	initial_howto;
58234285Sdimstatic u_int32_t	initial_bootdev;
59234285Sdimstatic struct bootinfo	*initial_bootinfo;
60234285Sdim
61234285Sdimstruct arch_switch	archsw;		/* MI/MD interface boundary */
62234285Sdim
63234285Sdimstatic void		extract_currdev(void);
64234285Sdimstatic int		isa_inb(int port);
65234285Sdimstatic void		isa_outb(int port, int value);
66234285Sdimvoid			exit(int code);
67234285Sdim
68234285Sdim/* from vers.c */
69234285Sdimextern	char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
70234285Sdim
71234285Sdim/* XXX debugging */
72234285Sdimextern char end[];
73234285Sdim
74234285Sdimstatic void *heap_top;
75234285Sdimstatic void *heap_bottom;
76234285Sdim
77234285Sdimstatic uint64_t
78234285Sdimpc98_loadaddr(u_int type, void *data, uint64_t addr)
79234285Sdim{
80239462Sdim	struct stat st;
81234285Sdim
82234285Sdim	if (type == LOAD_ELF)
83234285Sdim		return (roundup(addr, PAGE_SIZE));
84234285Sdim
85234285Sdim	/* We cannot use 15M-16M area on pc98. */
86234285Sdim	if (type == LOAD_RAW && addr < 0x1000000 && stat(data, &st) == 0 &&
87234285Sdim	    (st.st_size == -1 || addr + st.st_size > 0xf00000))
88234285Sdim		addr = 0x1000000;
89234285Sdim	return (addr);
90234285Sdim}
91234285Sdim
92234285Sdimint
93234285Sdimmain(void)
94234285Sdim{
95234285Sdim    int			i;
96234285Sdim
97234285Sdim    /* Set machine type to PC98_SYSTEM_PARAMETER. */
98234285Sdim    set_machine_type();
99234285Sdim
100234285Sdim    /* Pick up arguments */
101234285Sdim    kargs = (void *)__args;
102263508Sdim    initial_howto = kargs->howto;
103234285Sdim    initial_bootdev = kargs->bootdev;
104234285Sdim    initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL;
105234285Sdim
106234285Sdim    /* Initialize the v86 register set to a known-good state. */
107234285Sdim    bzero(&v86, sizeof(v86));
108234285Sdim    v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
109234285Sdim
110234285Sdim    /*
111234285Sdim     * Initialise the heap as early as possible.  Once this is done, malloc() is usable.
112234285Sdim     */
113234285Sdim    bios_getmem();
114234285Sdim
115234285Sdim#if defined(LOADER_BZIP2_SUPPORT)
116234285Sdim    if (high_heap_size > 0) {
117234285Sdim	heap_top = PTOV(high_heap_base + high_heap_size);
118234285Sdim	heap_bottom = PTOV(high_heap_base);
119234285Sdim	if (high_heap_base < memtop_copyin)
120234285Sdim	    memtop_copyin = high_heap_base;
121234285Sdim    } else
122234285Sdim#endif
123234285Sdim    {
124234285Sdim	heap_top = (void *)PTOV(bios_basemem);
125234285Sdim	heap_bottom = (void *)end;
126234285Sdim    }
127234285Sdim    setheap(heap_bottom, heap_top);
128234285Sdim
129234285Sdim    /*
130234285Sdim     * XXX Chicken-and-egg problem; we want to have console output early, but some
131234285Sdim     * console attributes may depend on reading from eg. the boot device, which we
132234285Sdim     * can't do yet.
133234285Sdim     *
134234285Sdim     * We can use printf() etc. once this is done.
135234285Sdim     * If the previous boot stage has requested a serial console, prefer that.
136239462Sdim     */
137239462Sdim    bi_setboothowto(initial_howto);
138239462Sdim    if (initial_howto & RB_MULTIPLE) {
139234285Sdim	if (initial_howto & RB_SERIAL)
140234285Sdim	    setenv("console", "comconsole vidconsole", 1);
141234285Sdim	else
142234285Sdim	    setenv("console", "vidconsole comconsole", 1);
143234285Sdim    } else if (initial_howto & RB_SERIAL)
144234285Sdim	setenv("console", "comconsole", 1);
145234285Sdim    else if (initial_howto & RB_MUTE)
146234285Sdim	setenv("console", "nullconsole", 1);
147234285Sdim    cons_probe();
148234285Sdim
149234285Sdim    /*
150234285Sdim     * Initialise the block cache
151234285Sdim     */
152234285Sdim    bcache_init(32, 512);	/* 16k cache XXX tune this */
153234285Sdim
154234285Sdim    /*
155234285Sdim     * Special handling for PXE and CD booting.
156234285Sdim     */
157234285Sdim    if (kargs->bootinfo == 0) {
158234285Sdim	/*
159234285Sdim	 * We only want the PXE disk to try to init itself in the below
160234285Sdim	 * walk through devsw if we actually booted off of PXE.
161234285Sdim	 */
162234285Sdim	if (kargs->bootflags & KARGS_FLAGS_PXE)
163234285Sdim	    pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL);
164234285Sdim	else if (kargs->bootflags & KARGS_FLAGS_CD)
165234285Sdim	    bc_add(initial_bootdev);
166234285Sdim    }
167234285Sdim
168234285Sdim    archsw.arch_autoload = i386_autoload;
169234285Sdim    archsw.arch_getdev = i386_getdev;
170234285Sdim    archsw.arch_copyin = i386_copyin;
171234285Sdim    archsw.arch_copyout = i386_copyout;
172234285Sdim    archsw.arch_readin = i386_readin;
173234285Sdim    archsw.arch_isainb = isa_inb;
174234285Sdim    archsw.arch_isaoutb = isa_outb;
175234285Sdim    archsw.arch_loadaddr = pc98_loadaddr;
176234285Sdim
177234285Sdim    /*
178234285Sdim     * March through the device switch probing for things.
179234285Sdim     */
180234285Sdim    for (i = 0; devsw[i] != NULL; i++)
181234285Sdim	if (devsw[i]->dv_init != NULL)
182234285Sdim	    (devsw[i]->dv_init)();
183234285Sdim    printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024);
184234285Sdim    if (initial_bootinfo != NULL) {
185234285Sdim	initial_bootinfo->bi_basemem = bios_basemem / 1024;
186234285Sdim	initial_bootinfo->bi_extmem = bios_extmem / 1024;
187234285Sdim    }
188234285Sdim
189234285Sdim    printf("\n");
190234285Sdim    printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
191234285Sdim    printf("(%s, %s)\n", bootprog_maker, bootprog_date);
192234285Sdim
193234285Sdim    extract_currdev();				/* set $currdev and $loaddev */
194234285Sdim    setenv("LINES", "24", 1);			/* optional */
195234285Sdim
196234285Sdim    interact();			/* doesn't return */
197234285Sdim
198234285Sdim    /* if we ever get here, it is an error */
199234285Sdim    return (1);
200239462Sdim}
201239462Sdim
202234285Sdim/*
203239462Sdim * Set the 'current device' by (if possible) recovering the boot device as
204239462Sdim * supplied by the initial bootstrap.
205239462Sdim *
206239462Sdim * XXX should be extended for netbooting.
207239462Sdim */
208239462Sdimstatic void
209239462Sdimextract_currdev(void)
210239462Sdim{
211239462Sdim    struct i386_devdesc		new_currdev;
212239462Sdim    int				major;
213239462Sdim    int				biosdev = -1;
214239462Sdim
215239462Sdim    /* Assume we are booting from a BIOS disk by default */
216239462Sdim    new_currdev.d_dev = &biosdisk;
217239462Sdim
218239462Sdim    /* new-style boot loaders such as pxeldr and cdldr */
219239462Sdim    if (kargs->bootinfo == 0) {
220239462Sdim        if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) {
221239462Sdim	    /* we are booting from a CD with cdboot */
222239462Sdim	    new_currdev.d_dev = &bioscd;
223249423Sdim	    new_currdev.d_unit = bc_bios2unit(initial_bootdev);
224249423Sdim	} else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) {
225234285Sdim	    /* we are booting from pxeldr */
226239462Sdim	    new_currdev.d_dev = &pxedisk;
227239462Sdim	    new_currdev.d_unit = 0;
228239462Sdim	} else {
229239462Sdim	    /* we don't know what our boot device is */
230239462Sdim	    new_currdev.d_kind.biosdisk.slice = -1;
231239462Sdim	    new_currdev.d_kind.biosdisk.partition = 0;
232239462Sdim	    biosdev = -1;
233249423Sdim	}
234249423Sdim    } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) {
235239462Sdim	/* The passed-in boot device is bad */
236239462Sdim	new_currdev.d_kind.biosdisk.slice = -1;
237239462Sdim	new_currdev.d_kind.biosdisk.partition = 0;
238239462Sdim	biosdev = -1;
239239462Sdim    } else {
240234285Sdim	new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1;
241234285Sdim	new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev);
242234285Sdim	biosdev = initial_bootinfo->bi_bios_dev;
243234285Sdim	major = B_TYPE(initial_bootdev);
244234285Sdim
245234285Sdim	/*
246234285Sdim	 * If we are booted by an old bootstrap, we have to guess at the BIOS
247234285Sdim	 * unit number.  We will lose if there is more than one disk type
248234285Sdim	 * and we are not booting from the lowest-numbered disk type
249234285Sdim	 * (ie. SCSI when IDE also exists).
250234285Sdim	 */
251234285Sdim	if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) {	/* biosdev doesn't match major */
252234285Sdim	    if (B_TYPE(initial_bootdev) == 6)
253234285Sdim		biosdev = 0x30 + B_UNIT(initial_bootdev);
254234285Sdim	    else
255234285Sdim		biosdev = (major << 3) + 0x80 + B_UNIT(initial_bootdev);
256234285Sdim	}
257234285Sdim    }
258234285Sdim    new_currdev.d_type = new_currdev.d_dev->dv_type;
259234285Sdim
260234285Sdim    /*
261234285Sdim     * If we are booting off of a BIOS disk and we didn't succeed in determining
262234285Sdim     * which one we booted off of, just use disk0: as a reasonable default.
263234285Sdim     */
264234285Sdim    if ((new_currdev.d_type == biosdisk.dv_type) &&
265234285Sdim	((new_currdev.d_unit = bd_bios2unit(biosdev)) == -1)) {
266234285Sdim	printf("Can't work out which disk we are booting from.\n"
267234285Sdim	       "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev);
268234285Sdim	new_currdev.d_unit = 0;
269234285Sdim    }
270263508Sdim
271234285Sdim    env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev),
272234285Sdim	       i386_setcurrdev, env_nounset);
273234285Sdim    env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset,
274234285Sdim	       env_nounset);
275234285Sdim}
276234285Sdim
277234285SdimCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
278234285Sdim
279234285Sdimstatic int
280239462Sdimcommand_reboot(int argc, char *argv[])
281239462Sdim{
282234285Sdim    int i;
283234285Sdim
284234285Sdim    for (i = 0; devsw[i] != NULL; ++i)
285234285Sdim	if (devsw[i]->dv_cleanup != NULL)
286234285Sdim	    (devsw[i]->dv_cleanup)();
287234285Sdim
288239462Sdim    printf("Rebooting...\n");
289234285Sdim    delay(1000000);
290234285Sdim    __exit(0);
291234982Sdim}
292234285Sdim
293234285Sdim/* provide this for panic, as it's not in the startup code */
294234285Sdimvoid
295234285Sdimexit(int code)
296234285Sdim{
297234285Sdim    __exit(code);
298234285Sdim}
299234285Sdim
300234285SdimCOMMAND_SET(heap, "heap", "show heap usage", command_heap);
301234285Sdim
302234285Sdimstatic int
303234285Sdimcommand_heap(int argc, char *argv[])
304234285Sdim{
305234285Sdim    mallocstats();
306234285Sdim    printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom,
307234285Sdim      sbrk(0), heap_top);
308234285Sdim    return(CMD_OK);
309234285Sdim}
310234285Sdim
311234285Sdim/* ISA bus access functions for PnP. */
312234285Sdimstatic int
313234285Sdimisa_inb(int port)
314234285Sdim{
315
316    return (inb(port));
317}
318
319static void
320isa_outb(int port, int value)
321{
322
323    outb(port, value);
324}
325