/*-1* Copyright (c) 1998 Michael Smith <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <stand.h>27#include <sys/param.h>28#include <sys/reboot.h>29#include <sys/linker.h>30#include <machine/bootinfo.h>31#include <machine/metadata.h>32#include "bootstrap.h"33#include "modinfo.h"34#include "libi386.h"35#include "btxv86.h"3637#ifdef LOADER_GELI_SUPPORT38#include "geliboot.h"39#endif4041static struct bootinfo *bi;4243/*44* Load the information expected by an i386 kernel.45*46* - The 'boothowto' argument is constructed47* - The 'bootdev' argument is constructed48* - The 'bootinfo' struct is constructed, and copied into the kernel space.49* - The kernel environment is copied into kernel space.50* - Module metadata are formatted and placed in kernel space.51*/52int53bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp)54{55struct preloaded_file *xp, *kfp;56struct i386_devdesc *rootdev;57struct file_metadata *md;58vm_offset_t addr;59vm_offset_t kernend;60vm_offset_t envp;61vm_offset_t size;62vm_offset_t ssym, esym;63char *rootdevname;64int bootdevnr, i, howto;65char *kernelname;66const char *kernelpath;6768howto = bi_getboothowto(args);6970/*71* Allow the environment variable 'rootdev' to override the supplied device72* This should perhaps go to MI code and/or have $rootdev tested/set by73* MI code before launching the kernel.74*/75rootdevname = getenv("rootdev");76i386_getdev((void **)(&rootdev), rootdevname, NULL);77if (rootdev == NULL) { /* bad $rootdev/$currdev */78printf("can't determine root device\n");79return(EINVAL);80}8182/* Try reading the /etc/fstab file to select the root device */83getrootmount(devformat(&rootdev->dd));8485/* Do legacy rootdev guessing */8687/* XXX - use a default bootdev of 0. Is this ok??? */88bootdevnr = 0;8990bi = calloc(sizeof(*bi), 1);91switch(rootdev->dd.d_dev->dv_type) {92case DEVT_CD:93case DEVT_DISK:94/* pass in the BIOS device number of the current disk */95bi->bi_bios_dev = bd_unit2bios(rootdev);96bootdevnr = bd_getdev(rootdev);97break;9899case DEVT_NET:100case DEVT_ZFS:101break;102103default:104printf("WARNING - don't know how to boot from device type %d\n",105rootdev->dd.d_dev->dv_type);106}107if (bootdevnr == -1) {108printf("root device %s invalid\n", devformat(&rootdev->dd));109return (EINVAL);110}111free(rootdev);112113/* find the last module in the chain */114addr = 0;115for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {116if (addr < (xp->f_addr + xp->f_size))117addr = xp->f_addr + xp->f_size;118}119/* pad to a page boundary */120addr = md_align(addr);121122addr = build_font_module(addr);123124/* copy our environment */125envp = addr;126addr = md_copyenv(addr);127128/* pad to a page boundary */129addr = md_align(addr);130131kfp = file_findfile(NULL, md_kerntype);132if (kfp == NULL)133panic("can't find kernel file");134kernend = 0; /* fill it in later */135file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);136file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);137file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);138bios_addsmapdata(kfp);139#ifdef LOADER_GELI_SUPPORT140geli_export_key_metadata(kfp);141#endif142bi_load_vbe_data(kfp);143144/* Figure out the size and location of the metadata */145*modulep = addr;146size = md_copymodules(0, false);147kernend = md_align(addr + size);148*kernendp = kernend;149150/* patch MODINFOMD_KERNEND */151md = file_findmetadata(kfp, MODINFOMD_KERNEND);152bcopy(&kernend, md->md_data, sizeof kernend);153154/* copy module list and metadata */155(void)md_copymodules(addr, false);156157ssym = esym = 0;158md = file_findmetadata(kfp, MODINFOMD_SSYM);159if (md != NULL)160ssym = *((vm_offset_t *)&(md->md_data));161md = file_findmetadata(kfp, MODINFOMD_ESYM);162if (md != NULL)163esym = *((vm_offset_t *)&(md->md_data));164if (ssym == 0 || esym == 0)165ssym = esym = 0; /* sanity */166167/* legacy bootinfo structure */168kernelname = getenv("kernelname");169i386_getdev(NULL, kernelname, &kernelpath);170bi->bi_version = BOOTINFO_VERSION;171bi->bi_size = sizeof(*bi);172bi->bi_memsizes_valid = 1;173bi->bi_basemem = bios_basemem / 1024;174bi->bi_extmem = bios_extmem / 1024;175bi->bi_envp = envp;176bi->bi_modulep = *modulep;177bi->bi_kernend = kernend;178bi->bi_kernelname = VTOP(kernelpath);179bi->bi_symtab = ssym; /* XXX this is only the primary kernel symtab */180bi->bi_esymtab = esym;181182/* legacy boot arguments */183*howtop = howto | RB_BOOTINFO;184*bootdevp = bootdevnr;185*bip = VTOP(bi);186187return(0);188}189190191