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 */ 2885720Sjake 29124139Sobrien#include <sys/cdefs.h> 30124139Sobrien__FBSDID("$FreeBSD$"); 31124139Sobrien 3285720Sjake#include <stand.h> 3385720Sjake#include <sys/param.h> 3485720Sjake#include <sys/reboot.h> 3585720Sjake#include <sys/linker.h> 3685720Sjake 3791107Sjake#include <machine/metadata.h> 3891107Sjake 3985720Sjake#include "bootstrap.h" 4085720Sjake#include "libofw.h" 4185720Sjake 4297445Sjakeextern struct tlb_entry *dtlb_store; 4397445Sjakeextern struct tlb_entry *itlb_store; 4491139Sjake 4591139Sjakeextern int dtlb_slot; 4691139Sjakeextern int itlb_slot; 4791139Sjake 48149111Smariusstatic int md_bootserial(void); 49149111Smarius 5085720Sjake/* 5185720Sjake * Return a 'boothowto' value corresponding to the kernel arguments in 5285720Sjake * (kargs) and any relevant environment variables. 5385720Sjake */ 5485720Sjakestatic struct 5585720Sjake{ 5685720Sjake const char *ev; 5785720Sjake int mask; 5885720Sjake} howto_names[] = { 5985720Sjake {"boot_askname", RB_ASKNAME}, 6085720Sjake {"boot_cdrom", RB_CDROM}, 6185720Sjake {"boot_ddb", RB_KDB}, 62150469Sru {"boot_dfltroot", RB_DFLTROOT}, 6385720Sjake {"boot_gdb", RB_GDB}, 64150469Sru {"boot_multicons", RB_MULTIPLE}, 65150469Sru {"boot_mute", RB_MUTE}, 66150469Sru {"boot_pause", RB_PAUSE}, 67150469Sru {"boot_serial", RB_SERIAL}, 6885720Sjake {"boot_single", RB_SINGLE}, 6985720Sjake {"boot_verbose", RB_VERBOSE}, 7085720Sjake {NULL, 0} 7185720Sjake}; 7285720Sjake 7385720Sjakeint 7485720Sjakemd_getboothowto(char *kargs) 7585720Sjake{ 7685720Sjake char *cp; 7785720Sjake int howto; 7885720Sjake int active; 7985720Sjake int i; 8085720Sjake 8185720Sjake /* Parse kargs */ 8285720Sjake howto = 0; 8385720Sjake if (kargs != NULL) { 8485720Sjake cp = kargs; 8585720Sjake active = 0; 8685720Sjake while (*cp != 0) { 8785720Sjake if (!active && (*cp == '-')) { 8885720Sjake active = 1; 8985720Sjake } else if (active) 9085720Sjake switch (*cp) { 9185720Sjake case 'a': 9285720Sjake howto |= RB_ASKNAME; 9385720Sjake break; 9485720Sjake case 'C': 9585720Sjake howto |= RB_CDROM; 9685720Sjake break; 9785720Sjake case 'd': 9885720Sjake howto |= RB_KDB; 9985720Sjake break; 10085720Sjake case 'D': 10185720Sjake howto |= RB_MULTIPLE; 10285720Sjake break; 10385720Sjake case 'm': 10485720Sjake howto |= RB_MUTE; 10585720Sjake break; 10685720Sjake case 'g': 10785720Sjake howto |= RB_GDB; 10885720Sjake break; 10985720Sjake case 'h': 11085720Sjake howto |= RB_SERIAL; 11185720Sjake break; 112150469Sru case 'p': 113150469Sru howto |= RB_PAUSE; 114150469Sru break; 11585720Sjake case 'r': 11685720Sjake howto |= RB_DFLTROOT; 11785720Sjake break; 11885720Sjake case 's': 11985720Sjake howto |= RB_SINGLE; 12085720Sjake break; 12185720Sjake case 'v': 12285720Sjake howto |= RB_VERBOSE; 12385720Sjake break; 12485720Sjake default: 12585720Sjake active = 0; 12685720Sjake break; 12785720Sjake } 12885720Sjake cp++; 12985720Sjake } 13085720Sjake } 13185720Sjake /* get equivalents from the environment */ 13285720Sjake for (i = 0; howto_names[i].ev != NULL; i++) 13385720Sjake if (getenv(howto_names[i].ev) != NULL) 13485720Sjake howto |= howto_names[i].mask; 135149111Smarius if (md_bootserial() != -1) 136127826Smarcel howto |= RB_SERIAL; 137149111Smarius return(howto); 138149111Smarius} 139127826Smarcel 140149111Smariusstatic int 141149111Smariusmd_bootserial(void) 142149111Smarius{ 143149111Smarius char buf[64]; 144149111Smarius ihandle_t inst; 145149111Smarius phandle_t input; 146149111Smarius phandle_t node; 147149111Smarius phandle_t output; 148149111Smarius 149149111Smarius if ((node = OF_finddevice("/options")) == -1) 150149111Smarius return(-1); 151149111Smarius if (OF_getprop(node, "input-device", buf, sizeof(buf)) == -1) 152149111Smarius return(-1); 153149111Smarius input = OF_finddevice(buf); 154149111Smarius if (OF_getprop(node, "output-device", buf, sizeof(buf)) == -1) 155149111Smarius return(-1); 156149111Smarius output = OF_finddevice(buf); 157149111Smarius if (input == -1 || output == -1 || OF_getproplen(input, "keyboard") >= 0) { 158149111Smarius if ((node = OF_finddevice("/chosen")) == -1) 159149111Smarius return(-1); 160149111Smarius if (OF_getprop(node, "stdin", &inst, sizeof(inst)) == -1) 161149111Smarius return(-1); 162149111Smarius if ((input = OF_instance_to_package(inst)) == -1) 163149111Smarius return(-1); 164149111Smarius if (OF_getprop(node, "stdout", &inst, sizeof(inst)) == -1) 165149111Smarius return(-1); 166149111Smarius if ((output = OF_instance_to_package(inst)) == -1) 167149111Smarius return(-1); 168127826Smarcel } 169149111Smarius if (input != output) 170149111Smarius return(-1); 171149111Smarius if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) 172149111Smarius return(-1); 173149111Smarius if (strcmp(buf, "serial") != 0) 174149111Smarius return(-1); 175149111Smarius return(0); 17685720Sjake} 17785720Sjake 17885720Sjake/* 17985720Sjake * Copy the environment into the load area starting at (addr). 18085720Sjake * Each variable is formatted as <name>=<value>, with a single nul 18185720Sjake * separating each variable, and a double nul terminating the environment. 18285720Sjake */ 18385720Sjakevm_offset_t 18485720Sjakemd_copyenv(vm_offset_t addr) 18585720Sjake{ 18685720Sjake struct env_var *ep; 18785720Sjake 18885720Sjake /* traverse the environment */ 18985720Sjake for (ep = environ; ep != NULL; ep = ep->ev_next) { 19085720Sjake archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); 19185720Sjake addr += strlen(ep->ev_name); 19285720Sjake archsw.arch_copyin("=", addr, 1); 19385720Sjake addr++; 19485720Sjake if (ep->ev_value != NULL) { 19585720Sjake archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); 19685720Sjake addr += strlen(ep->ev_value); 19785720Sjake } 19885720Sjake archsw.arch_copyin("", addr, 1); 19985720Sjake addr++; 20085720Sjake } 20185720Sjake archsw.arch_copyin("", addr, 1); 20285720Sjake addr++; 20385720Sjake return(addr); 20485720Sjake} 20585720Sjake 20685720Sjake/* 20785720Sjake * Copy module-related data into the load area, where it can be 20885720Sjake * used as a directory for loaded modules. 20985720Sjake * 21085720Sjake * Module data is presented in a self-describing format. Each datum 21185720Sjake * is preceded by a 32-bit identifier and a 32-bit size field. 21285720Sjake * 21385720Sjake * Currently, the following data are saved: 21485720Sjake * 21585720Sjake * MOD_NAME (variable) module name (string) 21685720Sjake * MOD_TYPE (variable) module type (string) 21785720Sjake * MOD_ARGS (variable) module parameters (string) 21885720Sjake * MOD_ADDR sizeof(vm_offset_t) module load address 21985720Sjake * MOD_SIZE sizeof(size_t) module size 22085720Sjake * MOD_METADATA (variable) type-specific metadata 22185720Sjake */ 22285720Sjake#define COPY32(v, a, c) { \ 22385720Sjake u_int32_t x = (v); \ 22485720Sjake if (c) \ 22585720Sjake archsw.arch_copyin(&x, a, sizeof(x)); \ 22685720Sjake a += sizeof(x); \ 22785720Sjake} 22885720Sjake 22985720Sjake#define MOD_STR(t, a, s, c) { \ 23085720Sjake COPY32(t, a, c); \ 23185720Sjake COPY32(strlen(s) + 1, a, c) \ 23285720Sjake if (c) \ 23385720Sjake archsw.arch_copyin(s, a, strlen(s) + 1);\ 23485720Sjake a += roundup(strlen(s) + 1, sizeof(u_long));\ 23585720Sjake} 23685720Sjake 23785720Sjake#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) 23885720Sjake#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) 23985720Sjake#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) 24085720Sjake 24185720Sjake#define MOD_VAR(t, a, s, c) { \ 24285720Sjake COPY32(t, a, c); \ 24385720Sjake COPY32(sizeof(s), a, c); \ 24485720Sjake if (c) \ 24585720Sjake archsw.arch_copyin(&s, a, sizeof(s)); \ 24685720Sjake a += roundup(sizeof(s), sizeof(u_long)); \ 24785720Sjake} 24885720Sjake 24985720Sjake#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) 25085720Sjake#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) 25185720Sjake 25285720Sjake#define MOD_METADATA(a, mm, c) { \ 25385720Sjake COPY32(MODINFO_METADATA | mm->md_type, a, c);\ 25485720Sjake COPY32(mm->md_size, a, c); \ 25585720Sjake if (c) \ 25685720Sjake archsw.arch_copyin(mm->md_data, a, mm->md_size);\ 25785720Sjake a += roundup(mm->md_size, sizeof(u_long)); \ 25885720Sjake} 25985720Sjake 26085720Sjake#define MOD_END(a, c) { \ 26185720Sjake COPY32(MODINFO_END, a, c); \ 26285720Sjake COPY32(0, a, c); \ 26385720Sjake} 26485720Sjake 26585720Sjakevm_offset_t 26685720Sjakemd_copymodules(vm_offset_t addr) 26785720Sjake{ 26885720Sjake struct preloaded_file *fp; 26985720Sjake struct file_metadata *md; 27085720Sjake int c; 27185720Sjake 27285720Sjake c = addr != 0; 27385720Sjake /* start with the first module on the list, should be the kernel */ 27485720Sjake for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 27585720Sjake 27685720Sjake MOD_NAME(addr, fp->f_name, c); /* this field must come first */ 27785720Sjake MOD_TYPE(addr, fp->f_type, c); 27885720Sjake if (fp->f_args) 27985720Sjake MOD_ARGS(addr, fp->f_args, c); 28085720Sjake MOD_ADDR(addr, fp->f_addr, c); 28185720Sjake MOD_SIZE(addr, fp->f_size, c); 28285720Sjake for (md = fp->f_metadata; md != NULL; md = md->md_next) { 28385720Sjake if (!(md->md_type & MODINFOMD_NOCOPY)) { 28485720Sjake MOD_METADATA(addr, md, c); 28585720Sjake } 28685720Sjake } 28785720Sjake } 28885720Sjake MOD_END(addr, c); 28985720Sjake return(addr); 29085720Sjake} 29185720Sjake 29285720Sjake/* 29385720Sjake * Load the information expected by a sparc64 kernel. 29485720Sjake * 29585720Sjake * - The 'boothowto' argument is constructed 29685720Sjake * - The 'bootdev' argument is constructed 29785720Sjake * - The kernel environment is copied into kernel space. 29885720Sjake * - Module metadata are formatted and placed in kernel space. 29985720Sjake */ 30085720Sjakeint 30185720Sjakemd_load(char *args, vm_offset_t *modulep) 30285720Sjake{ 30385720Sjake struct preloaded_file *kfp; 30485720Sjake struct preloaded_file *xp; 30585720Sjake struct file_metadata *md; 30685720Sjake vm_offset_t kernend; 30785720Sjake vm_offset_t addr; 30885720Sjake vm_offset_t envp; 30985720Sjake vm_offset_t size; 31085720Sjake char *rootdevname; 31185720Sjake int howto; 31285720Sjake 31385720Sjake howto = md_getboothowto(args); 31485720Sjake 31585720Sjake /* 31685720Sjake * Allow the environment variable 'rootdev' to override the supplied device 31785720Sjake * This should perhaps go to MI code and/or have $rootdev tested/set by 31885720Sjake * MI code before launching the kernel. 31985720Sjake */ 320106738Sjake if ((rootdevname = getenv("rootdev")) == NULL) 321106738Sjake rootdevname = getenv("currdev"); 322106738Sjake getrootmount(rootdevname); 32385720Sjake 32485720Sjake /* find the last module in the chain */ 32585720Sjake addr = 0; 32685720Sjake for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 32785720Sjake if (addr < (xp->f_addr + xp->f_size)) 32885720Sjake addr = xp->f_addr + xp->f_size; 32985720Sjake } 33085720Sjake /* pad to a page boundary */ 33185720Sjake addr = roundup(addr, PAGE_SIZE); 33285720Sjake 33385720Sjake /* copy our environment */ 33485720Sjake envp = addr; 33585720Sjake addr = md_copyenv(addr); 33685720Sjake 33785720Sjake /* pad to a page boundary */ 33885720Sjake addr = roundup(addr, PAGE_SIZE); 33985720Sjake 34085720Sjake kernend = 0; 341114338Speter kfp = file_findfile(NULL, "elf64 kernel"); 34285720Sjake if (kfp == NULL) 343114338Speter kfp = file_findfile(NULL, "elf kernel"); 344114338Speter if (kfp == NULL) 34585720Sjake panic("can't find kernel file"); 34685720Sjake file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 34785720Sjake file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 34885720Sjake file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 349105427Stmm file_addmetadata(kfp, MODINFOMD_DTLB_SLOTS, sizeof dtlb_slot, &dtlb_slot); 350105427Stmm file_addmetadata(kfp, MODINFOMD_ITLB_SLOTS, sizeof itlb_slot, &itlb_slot); 35197445Sjake file_addmetadata(kfp, MODINFOMD_DTLB, 352105427Stmm dtlb_slot * sizeof(*dtlb_store), dtlb_store); 35397445Sjake file_addmetadata(kfp, MODINFOMD_ITLB, 354105427Stmm itlb_slot * sizeof(*itlb_store), itlb_store); 35585720Sjake 35685720Sjake *modulep = addr; 35785720Sjake size = md_copymodules(0); 35885720Sjake kernend = roundup(addr + size, PAGE_SIZE); 35985720Sjake 36085720Sjake md = file_findmetadata(kfp, MODINFOMD_KERNEND); 36185720Sjake bcopy(&kernend, md->md_data, sizeof kernend); 36285720Sjake 36385720Sjake (void)md_copymodules(addr); 36485720Sjake 36585720Sjake return(0); 36685720Sjake} 367