metadata.c revision 99727
199727Sbenno/*- 299727Sbenno * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 399727Sbenno * All rights reserved. 499727Sbenno * 599727Sbenno * Redistribution and use in source and binary forms, with or without 699727Sbenno * modification, are permitted provided that the following conditions 799727Sbenno * are met: 899727Sbenno * 1. Redistributions of source code must retain the above copyright 999727Sbenno * notice, this list of conditions and the following disclaimer. 1099727Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1199727Sbenno * notice, this list of conditions and the following disclaimer in the 1299727Sbenno * documentation and/or other materials provided with the distribution. 1399727Sbenno * 1499727Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1599727Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1699727Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1799727Sbenno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1899727Sbenno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1999727Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2099727Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2199727Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2299727Sbenno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2399727Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2499727Sbenno * SUCH DAMAGE. 2599727Sbenno * 2699727Sbenno * from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.6 2799727Sbenno * $FreeBSD: head/sys/boot/powerpc/ofw/metadata.c 99727 2002-07-10 12:13:16Z benno $ 2899727Sbenno */ 2999727Sbenno 3099727Sbenno#include <stand.h> 3199727Sbenno#include <sys/param.h> 3299727Sbenno#include <sys/reboot.h> 3399727Sbenno#include <sys/linker.h> 3499727Sbenno 3599727Sbenno#include <machine/metadata.h> 3699727Sbenno 3799727Sbenno#include "bootstrap.h" 3899727Sbenno#include "libofw.h" 3999727Sbenno 4099727Sbenno/* 4199727Sbenno * Return a 'boothowto' value corresponding to the kernel arguments in 4299727Sbenno * (kargs) and any relevant environment variables. 4399727Sbenno */ 4499727Sbennostatic struct 4599727Sbenno{ 4699727Sbenno const char *ev; 4799727Sbenno int mask; 4899727Sbenno} howto_names[] = { 4999727Sbenno {"boot_askname", RB_ASKNAME}, 5099727Sbenno {"boot_cdrom", RB_CDROM}, 5199727Sbenno {"boot_userconfig", RB_CONFIG}, 5299727Sbenno {"boot_ddb", RB_KDB}, 5399727Sbenno {"boot_gdb", RB_GDB}, 5499727Sbenno {"boot_single", RB_SINGLE}, 5599727Sbenno {"boot_verbose", RB_VERBOSE}, 5699727Sbenno {"boot_multicons", RB_MULTIPLE}, 5799727Sbenno {"boot_serial", RB_SERIAL}, 5899727Sbenno {NULL, 0} 5999727Sbenno}; 6099727Sbenno 6199727Sbennoint 6299727Sbennomd_getboothowto(char *kargs) 6399727Sbenno{ 6499727Sbenno char *cp; 6599727Sbenno int howto; 6699727Sbenno int active; 6799727Sbenno int i; 6899727Sbenno 6999727Sbenno /* Parse kargs */ 7099727Sbenno howto = 0; 7199727Sbenno if (kargs != NULL) { 7299727Sbenno cp = kargs; 7399727Sbenno active = 0; 7499727Sbenno while (*cp != 0) { 7599727Sbenno if (!active && (*cp == '-')) { 7699727Sbenno active = 1; 7799727Sbenno } else if (active) 7899727Sbenno switch (*cp) { 7999727Sbenno case 'a': 8099727Sbenno howto |= RB_ASKNAME; 8199727Sbenno break; 8299727Sbenno case 'c': 8399727Sbenno howto |= RB_CONFIG; 8499727Sbenno break; 8599727Sbenno case 'C': 8699727Sbenno howto |= RB_CDROM; 8799727Sbenno break; 8899727Sbenno case 'd': 8999727Sbenno howto |= RB_KDB; 9099727Sbenno break; 9199727Sbenno case 'D': 9299727Sbenno howto |= RB_MULTIPLE; 9399727Sbenno break; 9499727Sbenno case 'm': 9599727Sbenno howto |= RB_MUTE; 9699727Sbenno break; 9799727Sbenno case 'g': 9899727Sbenno howto |= RB_GDB; 9999727Sbenno break; 10099727Sbenno case 'h': 10199727Sbenno howto |= RB_SERIAL; 10299727Sbenno break; 10399727Sbenno case 'r': 10499727Sbenno howto |= RB_DFLTROOT; 10599727Sbenno break; 10699727Sbenno case 's': 10799727Sbenno howto |= RB_SINGLE; 10899727Sbenno break; 10999727Sbenno case 'v': 11099727Sbenno howto |= RB_VERBOSE; 11199727Sbenno break; 11299727Sbenno default: 11399727Sbenno active = 0; 11499727Sbenno break; 11599727Sbenno } 11699727Sbenno cp++; 11799727Sbenno } 11899727Sbenno } 11999727Sbenno /* get equivalents from the environment */ 12099727Sbenno for (i = 0; howto_names[i].ev != NULL; i++) 12199727Sbenno if (getenv(howto_names[i].ev) != NULL) 12299727Sbenno howto |= howto_names[i].mask; 12399727Sbenno if (!strcmp(getenv("console"), "comconsole")) 12499727Sbenno howto |= RB_SERIAL; 12599727Sbenno if (!strcmp(getenv("console"), "nullconsole")) 12699727Sbenno howto |= RB_MUTE; 12799727Sbenno return(howto); 12899727Sbenno} 12999727Sbenno 13099727Sbenno/* 13199727Sbenno * Copy the environment into the load area starting at (addr). 13299727Sbenno * Each variable is formatted as <name>=<value>, with a single nul 13399727Sbenno * separating each variable, and a double nul terminating the environment. 13499727Sbenno */ 13599727Sbennovm_offset_t 13699727Sbennomd_copyenv(vm_offset_t addr) 13799727Sbenno{ 13899727Sbenno struct env_var *ep; 13999727Sbenno 14099727Sbenno /* traverse the environment */ 14199727Sbenno for (ep = environ; ep != NULL; ep = ep->ev_next) { 14299727Sbenno archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); 14399727Sbenno addr += strlen(ep->ev_name); 14499727Sbenno archsw.arch_copyin("=", addr, 1); 14599727Sbenno addr++; 14699727Sbenno if (ep->ev_value != NULL) { 14799727Sbenno archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); 14899727Sbenno addr += strlen(ep->ev_value); 14999727Sbenno } 15099727Sbenno archsw.arch_copyin("", addr, 1); 15199727Sbenno addr++; 15299727Sbenno } 15399727Sbenno archsw.arch_copyin("", addr, 1); 15499727Sbenno addr++; 15599727Sbenno return(addr); 15699727Sbenno} 15799727Sbenno 15899727Sbenno/* 15999727Sbenno * Copy module-related data into the load area, where it can be 16099727Sbenno * used as a directory for loaded modules. 16199727Sbenno * 16299727Sbenno * Module data is presented in a self-describing format. Each datum 16399727Sbenno * is preceded by a 32-bit identifier and a 32-bit size field. 16499727Sbenno * 16599727Sbenno * Currently, the following data are saved: 16699727Sbenno * 16799727Sbenno * MOD_NAME (variable) module name (string) 16899727Sbenno * MOD_TYPE (variable) module type (string) 16999727Sbenno * MOD_ARGS (variable) module parameters (string) 17099727Sbenno * MOD_ADDR sizeof(vm_offset_t) module load address 17199727Sbenno * MOD_SIZE sizeof(size_t) module size 17299727Sbenno * MOD_METADATA (variable) type-specific metadata 17399727Sbenno */ 17499727Sbenno#define COPY32(v, a, c) { \ 17599727Sbenno u_int32_t x = (v); \ 17699727Sbenno if (c) \ 17799727Sbenno archsw.arch_copyin(&x, a, sizeof(x)); \ 17899727Sbenno a += sizeof(x); \ 17999727Sbenno} 18099727Sbenno 18199727Sbenno#define MOD_STR(t, a, s, c) { \ 18299727Sbenno COPY32(t, a, c); \ 18399727Sbenno COPY32(strlen(s) + 1, a, c) \ 18499727Sbenno if (c) \ 18599727Sbenno archsw.arch_copyin(s, a, strlen(s) + 1);\ 18699727Sbenno a += roundup(strlen(s) + 1, sizeof(u_long));\ 18799727Sbenno} 18899727Sbenno 18999727Sbenno#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) 19099727Sbenno#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) 19199727Sbenno#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) 19299727Sbenno 19399727Sbenno#define MOD_VAR(t, a, s, c) { \ 19499727Sbenno COPY32(t, a, c); \ 19599727Sbenno COPY32(sizeof(s), a, c); \ 19699727Sbenno if (c) \ 19799727Sbenno archsw.arch_copyin(&s, a, sizeof(s)); \ 19899727Sbenno a += roundup(sizeof(s), sizeof(u_long)); \ 19999727Sbenno} 20099727Sbenno 20199727Sbenno#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) 20299727Sbenno#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) 20399727Sbenno 20499727Sbenno#define MOD_METADATA(a, mm, c) { \ 20599727Sbenno COPY32(MODINFO_METADATA | mm->md_type, a, c);\ 20699727Sbenno COPY32(mm->md_size, a, c); \ 20799727Sbenno if (c) \ 20899727Sbenno archsw.arch_copyin(mm->md_data, a, mm->md_size);\ 20999727Sbenno a += roundup(mm->md_size, sizeof(u_long)); \ 21099727Sbenno} 21199727Sbenno 21299727Sbenno#define MOD_END(a, c) { \ 21399727Sbenno COPY32(MODINFO_END, a, c); \ 21499727Sbenno COPY32(0, a, c); \ 21599727Sbenno} 21699727Sbenno 21799727Sbennovm_offset_t 21899727Sbennomd_copymodules(vm_offset_t addr) 21999727Sbenno{ 22099727Sbenno struct preloaded_file *fp; 22199727Sbenno struct file_metadata *md; 22299727Sbenno int c; 22399727Sbenno 22499727Sbenno c = addr != 0; 22599727Sbenno /* start with the first module on the list, should be the kernel */ 22699727Sbenno for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 22799727Sbenno 22899727Sbenno MOD_NAME(addr, fp->f_name, c); /* this field must come first */ 22999727Sbenno MOD_TYPE(addr, fp->f_type, c); 23099727Sbenno if (fp->f_args) 23199727Sbenno MOD_ARGS(addr, fp->f_args, c); 23299727Sbenno MOD_ADDR(addr, fp->f_addr, c); 23399727Sbenno MOD_SIZE(addr, fp->f_size, c); 23499727Sbenno for (md = fp->f_metadata; md != NULL; md = md->md_next) { 23599727Sbenno if (!(md->md_type & MODINFOMD_NOCOPY)) { 23699727Sbenno MOD_METADATA(addr, md, c); 23799727Sbenno } 23899727Sbenno } 23999727Sbenno } 24099727Sbenno MOD_END(addr, c); 24199727Sbenno return(addr); 24299727Sbenno} 24399727Sbenno 24499727Sbenno/* 24599727Sbenno * Load the information expected by a powerpc kernel. 24699727Sbenno * 24799727Sbenno * - The 'boothowto' argument is constructed 24899727Sbenno * - The 'bootdev' argument is constructed 24999727Sbenno * - The kernel environment is copied into kernel space. 25099727Sbenno * - Module metadata are formatted and placed in kernel space. 25199727Sbenno */ 25299727Sbennoint 25399727Sbennomd_load(char *args, vm_offset_t *modulep) 25499727Sbenno{ 25599727Sbenno struct preloaded_file *kfp; 25699727Sbenno struct preloaded_file *xp; 25799727Sbenno struct file_metadata *md; 25899727Sbenno struct ofw_devdesc *rootdev; 25999727Sbenno vm_offset_t kernend; 26099727Sbenno vm_offset_t addr; 26199727Sbenno vm_offset_t envp; 26299727Sbenno vm_offset_t size; 26399727Sbenno char *rootdevname; 26499727Sbenno int howto; 26599727Sbenno int dtlb_slots; 26699727Sbenno int itlb_slots; 26799727Sbenno 26899727Sbenno howto = md_getboothowto(args); 26999727Sbenno 27099727Sbenno /* 27199727Sbenno * Allow the environment variable 'rootdev' to override the supplied device 27299727Sbenno * This should perhaps go to MI code and/or have $rootdev tested/set by 27399727Sbenno * MI code before launching the kernel. 27499727Sbenno */ 27599727Sbenno rootdevname = getenv("rootdev"); 27699727Sbenno ofw_getdev((void **)(&rootdev), rootdevname, NULL); 27799727Sbenno if (rootdev == NULL) { /* bad $rootdev/$currdev */ 27899727Sbenno printf("can't determine root device\n"); 27999727Sbenno return(EINVAL); 28099727Sbenno } 28199727Sbenno 28299727Sbenno /* Try reading the /etc/fstab file to select the root device */ 28399727Sbenno getrootmount(ofw_fmtdev((void *)rootdev)); 28499727Sbenno 28599727Sbenno free(rootdev); 28699727Sbenno 28799727Sbenno /* find the last module in the chain */ 28899727Sbenno addr = 0; 28999727Sbenno for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 29099727Sbenno if (addr < (xp->f_addr + xp->f_size)) 29199727Sbenno addr = xp->f_addr + xp->f_size; 29299727Sbenno } 29399727Sbenno /* pad to a page boundary */ 29499727Sbenno addr = roundup(addr, PAGE_SIZE); 29599727Sbenno 29699727Sbenno /* copy our environment */ 29799727Sbenno envp = addr; 29899727Sbenno addr = md_copyenv(addr); 29999727Sbenno 30099727Sbenno /* pad to a page boundary */ 30199727Sbenno addr = roundup(addr, PAGE_SIZE); 30299727Sbenno 30399727Sbenno kernend = 0; 30499727Sbenno kfp = file_findfile(NULL, "elf kernel"); 30599727Sbenno if (kfp == NULL) 30699727Sbenno panic("can't find kernel file"); 30799727Sbenno file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 30899727Sbenno file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 30999727Sbenno file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 31099727Sbenno 31199727Sbenno *modulep = addr; 31299727Sbenno size = md_copymodules(0); 31399727Sbenno kernend = roundup(addr + size, PAGE_SIZE); 31499727Sbenno 31599727Sbenno md = file_findmetadata(kfp, MODINFOMD_KERNEND); 31699727Sbenno bcopy(&kernend, md->md_data, sizeof kernend); 31799727Sbenno 31899727Sbenno (void)md_copymodules(addr); 31999727Sbenno 32099727Sbenno return(0); 32199727Sbenno} 322