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