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 */ 2899727Sbenno 29124139Sobrien#include <sys/cdefs.h> 30124139Sobrien__FBSDID("$FreeBSD$"); 31124139Sobrien 3299727Sbenno#include <stand.h> 3399727Sbenno#include <sys/param.h> 3499727Sbenno#include <sys/reboot.h> 3599727Sbenno#include <sys/linker.h> 36271132Semaste#include <sys/boot.h> 3799727Sbenno 3899727Sbenno#include <machine/metadata.h> 3999727Sbenno 4099727Sbenno#include "bootstrap.h" 4199727Sbenno#include "libofw.h" 4299727Sbenno 4399727Sbennoint 4499727Sbennomd_getboothowto(char *kargs) 4599727Sbenno{ 4699727Sbenno char *cp; 4799727Sbenno int howto; 4899727Sbenno int active; 4999727Sbenno int i; 5099727Sbenno 5199727Sbenno /* Parse kargs */ 5299727Sbenno howto = 0; 5399727Sbenno if (kargs != NULL) { 5499727Sbenno cp = kargs; 5599727Sbenno active = 0; 5699727Sbenno while (*cp != 0) { 5799727Sbenno if (!active && (*cp == '-')) { 5899727Sbenno active = 1; 5999727Sbenno } else if (active) 6099727Sbenno switch (*cp) { 6199727Sbenno case 'a': 6299727Sbenno howto |= RB_ASKNAME; 6399727Sbenno break; 6499727Sbenno case 'C': 6599727Sbenno howto |= RB_CDROM; 6699727Sbenno break; 6799727Sbenno case 'd': 6899727Sbenno howto |= RB_KDB; 6999727Sbenno break; 7099727Sbenno case 'D': 7199727Sbenno howto |= RB_MULTIPLE; 7299727Sbenno break; 7399727Sbenno case 'm': 7499727Sbenno howto |= RB_MUTE; 7599727Sbenno break; 7699727Sbenno case 'g': 7799727Sbenno howto |= RB_GDB; 7899727Sbenno break; 7999727Sbenno case 'h': 8099727Sbenno howto |= RB_SERIAL; 8199727Sbenno break; 82150469Sru case 'p': 83150469Sru howto |= RB_PAUSE; 84150469Sru break; 8599727Sbenno case 'r': 8699727Sbenno howto |= RB_DFLTROOT; 8799727Sbenno break; 8899727Sbenno case 's': 8999727Sbenno howto |= RB_SINGLE; 9099727Sbenno break; 9199727Sbenno case 'v': 9299727Sbenno howto |= RB_VERBOSE; 9399727Sbenno break; 9499727Sbenno default: 9599727Sbenno active = 0; 9699727Sbenno break; 9799727Sbenno } 9899727Sbenno cp++; 9999727Sbenno } 10099727Sbenno } 10199727Sbenno /* get equivalents from the environment */ 10299727Sbenno for (i = 0; howto_names[i].ev != NULL; i++) 10399727Sbenno if (getenv(howto_names[i].ev) != NULL) 10499727Sbenno howto |= howto_names[i].mask; 10599727Sbenno if (!strcmp(getenv("console"), "comconsole")) 10699727Sbenno howto |= RB_SERIAL; 10799727Sbenno if (!strcmp(getenv("console"), "nullconsole")) 10899727Sbenno howto |= RB_MUTE; 10999727Sbenno return(howto); 11099727Sbenno} 11199727Sbenno 11299727Sbenno/* 11399727Sbenno * Copy the environment into the load area starting at (addr). 11499727Sbenno * Each variable is formatted as <name>=<value>, with a single nul 11599727Sbenno * separating each variable, and a double nul terminating the environment. 11699727Sbenno */ 11799727Sbennovm_offset_t 11899727Sbennomd_copyenv(vm_offset_t addr) 11999727Sbenno{ 12099727Sbenno struct env_var *ep; 12199727Sbenno 12299727Sbenno /* traverse the environment */ 12399727Sbenno for (ep = environ; ep != NULL; ep = ep->ev_next) { 12499727Sbenno archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); 12599727Sbenno addr += strlen(ep->ev_name); 12699727Sbenno archsw.arch_copyin("=", addr, 1); 12799727Sbenno addr++; 12899727Sbenno if (ep->ev_value != NULL) { 12999727Sbenno archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); 13099727Sbenno addr += strlen(ep->ev_value); 13199727Sbenno } 13299727Sbenno archsw.arch_copyin("", addr, 1); 13399727Sbenno addr++; 13499727Sbenno } 13599727Sbenno archsw.arch_copyin("", addr, 1); 13699727Sbenno addr++; 13799727Sbenno return(addr); 13899727Sbenno} 13999727Sbenno 14099727Sbenno/* 14199727Sbenno * Copy module-related data into the load area, where it can be 14299727Sbenno * used as a directory for loaded modules. 14399727Sbenno * 14499727Sbenno * Module data is presented in a self-describing format. Each datum 14599727Sbenno * is preceded by a 32-bit identifier and a 32-bit size field. 14699727Sbenno * 14799727Sbenno * Currently, the following data are saved: 14899727Sbenno * 14999727Sbenno * MOD_NAME (variable) module name (string) 15099727Sbenno * MOD_TYPE (variable) module type (string) 15199727Sbenno * MOD_ARGS (variable) module parameters (string) 15299727Sbenno * MOD_ADDR sizeof(vm_offset_t) module load address 15399727Sbenno * MOD_SIZE sizeof(size_t) module size 15499727Sbenno * MOD_METADATA (variable) type-specific metadata 15599727Sbenno */ 156209920Snwhitehorn 157209920Snwhitehornstatic int align; 158209920Snwhitehorn 15999727Sbenno#define COPY32(v, a, c) { \ 16099727Sbenno u_int32_t x = (v); \ 16199727Sbenno if (c) \ 16299727Sbenno archsw.arch_copyin(&x, a, sizeof(x)); \ 16399727Sbenno a += sizeof(x); \ 16499727Sbenno} 16599727Sbenno 16699727Sbenno#define MOD_STR(t, a, s, c) { \ 16799727Sbenno COPY32(t, a, c); \ 16899727Sbenno COPY32(strlen(s) + 1, a, c) \ 16999727Sbenno if (c) \ 17099727Sbenno archsw.arch_copyin(s, a, strlen(s) + 1);\ 171209920Snwhitehorn a += roundup(strlen(s) + 1, align); \ 17299727Sbenno} 17399727Sbenno 17499727Sbenno#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) 17599727Sbenno#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) 17699727Sbenno#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) 17799727Sbenno 17899727Sbenno#define MOD_VAR(t, a, s, c) { \ 17999727Sbenno COPY32(t, a, c); \ 18099727Sbenno COPY32(sizeof(s), a, c); \ 18199727Sbenno if (c) \ 18299727Sbenno archsw.arch_copyin(&s, a, sizeof(s)); \ 183209920Snwhitehorn a += roundup(sizeof(s), align); \ 18499727Sbenno} 18599727Sbenno 18699727Sbenno#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) 18799727Sbenno#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) 18899727Sbenno 18999727Sbenno#define MOD_METADATA(a, mm, c) { \ 19099727Sbenno COPY32(MODINFO_METADATA | mm->md_type, a, c);\ 19199727Sbenno COPY32(mm->md_size, a, c); \ 19299727Sbenno if (c) \ 19399727Sbenno archsw.arch_copyin(mm->md_data, a, mm->md_size);\ 194209920Snwhitehorn a += roundup(mm->md_size, align); \ 19599727Sbenno} 19699727Sbenno 19799727Sbenno#define MOD_END(a, c) { \ 19899727Sbenno COPY32(MODINFO_END, a, c); \ 19999727Sbenno COPY32(0, a, c); \ 20099727Sbenno} 20199727Sbenno 20299727Sbennovm_offset_t 203209920Snwhitehornmd_copymodules(vm_offset_t addr, int kern64) 20499727Sbenno{ 20599727Sbenno struct preloaded_file *fp; 20699727Sbenno struct file_metadata *md; 207209920Snwhitehorn uint64_t scratch64; 20899727Sbenno int c; 20999727Sbenno 21099727Sbenno c = addr != 0; 21199727Sbenno /* start with the first module on the list, should be the kernel */ 21299727Sbenno for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 21399727Sbenno 21499727Sbenno MOD_NAME(addr, fp->f_name, c); /* this field must come first */ 21599727Sbenno MOD_TYPE(addr, fp->f_type, c); 21699727Sbenno if (fp->f_args) 21799727Sbenno MOD_ARGS(addr, fp->f_args, c); 218209920Snwhitehorn if (kern64) { 219209920Snwhitehorn scratch64 = fp->f_addr; 220209920Snwhitehorn MOD_ADDR(addr, scratch64, c); 221209920Snwhitehorn scratch64 = fp->f_size; 222209920Snwhitehorn MOD_SIZE(addr, scratch64, c); 223209920Snwhitehorn } else { 224209920Snwhitehorn MOD_ADDR(addr, fp->f_addr, c); 225209920Snwhitehorn MOD_SIZE(addr, fp->f_size, c); 226209920Snwhitehorn } 22799727Sbenno for (md = fp->f_metadata; md != NULL; md = md->md_next) { 22899727Sbenno if (!(md->md_type & MODINFOMD_NOCOPY)) { 22999727Sbenno MOD_METADATA(addr, md, c); 23099727Sbenno } 23199727Sbenno } 23299727Sbenno } 23399727Sbenno MOD_END(addr, c); 23499727Sbenno return(addr); 23599727Sbenno} 23699727Sbenno 23799727Sbenno/* 23899727Sbenno * Load the information expected by a powerpc kernel. 23999727Sbenno * 24099727Sbenno * - The 'boothowto' argument is constructed 24199727Sbenno * - The 'bootdev' argument is constructed 24299727Sbenno * - The kernel environment is copied into kernel space. 24399727Sbenno * - Module metadata are formatted and placed in kernel space. 24499727Sbenno */ 24599727Sbennoint 246209920Snwhitehornmd_load_dual(char *args, vm_offset_t *modulep, int kern64) 24799727Sbenno{ 24899727Sbenno struct preloaded_file *kfp; 24999727Sbenno struct preloaded_file *xp; 25099727Sbenno struct file_metadata *md; 25199727Sbenno vm_offset_t kernend; 25299727Sbenno vm_offset_t addr; 25399727Sbenno vm_offset_t envp; 25499727Sbenno vm_offset_t size; 255209920Snwhitehorn uint64_t scratch64; 25699727Sbenno char *rootdevname; 25799727Sbenno int howto; 25899727Sbenno 259209920Snwhitehorn align = kern64 ? 8 : 4; 26099727Sbenno howto = md_getboothowto(args); 26199727Sbenno 26299727Sbenno /* 26399727Sbenno * Allow the environment variable 'rootdev' to override the supplied device 26499727Sbenno * This should perhaps go to MI code and/or have $rootdev tested/set by 26599727Sbenno * MI code before launching the kernel. 26699727Sbenno */ 26799727Sbenno rootdevname = getenv("rootdev"); 268106738Sjake if (rootdevname == NULL) 269106738Sjake rootdevname = getenv("currdev"); 27099727Sbenno /* Try reading the /etc/fstab file to select the root device */ 271106738Sjake getrootmount(rootdevname); 27299727Sbenno 27399727Sbenno /* find the last module in the chain */ 27499727Sbenno addr = 0; 27599727Sbenno for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 27699727Sbenno if (addr < (xp->f_addr + xp->f_size)) 27799727Sbenno addr = xp->f_addr + xp->f_size; 27899727Sbenno } 27999727Sbenno /* pad to a page boundary */ 28099727Sbenno addr = roundup(addr, PAGE_SIZE); 28199727Sbenno 28299727Sbenno /* copy our environment */ 28399727Sbenno envp = addr; 28499727Sbenno addr = md_copyenv(addr); 28599727Sbenno 28699727Sbenno /* pad to a page boundary */ 28799727Sbenno addr = roundup(addr, PAGE_SIZE); 28899727Sbenno 28999727Sbenno kernend = 0; 290209920Snwhitehorn kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel"); 29199727Sbenno if (kfp == NULL) 292114338Speter kfp = file_findfile(NULL, "elf kernel"); 293114338Speter if (kfp == NULL) 29499727Sbenno panic("can't find kernel file"); 29599727Sbenno file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 296209920Snwhitehorn if (kern64) { 297209920Snwhitehorn scratch64 = envp; 298209920Snwhitehorn file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64); 299209920Snwhitehorn scratch64 = kernend; 300209920Snwhitehorn file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64); 301209920Snwhitehorn } else { 302209920Snwhitehorn file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 303209920Snwhitehorn file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 304209920Snwhitehorn } 30599727Sbenno 30699727Sbenno *modulep = addr; 307209920Snwhitehorn size = md_copymodules(0, kern64); 30899727Sbenno kernend = roundup(addr + size, PAGE_SIZE); 30999727Sbenno 31099727Sbenno md = file_findmetadata(kfp, MODINFOMD_KERNEND); 311209920Snwhitehorn if (kern64) { 312209920Snwhitehorn scratch64 = kernend; 313209920Snwhitehorn bcopy(&scratch64, md->md_data, sizeof scratch64); 314209920Snwhitehorn } else { 315209920Snwhitehorn bcopy(&kernend, md->md_data, sizeof kernend); 316209920Snwhitehorn } 317209920Snwhitehorn 318209920Snwhitehorn (void)md_copymodules(addr, kern64); 31999727Sbenno 32099727Sbenno return(0); 32199727Sbenno} 322209920Snwhitehorn 323209920Snwhitehornint 324209920Snwhitehornmd_load(char *args, vm_offset_t *modulep) 325209920Snwhitehorn{ 326209920Snwhitehorn return (md_load_dual(args, modulep, 0)); 327209920Snwhitehorn} 328209920Snwhitehorn 329209920Snwhitehornint 330209920Snwhitehornmd_load64(char *args, vm_offset_t *modulep) 331209920Snwhitehorn{ 332209920Snwhitehorn return (md_load_dual(args, modulep, 1)); 333209920Snwhitehorn} 334209920Snwhitehorn 335