bootinfo32.c revision 59087
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 * 2650477Speter * $FreeBSD: head/sys/boot/i386/libi386/bootinfo32.c 59087 2000-04-08 01:22:14Z ps $ 2738465Smsmith */ 2838465Smsmith 2939902Smsmith#include <stand.h> 3039902Smsmith#include <sys/param.h> 3138465Smsmith#include <sys/reboot.h> 3240146Speter#include <sys/linker.h> 3339902Smsmith#include <machine/bootinfo.h> 3438465Smsmith#include "bootstrap.h" 3539902Smsmith#include "libi386.h" 3639902Smsmith#include "btxv86.h" 3738465Smsmith 3839902Smsmithstatic struct bootinfo bi; 3938465Smsmith 4038465Smsmith/* 4138465Smsmith * Return a 'boothowto' value corresponding to the kernel arguments in 4238465Smsmith * (kargs) and any relevant environment variables. 4338465Smsmith */ 4438465Smsmithstatic struct 4538465Smsmith{ 4638465Smsmith char *ev; 4738465Smsmith int mask; 4838465Smsmith} howto_names[] = { 4938465Smsmith {"boot_askname", RB_ASKNAME}, 5047727Sghelmer {"boot_cdrom", RB_CDROM}, 5138465Smsmith {"boot_userconfig", RB_CONFIG}, 5238465Smsmith {"boot_ddb", RB_KDB}, 5338465Smsmith {"boot_gdb", RB_GDB}, 5438465Smsmith {"boot_single", RB_SINGLE}, 5538465Smsmith {"boot_verbose", RB_VERBOSE}, 5638465Smsmith {NULL, 0} 5738465Smsmith}; 5838465Smsmith 5938465Smsmithint 6038465Smsmithbi_getboothowto(char *kargs) 6138465Smsmith{ 6238465Smsmith char *cp; 6338465Smsmith int howto; 6438465Smsmith int active; 6538465Smsmith int i; 6638465Smsmith 6739178Smsmith /* Parse kargs */ 6838465Smsmith howto = 0; 6938465Smsmith if (kargs != NULL) { 7038465Smsmith cp = kargs; 7138465Smsmith active = 0; 7238465Smsmith while (*cp != 0) { 7338465Smsmith if (!active && (*cp == '-')) { 7438465Smsmith active = 1; 7538465Smsmith } else if (active) 7638465Smsmith switch (*cp) { 7738465Smsmith case 'a': 7838465Smsmith howto |= RB_ASKNAME; 7938465Smsmith break; 8038465Smsmith case 'c': 8138465Smsmith howto |= RB_CONFIG; 8238465Smsmith break; 8347727Sghelmer case 'C': 8447727Sghelmer howto |= RB_CDROM; 8547727Sghelmer break; 8638465Smsmith case 'd': 8738465Smsmith howto |= RB_KDB; 8838465Smsmith break; 8938465Smsmith case 'g': 9038465Smsmith howto |= RB_GDB; 9138465Smsmith break; 9238465Smsmith case 'h': 9338465Smsmith howto |= RB_SERIAL; 9438465Smsmith break; 9538465Smsmith case 'r': 9638465Smsmith howto |= RB_DFLTROOT; 9738465Smsmith break; 9838465Smsmith case 's': 9938465Smsmith howto |= RB_SINGLE; 10038465Smsmith break; 10138465Smsmith case 'v': 10238465Smsmith howto |= RB_VERBOSE; 10338465Smsmith break; 10438465Smsmith default: 10538465Smsmith active = 0; 10638465Smsmith break; 10738465Smsmith } 10839178Smsmith cp++; 10938465Smsmith } 11038465Smsmith } 11139178Smsmith /* get equivalents from the environment */ 11238465Smsmith for (i = 0; howto_names[i].ev != NULL; i++) 11338465Smsmith if (getenv(howto_names[i].ev) != NULL) 11438465Smsmith howto |= howto_names[i].mask; 11538465Smsmith if (!strcmp(getenv("console"), "comconsole")) 11638465Smsmith howto |= RB_SERIAL; 11738465Smsmith return(howto); 11838465Smsmith} 11938465Smsmith 12038465Smsmith/* 12138465Smsmith * Copy the environment into the load area starting at (addr). 12238465Smsmith * Each variable is formatted as <name>=<value>, with a single nul 12338465Smsmith * separating each variable, and a double nul terminating the environment. 12438465Smsmith */ 12538465Smsmithvm_offset_t 12638465Smsmithbi_copyenv(vm_offset_t addr) 12738465Smsmith{ 12838465Smsmith struct env_var *ep; 12938465Smsmith 13038465Smsmith /* traverse the environment */ 13138465Smsmith for (ep = environ; ep != NULL; ep = ep->ev_next) { 13239441Smsmith i386_copyin(ep->ev_name, addr, strlen(ep->ev_name)); 13338465Smsmith addr += strlen(ep->ev_name); 13439441Smsmith i386_copyin("=", addr, 1); 13538465Smsmith addr++; 13638465Smsmith if (ep->ev_value != NULL) { 13739441Smsmith i386_copyin(ep->ev_value, addr, strlen(ep->ev_value)); 13838465Smsmith addr += strlen(ep->ev_value); 13938465Smsmith } 14039441Smsmith i386_copyin("", addr, 1); 14138465Smsmith addr++; 14238465Smsmith } 14339441Smsmith i386_copyin("", addr, 1); 14438465Smsmith addr++; 14539730Speter return(addr); 14638465Smsmith} 14738465Smsmith 14838465Smsmith/* 14938465Smsmith * Copy module-related data into the load area, where it can be 15038465Smsmith * used as a directory for loaded modules. 15138465Smsmith * 15238465Smsmith * Module data is presented in a self-describing format. Each datum 15339178Smsmith * is preceeded by a 32-bit identifier and a 32-bit size field. 15438465Smsmith * 15538465Smsmith * Currently, the following data are saved: 15638465Smsmith * 15738465Smsmith * MOD_NAME (variable) module name (string) 15838465Smsmith * MOD_TYPE (variable) module type (string) 15944572Sdcs * MOD_ARGS (variable) module parameters (string) 16038465Smsmith * MOD_ADDR sizeof(vm_offset_t) module load address 16138465Smsmith * MOD_SIZE sizeof(size_t) module size 16238465Smsmith * MOD_METADATA (variable) type-specific metadata 16338465Smsmith */ 16440107Smsmith#define COPY32(v, a) { \ 16540107Smsmith u_int32_t x = (v); \ 16640107Smsmith i386_copyin(&x, a, sizeof(x)); \ 16740107Smsmith a += sizeof(x); \ 16838465Smsmith} 16938465Smsmith 17040107Smsmith#define MOD_STR(t, a, s) { \ 17140107Smsmith COPY32(t, a); \ 17240107Smsmith COPY32(strlen(s) + 1, a); \ 17340107Smsmith i386_copyin(s, a, strlen(s) + 1); \ 17440336Speter a += roundup(strlen(s) + 1, sizeof(u_long));\ 17540107Smsmith} 17640107Smsmith 17738465Smsmith#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s) 17838465Smsmith#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s) 17944572Sdcs#define MOD_ARGS(a, s) MOD_STR(MODINFO_ARGS, a, s) 18038465Smsmith 18138465Smsmith#define MOD_VAR(t, a, s) { \ 18240107Smsmith COPY32(t, a); \ 18340107Smsmith COPY32(sizeof(s), a); \ 18439441Smsmith i386_copyin(&s, a, sizeof(s)); \ 18540336Speter a += roundup(sizeof(s), sizeof(u_long)); \ 18638465Smsmith} 18738465Smsmith 18838465Smsmith#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s) 18938465Smsmith#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s) 19038465Smsmith 19140107Smsmith#define MOD_METADATA(a, mm) { \ 19240107Smsmith COPY32(MODINFO_METADATA | mm->md_type, a); \ 19340107Smsmith COPY32(mm->md_size, a); \ 19440107Smsmith i386_copyin(mm->md_data, a, mm->md_size); \ 19540336Speter a += roundup(mm->md_size, sizeof(u_long));\ 19638465Smsmith} 19738465Smsmith 19839441Smsmith#define MOD_END(a) { \ 19940107Smsmith COPY32(MODINFO_END, a); \ 20040107Smsmith COPY32(0, a); \ 20139178Smsmith} 20239178Smsmith 20338465Smsmithvm_offset_t 20438465Smsmithbi_copymodules(vm_offset_t addr) 20538465Smsmith{ 20638465Smsmith struct loaded_module *mp; 20738465Smsmith struct module_metadata *md; 20838465Smsmith 20938465Smsmith /* start with the first module on the list, should be the kernel */ 21038465Smsmith for (mp = mod_findmodule(NULL, NULL); mp != NULL; mp = mp->m_next) { 21140146Speter 21239178Smsmith MOD_NAME(addr, mp->m_name); /* this field must come first */ 21338465Smsmith MOD_TYPE(addr, mp->m_type); 21444861Sdcs if (mp->m_args) 21544861Sdcs MOD_ARGS(addr, mp->m_args); 21638465Smsmith MOD_ADDR(addr, mp->m_addr); 21738465Smsmith MOD_SIZE(addr, mp->m_size); 21838465Smsmith for (md = mp->m_metadata; md != NULL; md = md->md_next) 21938764Smsmith if (!(md->md_type & MODINFOMD_NOCOPY)) 22038764Smsmith MOD_METADATA(addr, md); 22138465Smsmith } 22239178Smsmith MOD_END(addr); 22338465Smsmith return(addr); 22438465Smsmith} 22539902Smsmith 22639902Smsmith/* 22739902Smsmith * Load the information expected by an i386 kernel. 22839902Smsmith * 22939902Smsmith * - The 'boothowto' argument is constructed 23039902Smsmith * - The 'botdev' argument is constructed 23139902Smsmith * - The 'bootinfo' struct is constructed, and copied into the kernel space. 23239902Smsmith * - The kernel environment is copied into kernel space. 23339902Smsmith * - Module metadata are formatted and placed in kernel space. 23439902Smsmith */ 23539902Smsmithint 23639902Smsmithbi_load(char *args, int *howtop, int *bootdevp, vm_offset_t *bip) 23739902Smsmith{ 23839902Smsmith struct loaded_module *xp; 23939902Smsmith struct i386_devdesc *rootdev; 24039902Smsmith vm_offset_t addr, bootinfo_addr; 24139902Smsmith char *rootdevname; 24248083Srnordier int bootdevnr, i; 24339902Smsmith u_int pad; 24439902Smsmith char *kernelname; 24539989Smsmith const char *kernelpath; 24639902Smsmith 24739902Smsmith *howtop = bi_getboothowto(args); 24839902Smsmith 24939902Smsmith /* 25039902Smsmith * Allow the environment variable 'rootdev' to override the supplied device 25139902Smsmith * This should perhaps go to MI code and/or have $rootdev tested/set by 25239902Smsmith * MI code before launching the kernel. 25339902Smsmith */ 25439902Smsmith rootdevname = getenv("rootdev"); 25539902Smsmith i386_getdev((void **)(&rootdev), rootdevname, NULL); 25639902Smsmith if (rootdev == NULL) { /* bad $rootdev/$currdev */ 25739902Smsmith printf("can't determine root device\n"); 25839902Smsmith return(EINVAL); 25939902Smsmith } 26041139Smsmith 26148952Smsmith /* Try reading the /etc/fstab file to select the root device */ 26248952Smsmith getrootmount(i386_fmtdev((void *)rootdev)); 26348952Smsmith 26448952Smsmith /* Do legacy rootdev guessing */ 26539902Smsmith switch(rootdev->d_type) { 26639902Smsmith case DEVT_DISK: 26739902Smsmith /* pass in the BIOS device number of the current disk */ 26839902Smsmith bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit); 26939902Smsmith bootdevnr = bd_getdev(rootdev); 27043114Smsmith if (bootdevnr != -1) 27143114Smsmith break; 27243114Smsmith printf("root device %s invalid\n", i386_fmtdev(rootdev)); 27343114Smsmith return(EINVAL); 27459087Sps 27559087Sps case DEVT_NET: 27659087Sps break; 27759087Sps 27839902Smsmith default: 27948952Smsmith printf("WARNING - don't know how to boot from device type %d\n", rootdev->d_type); 28039902Smsmith } 28139902Smsmith free(rootdev); 28239902Smsmith *bootdevp = bootdevnr; 28339902Smsmith 28439902Smsmith /* legacy bootinfo structure */ 28539902Smsmith bi.bi_version = BOOTINFO_VERSION; 28639902Smsmith bi.bi_kernelname = 0; /* XXX char * -> kernel name */ 28739902Smsmith bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */ 28839902Smsmith bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */ 28948083Srnordier for (i = 0; i < N_BIOS_GEOM; i++) 29048083Srnordier bi.bi_bios_geom[i] = bd_getbigeom(i); 29139902Smsmith bi.bi_size = sizeof(bi); 29239902Smsmith bi.bi_memsizes_valid = 1; 29355211Smsmith bi.bi_basemem = bios_basemem / 1024; 29455211Smsmith bi.bi_extmem = bios_extmem / 1024; 29539902Smsmith 29639902Smsmith /* find the last module in the chain */ 29740393Speter addr = 0; 29840393Speter for (xp = mod_findmodule(NULL, NULL); xp != NULL; xp = xp->m_next) { 29940393Speter if (addr < (xp->m_addr + xp->m_size)) 30040393Speter addr = xp->m_addr + xp->m_size; 30140393Speter } 30239902Smsmith /* pad to a page boundary */ 30339902Smsmith pad = (u_int)addr & PAGE_MASK; 30439902Smsmith if (pad != 0) { 30539902Smsmith pad = PAGE_SIZE - pad; 30639902Smsmith addr += pad; 30739902Smsmith } 30839902Smsmith 30939902Smsmith /* copy our environment */ 31039902Smsmith bi.bi_envp = addr; 31139902Smsmith addr = bi_copyenv(addr); 31239902Smsmith 31339902Smsmith /* pad to a page boundary */ 31439902Smsmith pad = (u_int)addr & PAGE_MASK; 31539902Smsmith if (pad != 0) { 31639902Smsmith pad = PAGE_SIZE - pad; 31739902Smsmith addr += pad; 31839902Smsmith } 31939902Smsmith /* copy module list and metadata */ 32039902Smsmith bi.bi_modulep = addr; 32139902Smsmith addr = bi_copymodules(addr); 32239902Smsmith 32339902Smsmith /* all done copying stuff in, save end of loaded object space */ 32439902Smsmith bi.bi_kernend = addr; 32539902Smsmith 32639902Smsmith *howtop |= RB_BOOTINFO; /* it's there now */ 32739902Smsmith 32839989Smsmith /* 32939989Smsmith * Get the kernel name, strip off any device prefix. 33039989Smsmith */ 33139902Smsmith kernelname = getenv("kernelname"); 33239989Smsmith i386_getdev(NULL, kernelname, &kernelpath); 33339989Smsmith bi.bi_kernelname = VTOP(kernelpath); 33439902Smsmith *bip = VTOP(&bi); 33539902Smsmith 33639902Smsmith return(0); 33739902Smsmith} 338