metadata.c revision 91107
185720Sjake/*- 285720Sjake * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 385720Sjake * All rights reserved. 485720Sjake * 585720Sjake * Redistribution and use in source and binary forms, with or without 685720Sjake * modification, are permitted provided that the following conditions 785720Sjake * are met: 885720Sjake * 1. Redistributions of source code must retain the above copyright 985720Sjake * notice, this list of conditions and the following disclaimer. 1085720Sjake * 2. Redistributions in binary form must reproduce the above copyright 1185720Sjake * notice, this list of conditions and the following disclaimer in the 1285720Sjake * documentation and/or other materials provided with the distribution. 1385720Sjake * 1485720Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1585720Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1685720Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1785720Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1885720Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1985720Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2085720Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2185720Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2285720Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2385720Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2485720Sjake * SUCH DAMAGE. 2585720Sjake * 2685720Sjake * from: FreeBSD: src/sys/boot/i386/libi386/bootinfo.c,v 1.29 2785720Sjake * $FreeBSD: head/sys/boot/sparc64/loader/metadata.c 91107 2002-02-23 03:33:39Z jake $ 2885720Sjake */ 2985720Sjake 3085720Sjake#include <stand.h> 3185720Sjake#include <sys/param.h> 3285720Sjake#include <sys/reboot.h> 3385720Sjake#include <sys/linker.h> 3485720Sjake 3591107Sjake#include <machine/metadata.h> 3691107Sjake 3785720Sjake#include "bootstrap.h" 3885720Sjake#include "libofw.h" 3985720Sjake 4085720Sjake/* 4185720Sjake * Return a 'boothowto' value corresponding to the kernel arguments in 4285720Sjake * (kargs) and any relevant environment variables. 4385720Sjake */ 4485720Sjakestatic struct 4585720Sjake{ 4685720Sjake const char *ev; 4785720Sjake int mask; 4885720Sjake} howto_names[] = { 4985720Sjake {"boot_askname", RB_ASKNAME}, 5085720Sjake {"boot_cdrom", RB_CDROM}, 5185720Sjake {"boot_userconfig", RB_CONFIG}, 5285720Sjake {"boot_ddb", RB_KDB}, 5385720Sjake {"boot_gdb", RB_GDB}, 5485720Sjake {"boot_single", RB_SINGLE}, 5585720Sjake {"boot_verbose", RB_VERBOSE}, 5685720Sjake {NULL, 0} 5785720Sjake}; 5885720Sjake 5985720Sjakeint 6085720Sjakemd_getboothowto(char *kargs) 6185720Sjake{ 6285720Sjake char *cp; 6385720Sjake int howto; 6485720Sjake int active; 6585720Sjake int i; 6685720Sjake 6785720Sjake /* Parse kargs */ 6885720Sjake howto = 0; 6985720Sjake if (kargs != NULL) { 7085720Sjake cp = kargs; 7185720Sjake active = 0; 7285720Sjake while (*cp != 0) { 7385720Sjake if (!active && (*cp == '-')) { 7485720Sjake active = 1; 7585720Sjake } else if (active) 7685720Sjake switch (*cp) { 7785720Sjake case 'a': 7885720Sjake howto |= RB_ASKNAME; 7985720Sjake break; 8085720Sjake case 'c': 8185720Sjake howto |= RB_CONFIG; 8285720Sjake break; 8385720Sjake case 'C': 8485720Sjake howto |= RB_CDROM; 8585720Sjake break; 8685720Sjake case 'd': 8785720Sjake howto |= RB_KDB; 8885720Sjake break; 8985720Sjake case 'D': 9085720Sjake howto |= RB_MULTIPLE; 9185720Sjake break; 9285720Sjake case 'm': 9385720Sjake howto |= RB_MUTE; 9485720Sjake break; 9585720Sjake case 'g': 9685720Sjake howto |= RB_GDB; 9785720Sjake break; 9885720Sjake case 'h': 9985720Sjake howto |= RB_SERIAL; 10085720Sjake break; 10185720Sjake case 'r': 10285720Sjake howto |= RB_DFLTROOT; 10385720Sjake break; 10485720Sjake case 's': 10585720Sjake howto |= RB_SINGLE; 10685720Sjake break; 10785720Sjake case 'v': 10885720Sjake howto |= RB_VERBOSE; 10985720Sjake break; 11085720Sjake default: 11185720Sjake active = 0; 11285720Sjake break; 11385720Sjake } 11485720Sjake cp++; 11585720Sjake } 11685720Sjake } 11785720Sjake /* get equivalents from the environment */ 11885720Sjake for (i = 0; howto_names[i].ev != NULL; i++) 11985720Sjake if (getenv(howto_names[i].ev) != NULL) 12085720Sjake howto |= howto_names[i].mask; 12185720Sjake if (!strcmp(getenv("console"), "comconsole")) 12285720Sjake howto |= RB_SERIAL; 12385720Sjake if (!strcmp(getenv("console"), "nullconsole")) 12485720Sjake howto |= RB_MUTE; 12585720Sjake return(howto); 12685720Sjake} 12785720Sjake 12885720Sjake/* 12985720Sjake * Copy the environment into the load area starting at (addr). 13085720Sjake * Each variable is formatted as <name>=<value>, with a single nul 13185720Sjake * separating each variable, and a double nul terminating the environment. 13285720Sjake */ 13385720Sjakevm_offset_t 13485720Sjakemd_copyenv(vm_offset_t addr) 13585720Sjake{ 13685720Sjake struct env_var *ep; 13785720Sjake 13885720Sjake /* traverse the environment */ 13985720Sjake for (ep = environ; ep != NULL; ep = ep->ev_next) { 14085720Sjake archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); 14185720Sjake addr += strlen(ep->ev_name); 14285720Sjake archsw.arch_copyin("=", addr, 1); 14385720Sjake addr++; 14485720Sjake if (ep->ev_value != NULL) { 14585720Sjake archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); 14685720Sjake addr += strlen(ep->ev_value); 14785720Sjake } 14885720Sjake archsw.arch_copyin("", addr, 1); 14985720Sjake addr++; 15085720Sjake } 15185720Sjake archsw.arch_copyin("", addr, 1); 15285720Sjake addr++; 15385720Sjake return(addr); 15485720Sjake} 15585720Sjake 15685720Sjake/* 15785720Sjake * Copy module-related data into the load area, where it can be 15885720Sjake * used as a directory for loaded modules. 15985720Sjake * 16085720Sjake * Module data is presented in a self-describing format. Each datum 16185720Sjake * is preceded by a 32-bit identifier and a 32-bit size field. 16285720Sjake * 16385720Sjake * Currently, the following data are saved: 16485720Sjake * 16585720Sjake * MOD_NAME (variable) module name (string) 16685720Sjake * MOD_TYPE (variable) module type (string) 16785720Sjake * MOD_ARGS (variable) module parameters (string) 16885720Sjake * MOD_ADDR sizeof(vm_offset_t) module load address 16985720Sjake * MOD_SIZE sizeof(size_t) module size 17085720Sjake * MOD_METADATA (variable) type-specific metadata 17185720Sjake */ 17285720Sjake#define COPY32(v, a, c) { \ 17385720Sjake u_int32_t x = (v); \ 17485720Sjake if (c) \ 17585720Sjake archsw.arch_copyin(&x, a, sizeof(x)); \ 17685720Sjake a += sizeof(x); \ 17785720Sjake} 17885720Sjake 17985720Sjake#define MOD_STR(t, a, s, c) { \ 18085720Sjake COPY32(t, a, c); \ 18185720Sjake COPY32(strlen(s) + 1, a, c) \ 18285720Sjake if (c) \ 18385720Sjake archsw.arch_copyin(s, a, strlen(s) + 1);\ 18485720Sjake a += roundup(strlen(s) + 1, sizeof(u_long));\ 18585720Sjake} 18685720Sjake 18785720Sjake#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) 18885720Sjake#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) 18985720Sjake#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) 19085720Sjake 19185720Sjake#define MOD_VAR(t, a, s, c) { \ 19285720Sjake COPY32(t, a, c); \ 19385720Sjake COPY32(sizeof(s), a, c); \ 19485720Sjake if (c) \ 19585720Sjake archsw.arch_copyin(&s, a, sizeof(s)); \ 19685720Sjake a += roundup(sizeof(s), sizeof(u_long)); \ 19785720Sjake} 19885720Sjake 19985720Sjake#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) 20085720Sjake#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) 20185720Sjake 20285720Sjake#define MOD_METADATA(a, mm, c) { \ 20385720Sjake COPY32(MODINFO_METADATA | mm->md_type, a, c);\ 20485720Sjake COPY32(mm->md_size, a, c); \ 20585720Sjake if (c) \ 20685720Sjake archsw.arch_copyin(mm->md_data, a, mm->md_size);\ 20785720Sjake a += roundup(mm->md_size, sizeof(u_long)); \ 20885720Sjake} 20985720Sjake 21085720Sjake#define MOD_END(a, c) { \ 21185720Sjake COPY32(MODINFO_END, a, c); \ 21285720Sjake COPY32(0, a, c); \ 21385720Sjake} 21485720Sjake 21585720Sjakevm_offset_t 21685720Sjakemd_copymodules(vm_offset_t addr) 21785720Sjake{ 21885720Sjake struct preloaded_file *fp; 21985720Sjake struct file_metadata *md; 22085720Sjake int c; 22185720Sjake 22285720Sjake c = addr != 0; 22385720Sjake /* start with the first module on the list, should be the kernel */ 22485720Sjake for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 22585720Sjake 22685720Sjake MOD_NAME(addr, fp->f_name, c); /* this field must come first */ 22785720Sjake MOD_TYPE(addr, fp->f_type, c); 22885720Sjake if (fp->f_args) 22985720Sjake MOD_ARGS(addr, fp->f_args, c); 23085720Sjake MOD_ADDR(addr, fp->f_addr, c); 23185720Sjake MOD_SIZE(addr, fp->f_size, c); 23285720Sjake for (md = fp->f_metadata; md != NULL; md = md->md_next) { 23385720Sjake if (!(md->md_type & MODINFOMD_NOCOPY)) { 23485720Sjake MOD_METADATA(addr, md, c); 23585720Sjake } 23685720Sjake } 23785720Sjake } 23885720Sjake MOD_END(addr, c); 23985720Sjake return(addr); 24085720Sjake} 24185720Sjake 24285720Sjake/* 24385720Sjake * Load the information expected by a sparc64 kernel. 24485720Sjake * 24585720Sjake * - The 'boothowto' argument is constructed 24685720Sjake * - The 'bootdev' argument is constructed 24785720Sjake * - The kernel environment is copied into kernel space. 24885720Sjake * - Module metadata are formatted and placed in kernel space. 24985720Sjake */ 25085720Sjakeint 25185720Sjakemd_load(char *args, vm_offset_t *modulep) 25285720Sjake{ 25385720Sjake struct preloaded_file *kfp; 25485720Sjake struct preloaded_file *xp; 25585720Sjake struct file_metadata *md; 25685720Sjake struct ofw_devdesc *rootdev; 25785720Sjake vm_offset_t kernend; 25885720Sjake vm_offset_t addr; 25985720Sjake vm_offset_t envp; 26085720Sjake vm_offset_t size; 26185720Sjake char *rootdevname; 26285720Sjake int howto; 26385720Sjake 26485720Sjake howto = md_getboothowto(args); 26585720Sjake 26685720Sjake /* 26785720Sjake * Allow the environment variable 'rootdev' to override the supplied device 26885720Sjake * This should perhaps go to MI code and/or have $rootdev tested/set by 26985720Sjake * MI code before launching the kernel. 27085720Sjake */ 27185720Sjake rootdevname = getenv("rootdev"); 27285720Sjake ofw_getdev((void **)(&rootdev), rootdevname, NULL); 27385720Sjake if (rootdev == NULL) { /* bad $rootdev/$currdev */ 27485720Sjake printf("can't determine root device\n"); 27585720Sjake return(EINVAL); 27685720Sjake } 27785720Sjake 27885720Sjake /* Try reading the /etc/fstab file to select the root device */ 27985720Sjake getrootmount(ofw_fmtdev((void *)rootdev)); 28085720Sjake 28185720Sjake free(rootdev); 28285720Sjake 28385720Sjake /* find the last module in the chain */ 28485720Sjake addr = 0; 28585720Sjake for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 28685720Sjake if (addr < (xp->f_addr + xp->f_size)) 28785720Sjake addr = xp->f_addr + xp->f_size; 28885720Sjake } 28985720Sjake /* pad to a page boundary */ 29085720Sjake addr = roundup(addr, PAGE_SIZE); 29185720Sjake 29285720Sjake /* copy our environment */ 29385720Sjake envp = addr; 29485720Sjake addr = md_copyenv(addr); 29585720Sjake 29685720Sjake /* pad to a page boundary */ 29785720Sjake addr = roundup(addr, PAGE_SIZE); 29885720Sjake 29985720Sjake kernend = 0; 30085720Sjake kfp = file_findfile(NULL, "elf kernel"); 30185720Sjake if (kfp == NULL) 30285720Sjake panic("can't find kernel file"); 30385720Sjake file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 30485720Sjake file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 30585720Sjake file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 30685720Sjake 30785720Sjake *modulep = addr; 30885720Sjake size = md_copymodules(0); 30985720Sjake kernend = roundup(addr + size, PAGE_SIZE); 31085720Sjake 31185720Sjake md = file_findmetadata(kfp, MODINFOMD_KERNEND); 31285720Sjake bcopy(&kernend, md->md_data, sizeof kernend); 31385720Sjake 31485720Sjake (void)md_copymodules(addr); 31585720Sjake 31685720Sjake return(0); 31785720Sjake} 318