bootinfo32.c revision 40107
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 * 2640107Smsmith * $Id: bootinfo.c,v 1.10 1998/10/07 10:55:46 peter Exp $ 2738465Smsmith */ 2838465Smsmith 2939902Smsmith#include <stand.h> 3039902Smsmith#include <sys/param.h> 3138465Smsmith#include <sys/reboot.h> 3239902Smsmith#include <machine/bootinfo.h> 3338465Smsmith#include "bootstrap.h" 3439902Smsmith#include "libi386.h" 3539902Smsmith#include "btxv86.h" 3638465Smsmith 3739902Smsmithstatic struct bootinfo bi; 3838465Smsmith 3938465Smsmith/* 4038465Smsmith * Return a 'boothowto' value corresponding to the kernel arguments in 4138465Smsmith * (kargs) and any relevant environment variables. 4238465Smsmith */ 4338465Smsmithstatic struct 4438465Smsmith{ 4538465Smsmith char *ev; 4638465Smsmith int mask; 4738465Smsmith} howto_names[] = { 4838465Smsmith {"boot_askname", RB_ASKNAME}, 4938465Smsmith {"boot_userconfig", RB_CONFIG}, 5038465Smsmith {"boot_ddb", RB_KDB}, 5138465Smsmith {"boot_gdb", RB_GDB}, 5238465Smsmith {"boot_single", RB_SINGLE}, 5338465Smsmith {"boot_verbose", RB_VERBOSE}, 5438465Smsmith {NULL, 0} 5538465Smsmith}; 5638465Smsmith 5738465Smsmithint 5838465Smsmithbi_getboothowto(char *kargs) 5938465Smsmith{ 6038465Smsmith char *cp; 6138465Smsmith int howto; 6238465Smsmith int active; 6338465Smsmith int i; 6438465Smsmith 6539178Smsmith /* Parse kargs */ 6638465Smsmith howto = 0; 6738465Smsmith if (kargs != NULL) { 6838465Smsmith cp = kargs; 6938465Smsmith active = 0; 7038465Smsmith while (*cp != 0) { 7138465Smsmith if (!active && (*cp == '-')) { 7238465Smsmith active = 1; 7338465Smsmith } else if (active) 7438465Smsmith switch (*cp) { 7538465Smsmith case 'a': 7638465Smsmith howto |= RB_ASKNAME; 7738465Smsmith break; 7838465Smsmith case 'c': 7938465Smsmith howto |= RB_CONFIG; 8038465Smsmith break; 8138465Smsmith case 'd': 8238465Smsmith howto |= RB_KDB; 8338465Smsmith break; 8438465Smsmith case 'g': 8538465Smsmith howto |= RB_GDB; 8638465Smsmith break; 8738465Smsmith case 'h': 8838465Smsmith howto |= RB_SERIAL; 8938465Smsmith break; 9038465Smsmith case 'r': 9138465Smsmith howto |= RB_DFLTROOT; 9238465Smsmith break; 9338465Smsmith case 's': 9438465Smsmith howto |= RB_SINGLE; 9538465Smsmith break; 9638465Smsmith case 'v': 9738465Smsmith howto |= RB_VERBOSE; 9838465Smsmith break; 9938465Smsmith default: 10038465Smsmith active = 0; 10138465Smsmith break; 10238465Smsmith } 10339178Smsmith cp++; 10438465Smsmith } 10538465Smsmith } 10639178Smsmith /* get equivalents from the environment */ 10738465Smsmith for (i = 0; howto_names[i].ev != NULL; i++) 10838465Smsmith if (getenv(howto_names[i].ev) != NULL) 10938465Smsmith howto |= howto_names[i].mask; 11038465Smsmith if (!strcmp(getenv("console"), "comconsole")) 11138465Smsmith howto |= RB_SERIAL; 11238465Smsmith return(howto); 11338465Smsmith} 11438465Smsmith 11538465Smsmith/* 11638465Smsmith * Copy the environment into the load area starting at (addr). 11738465Smsmith * Each variable is formatted as <name>=<value>, with a single nul 11838465Smsmith * separating each variable, and a double nul terminating the environment. 11938465Smsmith */ 12038465Smsmithvm_offset_t 12138465Smsmithbi_copyenv(vm_offset_t addr) 12238465Smsmith{ 12338465Smsmith struct env_var *ep; 12438465Smsmith 12538465Smsmith /* traverse the environment */ 12638465Smsmith for (ep = environ; ep != NULL; ep = ep->ev_next) { 12739441Smsmith i386_copyin(ep->ev_name, addr, strlen(ep->ev_name)); 12838465Smsmith addr += strlen(ep->ev_name); 12939441Smsmith i386_copyin("=", addr, 1); 13038465Smsmith addr++; 13138465Smsmith if (ep->ev_value != NULL) { 13239441Smsmith i386_copyin(ep->ev_value, addr, strlen(ep->ev_value)); 13338465Smsmith addr += strlen(ep->ev_value); 13438465Smsmith } 13539441Smsmith i386_copyin("", addr, 1); 13638465Smsmith addr++; 13738465Smsmith } 13839441Smsmith i386_copyin("", addr, 1); 13938465Smsmith addr++; 14039730Speter return(addr); 14138465Smsmith} 14238465Smsmith 14338465Smsmith/* 14438465Smsmith * Copy module-related data into the load area, where it can be 14538465Smsmith * used as a directory for loaded modules. 14638465Smsmith * 14738465Smsmith * Module data is presented in a self-describing format. Each datum 14839178Smsmith * is preceeded by a 32-bit identifier and a 32-bit size field. 14938465Smsmith * 15038465Smsmith * Currently, the following data are saved: 15138465Smsmith * 15238465Smsmith * MOD_NAME (variable) module name (string) 15338465Smsmith * MOD_TYPE (variable) module type (string) 15438465Smsmith * MOD_ADDR sizeof(vm_offset_t) module load address 15538465Smsmith * MOD_SIZE sizeof(size_t) module size 15638465Smsmith * MOD_METADATA (variable) type-specific metadata 15738465Smsmith */ 15840107Smsmith#define COPY32(v, a) { \ 15940107Smsmith u_int32_t x = (v); \ 16040107Smsmith i386_copyin(&x, a, sizeof(x)); \ 16140107Smsmith a += sizeof(x); \ 16238465Smsmith} 16338465Smsmith 16440107Smsmith#define MOD_STR(t, a, s) { \ 16540107Smsmith COPY32(t, a); \ 16640107Smsmith COPY32(strlen(s) + 1, a); \ 16740107Smsmith i386_copyin(s, a, strlen(s) + 1); \ 16840107Smsmith a += strlen(s) + 1; \ 16940107Smsmith} 17040107Smsmith 17138465Smsmith#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s) 17238465Smsmith#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s) 17338465Smsmith 17438465Smsmith#define MOD_VAR(t, a, s) { \ 17540107Smsmith COPY32(t, a); \ 17640107Smsmith COPY32(sizeof(s), a); \ 17739441Smsmith i386_copyin(&s, a, sizeof(s)); \ 17838465Smsmith a += sizeof(s); \ 17938465Smsmith} 18038465Smsmith 18138465Smsmith#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s) 18238465Smsmith#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s) 18338465Smsmith 18440107Smsmith#define MOD_METADATA(a, mm) { \ 18540107Smsmith COPY32(MODINFO_METADATA | mm->md_type, a); \ 18640107Smsmith COPY32(mm->md_size, a); \ 18740107Smsmith i386_copyin(mm->md_data, a, mm->md_size); \ 18840107Smsmith a += mm->md_size; \ 18938465Smsmith} 19038465Smsmith 19139441Smsmith#define MOD_END(a) { \ 19240107Smsmith COPY32(MODINFO_END, a); \ 19340107Smsmith COPY32(0, a); \ 19439178Smsmith} 19539178Smsmith 19638465Smsmithvm_offset_t 19738465Smsmithbi_copymodules(vm_offset_t addr) 19838465Smsmith{ 19938465Smsmith struct loaded_module *mp; 20038465Smsmith struct module_metadata *md; 20138465Smsmith 20238465Smsmith /* start with the first module on the list, should be the kernel */ 20338465Smsmith for (mp = mod_findmodule(NULL, NULL); mp != NULL; mp = mp->m_next) { 20438465Smsmith 20539178Smsmith MOD_NAME(addr, mp->m_name); /* this field must come first */ 20638465Smsmith MOD_TYPE(addr, mp->m_type); 20738465Smsmith MOD_ADDR(addr, mp->m_addr); 20838465Smsmith MOD_SIZE(addr, mp->m_size); 20938465Smsmith for (md = mp->m_metadata; md != NULL; md = md->md_next) 21038764Smsmith if (!(md->md_type & MODINFOMD_NOCOPY)) 21138764Smsmith MOD_METADATA(addr, md); 21238465Smsmith } 21339178Smsmith MOD_END(addr); 21438465Smsmith return(addr); 21538465Smsmith} 21639902Smsmith 21739902Smsmith/* 21839902Smsmith * Load the information expected by an i386 kernel. 21939902Smsmith * 22039902Smsmith * - The 'boothowto' argument is constructed 22139902Smsmith * - The 'botdev' argument is constructed 22239902Smsmith * - The 'bootinfo' struct is constructed, and copied into the kernel space. 22339902Smsmith * - The kernel environment is copied into kernel space. 22439902Smsmith * - Module metadata are formatted and placed in kernel space. 22539902Smsmith */ 22639902Smsmithint 22739902Smsmithbi_load(char *args, int *howtop, int *bootdevp, vm_offset_t *bip) 22839902Smsmith{ 22939902Smsmith struct loaded_module *xp; 23039902Smsmith struct i386_devdesc *rootdev; 23139902Smsmith vm_offset_t addr, bootinfo_addr; 23239902Smsmith char *rootdevname; 23339902Smsmith int bootdevnr; 23439902Smsmith u_int pad; 23539902Smsmith char *kernelname; 23639989Smsmith const char *kernelpath; 23739902Smsmith 23839902Smsmith *howtop = bi_getboothowto(args); 23939902Smsmith 24039902Smsmith /* 24139902Smsmith * Allow the environment variable 'rootdev' to override the supplied device 24239902Smsmith * This should perhaps go to MI code and/or have $rootdev tested/set by 24339902Smsmith * MI code before launching the kernel. 24439902Smsmith */ 24539902Smsmith rootdevname = getenv("rootdev"); 24639902Smsmith i386_getdev((void **)(&rootdev), rootdevname, NULL); 24739902Smsmith if (rootdev == NULL) { /* bad $rootdev/$currdev */ 24839902Smsmith printf("can't determine root device\n"); 24939902Smsmith return(EINVAL); 25039902Smsmith } 25139902Smsmith 25239902Smsmith /* Boot from whatever the current device is */ 25339902Smsmith i386_getdev((void **)(&rootdev), NULL, NULL); 25439902Smsmith switch(rootdev->d_type) { 25539902Smsmith case DEVT_DISK: 25639902Smsmith /* pass in the BIOS device number of the current disk */ 25739902Smsmith bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit); 25839902Smsmith bootdevnr = bd_getdev(rootdev); 25939902Smsmith break; 26039902Smsmith 26139902Smsmith default: 26239902Smsmith printf("aout_exec: WARNING - don't know how to boot from device type %d\n", rootdev->d_type); 26339902Smsmith } 26439902Smsmith free(rootdev); 26539902Smsmith *bootdevp = bootdevnr; 26639902Smsmith 26739902Smsmith /* legacy bootinfo structure */ 26839902Smsmith bi.bi_version = BOOTINFO_VERSION; 26939902Smsmith bi.bi_kernelname = 0; /* XXX char * -> kernel name */ 27039902Smsmith bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */ 27139902Smsmith bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */ 27239902Smsmith /* bi.bi_bios_geom[] */ 27339902Smsmith bi.bi_size = sizeof(bi); 27439902Smsmith bi.bi_memsizes_valid = 1; 27539902Smsmith bi.bi_basemem = getbasemem(); 27639902Smsmith bi.bi_extmem = getextmem(); 27739902Smsmith 27839902Smsmith /* find the last module in the chain */ 27939902Smsmith for (xp = mod_findmodule(NULL, NULL); xp->m_next != NULL; xp = xp->m_next) 28039902Smsmith ; 28139902Smsmith addr = xp->m_addr + xp->m_size; 28239902Smsmith /* pad to a page boundary */ 28339902Smsmith pad = (u_int)addr & PAGE_MASK; 28439902Smsmith if (pad != 0) { 28539902Smsmith pad = PAGE_SIZE - pad; 28639902Smsmith addr += pad; 28739902Smsmith } 28839902Smsmith 28939902Smsmith /* copy our environment */ 29039902Smsmith bi.bi_envp = addr; 29139902Smsmith addr = bi_copyenv(addr); 29239902Smsmith 29339902Smsmith /* pad to a page boundary */ 29439902Smsmith pad = (u_int)addr & PAGE_MASK; 29539902Smsmith if (pad != 0) { 29639902Smsmith pad = PAGE_SIZE - pad; 29739902Smsmith addr += pad; 29839902Smsmith } 29939902Smsmith /* copy module list and metadata */ 30039902Smsmith bi.bi_modulep = addr; 30139902Smsmith addr = bi_copymodules(addr); 30239902Smsmith 30339902Smsmith /* all done copying stuff in, save end of loaded object space */ 30439902Smsmith bi.bi_kernend = addr; 30539902Smsmith 30639902Smsmith *howtop |= RB_BOOTINFO; /* it's there now */ 30739902Smsmith 30839989Smsmith /* 30939989Smsmith * Get the kernel name, strip off any device prefix. 31039989Smsmith */ 31139902Smsmith kernelname = getenv("kernelname"); 31239989Smsmith i386_getdev(NULL, kernelname, &kernelpath); 31339989Smsmith bi.bi_kernelname = VTOP(kernelpath); 31439902Smsmith *bip = VTOP(&bi); 31539902Smsmith 31639902Smsmith return(0); 31739902Smsmith} 318