138465Smsmith/*-
238465Smsmith * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
338465Smsmith * All rights reserved.
438465Smsmith *
538465Smsmith * Redistribution and use in source and binary forms, with or without
638465Smsmith * modification, are permitted provided that the following conditions
738465Smsmith * are met:
838465Smsmith * 1. Redistributions of source code must retain the above copyright
938465Smsmith *    notice, this list of conditions and the following disclaimer.
1038465Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1138465Smsmith *    notice, this list of conditions and the following disclaimer in the
1238465Smsmith *    documentation and/or other materials provided with the distribution.
1338465Smsmith *
1438465Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538465Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638465Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738465Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838465Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938465Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038465Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138465Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238465Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338465Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438465Smsmith * SUCH DAMAGE.
2538465Smsmith */
2638465Smsmith
27119482Sobrien#include <sys/cdefs.h>
28119482Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/boot/i386/libi386/bootinfo32.c 185029 2008-11-17 20:49:29Z pjd $");
29119482Sobrien
3039902Smsmith#include <stand.h>
3139902Smsmith#include <sys/param.h>
3238465Smsmith#include <sys/reboot.h>
3340146Speter#include <sys/linker.h>
3439902Smsmith#include <machine/bootinfo.h>
3538465Smsmith#include "bootstrap.h"
3639902Smsmith#include "libi386.h"
3739902Smsmith#include "btxv86.h"
3838465Smsmith
39114379Speterstatic struct bootinfo  bi;
4038465Smsmith
4138465Smsmith/*
4238465Smsmith * Copy module-related data into the load area, where it can be
4338465Smsmith * used as a directory for loaded modules.
4438465Smsmith *
4538465Smsmith * Module data is presented in a self-describing format.  Each datum
4672640Sasmodai * is preceded by a 32-bit identifier and a 32-bit size field.
4738465Smsmith *
4838465Smsmith * Currently, the following data are saved:
4938465Smsmith *
5038465Smsmith * MOD_NAME	(variable)		module name (string)
5138465Smsmith * MOD_TYPE	(variable)		module type (string)
5244572Sdcs * MOD_ARGS	(variable)		module parameters (string)
5338465Smsmith * MOD_ADDR	sizeof(vm_offset_t)	module load address
5438465Smsmith * MOD_SIZE	sizeof(size_t)		module size
5538465Smsmith * MOD_METADATA	(variable)		type-specific metadata
5638465Smsmith */
57114379Speter#define COPY32(v, a, c) {			\
5840107Smsmith    u_int32_t	x = (v);			\
59114379Speter    if (c)					\
60114379Speter	i386_copyin(&x, a, sizeof(x));		\
6140107Smsmith    a += sizeof(x);				\
6238465Smsmith}
6338465Smsmith
64114379Speter#define MOD_STR(t, a, s, c) {			\
65114379Speter    COPY32(t, a, c);				\
66114379Speter    COPY32(strlen(s) + 1, a, c);		\
67114379Speter    if (c)					\
68114379Speter	i386_copyin(s, a, strlen(s) + 1);	\
6940336Speter    a += roundup(strlen(s) + 1, sizeof(u_long));\
7040107Smsmith}
7140107Smsmith
72114379Speter#define MOD_NAME(a, s, c)	MOD_STR(MODINFO_NAME, a, s, c)
73114379Speter#define MOD_TYPE(a, s, c)	MOD_STR(MODINFO_TYPE, a, s, c)
74114379Speter#define MOD_ARGS(a, s, c)	MOD_STR(MODINFO_ARGS, a, s, c)
7538465Smsmith
76114379Speter#define MOD_VAR(t, a, s, c) {			\
77114379Speter    COPY32(t, a, c);				\
78114379Speter    COPY32(sizeof(s), a, c);			\
79114379Speter    if (c)					\
80114379Speter	i386_copyin(&s, a, sizeof(s));		\
8140336Speter    a += roundup(sizeof(s), sizeof(u_long));	\
8238465Smsmith}
8338465Smsmith
84114379Speter#define MOD_ADDR(a, s, c)	MOD_VAR(MODINFO_ADDR, a, s, c)
85114379Speter#define MOD_SIZE(a, s, c)	MOD_VAR(MODINFO_SIZE, a, s, c)
8638465Smsmith
87114379Speter#define MOD_METADATA(a, mm, c) {		\
88114379Speter    COPY32(MODINFO_METADATA | mm->md_type, a, c); \
89114379Speter    COPY32(mm->md_size, a, c);			\
90114379Speter    if (c)					\
91114379Speter	i386_copyin(mm->md_data, a, mm->md_size); \
9240336Speter    a += roundup(mm->md_size, sizeof(u_long));\
9338465Smsmith}
9438465Smsmith
95114379Speter#define MOD_END(a, c) {				\
96114379Speter    COPY32(MODINFO_END, a, c);			\
97114379Speter    COPY32(0, a, c);				\
9839178Smsmith}
9939178Smsmith
100114379Speterstatic vm_offset_t
101114379Speterbi_copymodules32(vm_offset_t addr)
10238465Smsmith{
10359854Sbp    struct preloaded_file	*fp;
10459854Sbp    struct file_metadata	*md;
105114379Speter    int				c;
10638465Smsmith
107114379Speter    c = addr != 0;
10838465Smsmith    /* start with the first module on the list, should be the kernel */
10959854Sbp    for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
11040146Speter
111114379Speter	MOD_NAME(addr, fp->f_name, c);	/* this field must come first */
112114379Speter	MOD_TYPE(addr, fp->f_type, c);
11359854Sbp	if (fp->f_args)
114114379Speter	    MOD_ARGS(addr, fp->f_args, c);
115114379Speter	MOD_ADDR(addr, fp->f_addr, c);
116114379Speter	MOD_SIZE(addr, fp->f_size, c);
11759854Sbp	for (md = fp->f_metadata; md != NULL; md = md->md_next)
11838764Smsmith	    if (!(md->md_type & MODINFOMD_NOCOPY))
119114379Speter		MOD_METADATA(addr, md, c);
12038465Smsmith    }
121114379Speter    MOD_END(addr, c);
12238465Smsmith    return(addr);
12338465Smsmith}
12439902Smsmith
12539902Smsmith/*
12639902Smsmith * Load the information expected by an i386 kernel.
12739902Smsmith *
12839902Smsmith * - The 'boothowto' argument is constructed
12964187Sjhb * - The 'bootdev' argument is constructed
13039902Smsmith * - The 'bootinfo' struct is constructed, and copied into the kernel space.
13139902Smsmith * - The kernel environment is copied into kernel space.
13239902Smsmith * - Module metadata are formatted and placed in kernel space.
13339902Smsmith */
13439902Smsmithint
135114379Speterbi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp)
13639902Smsmith{
137114379Speter    struct preloaded_file	*xp, *kfp;
13839902Smsmith    struct i386_devdesc		*rootdev;
139114379Speter    struct file_metadata	*md;
14064187Sjhb    vm_offset_t			addr;
141114379Speter    vm_offset_t			kernend;
142114379Speter    vm_offset_t			envp;
143114379Speter    vm_offset_t			size;
144114379Speter    vm_offset_t			ssym, esym;
14539902Smsmith    char			*rootdevname;
146114379Speter    int				bootdevnr, i, howto;
14739902Smsmith    char			*kernelname;
14839989Smsmith    const char			*kernelpath;
14939902Smsmith
150114379Speter    howto = bi_getboothowto(args);
15139902Smsmith
15239902Smsmith    /*
15339902Smsmith     * Allow the environment variable 'rootdev' to override the supplied device
15439902Smsmith     * This should perhaps go to MI code and/or have $rootdev tested/set by
15539902Smsmith     * MI code before launching the kernel.
15639902Smsmith     */
15739902Smsmith    rootdevname = getenv("rootdev");
15839902Smsmith    i386_getdev((void **)(&rootdev), rootdevname, NULL);
15939902Smsmith    if (rootdev == NULL) {		/* bad $rootdev/$currdev */
16039902Smsmith	printf("can't determine root device\n");
16139902Smsmith	return(EINVAL);
16239902Smsmith    }
16341139Smsmith
16448952Smsmith    /* Try reading the /etc/fstab file to select the root device */
16548952Smsmith    getrootmount(i386_fmtdev((void *)rootdev));
16648952Smsmith
16748952Smsmith    /* Do legacy rootdev guessing */
16864187Sjhb
16964187Sjhb    /* XXX - use a default bootdev of 0.  Is this ok??? */
17064187Sjhb    bootdevnr = 0;
17164187Sjhb
17239902Smsmith    switch(rootdev->d_type) {
17386091Sjhb    case DEVT_CD:
17486091Sjhb	    /* Pass in BIOS device number. */
175163897Smarcel	    bi.bi_bios_dev = bc_unit2bios(rootdev->d_unit);
17686091Sjhb	    bootdevnr = bc_getdev(rootdev);
17786091Sjhb	    break;
17886091Sjhb
17939902Smsmith    case DEVT_DISK:
18039902Smsmith	/* pass in the BIOS device number of the current disk */
181163897Smarcel	bi.bi_bios_dev = bd_unit2bios(rootdev->d_unit);
18239902Smsmith	bootdevnr = bd_getdev(rootdev);
18386091Sjhb	break;
18486091Sjhb
18559087Sps    case DEVT_NET:
186185029Spjd    case DEVT_ZFS:
18759087Sps	    break;
18859087Sps
18939902Smsmith    default:
19048952Smsmith	printf("WARNING - don't know how to boot from device type %d\n", rootdev->d_type);
19139902Smsmith    }
19286091Sjhb    if (bootdevnr == -1) {
19386091Sjhb	printf("root device %s invalid\n", i386_fmtdev(rootdev));
19486091Sjhb	return (EINVAL);
19586091Sjhb    }
19639902Smsmith    free(rootdev);
19739902Smsmith
19839902Smsmith    /* find the last module in the chain */
19940393Speter    addr = 0;
20059854Sbp    for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
20159854Sbp	if (addr < (xp->f_addr + xp->f_size))
20259854Sbp	    addr = xp->f_addr + xp->f_size;
20340393Speter    }
20439902Smsmith    /* pad to a page boundary */
205114379Speter    addr = roundup(addr, PAGE_SIZE);
20639902Smsmith
20739902Smsmith    /* copy our environment */
208114379Speter    envp = addr;
20939902Smsmith    addr = bi_copyenv(addr);
21039902Smsmith
21139902Smsmith    /* pad to a page boundary */
212114379Speter    addr = roundup(addr, PAGE_SIZE);
213114379Speter
214114385Speter    kfp = file_findfile(NULL, "elf kernel");
215114379Speter    if (kfp == NULL)
216114379Speter      kfp = file_findfile(NULL, "elf32 kernel");
217114379Speter    if (kfp == NULL)
218114379Speter	panic("can't find kernel file");
219114379Speter    kernend = 0;	/* fill it in later */
220114379Speter    file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
221114379Speter    file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
222114379Speter    file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
223114379Speter    bios_addsmapdata(kfp);
224114379Speter
225114379Speter    /* Figure out the size and location of the metadata */
226114379Speter    *modulep = addr;
227114379Speter    size = bi_copymodules32(0);
228114379Speter    kernend = roundup(addr + size, PAGE_SIZE);
229114379Speter    *kernendp = kernend;
230114379Speter
231114379Speter    /* patch MODINFOMD_KERNEND */
232114379Speter    md = file_findmetadata(kfp, MODINFOMD_KERNEND);
233114379Speter    bcopy(&kernend, md->md_data, sizeof kernend);
234114379Speter
23539902Smsmith    /* copy module list and metadata */
236114379Speter    (void)bi_copymodules32(addr);
23739902Smsmith
238114379Speter    ssym = esym = 0;
239114379Speter    md = file_findmetadata(kfp, MODINFOMD_SSYM);
240114379Speter    if (md != NULL)
241114379Speter	ssym = *((vm_offset_t *)&(md->md_data));
242114379Speter    md = file_findmetadata(kfp, MODINFOMD_ESYM);
243114379Speter    if (md != NULL)
244114379Speter	esym = *((vm_offset_t *)&(md->md_data));
245114379Speter    if (ssym == 0 || esym == 0)
246114379Speter	ssym = esym = 0;		/* sanity */
24739902Smsmith
248114379Speter    /* legacy bootinfo structure */
24939902Smsmith    kernelname = getenv("kernelname");
25039989Smsmith    i386_getdev(NULL, kernelname, &kernelpath);
251114379Speter    bi.bi_version = BOOTINFO_VERSION;
252114379Speter    bi.bi_kernelname = 0;		/* XXX char * -> kernel name */
253114379Speter    bi.bi_nfs_diskless = 0;		/* struct nfs_diskless * */
254114379Speter    bi.bi_n_bios_used = 0;		/* XXX would have to hook biosdisk driver for these */
255114379Speter    for (i = 0; i < N_BIOS_GEOM; i++)
256114379Speter        bi.bi_bios_geom[i] = bd_getbigeom(i);
257114379Speter    bi.bi_size = sizeof(bi);
258114379Speter    bi.bi_memsizes_valid = 1;
259114379Speter    bi.bi_basemem = bios_basemem / 1024;
260114379Speter    bi.bi_extmem = bios_extmem / 1024;
261114379Speter    bi.bi_envp = envp;
262114379Speter    bi.bi_modulep = *modulep;
263114379Speter    bi.bi_kernend = kernend;
26439989Smsmith    bi.bi_kernelname = VTOP(kernelpath);
265114379Speter    bi.bi_symtab = ssym;       /* XXX this is only the primary kernel symtab */
266114379Speter    bi.bi_esymtab = esym;
267114379Speter
268114379Speter    /* legacy boot arguments */
269114379Speter    *howtop = howto | RB_BOOTINFO;
270114379Speter    *bootdevp = bootdevnr;
27139902Smsmith    *bip = VTOP(&bi);
27239902Smsmith
27339902Smsmith    return(0);
27439902Smsmith}
275