metadata.c revision 138249
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * from: FreeBSD: src/sys/boot/i386/libi386/bootinfo.c,v 1.29 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: head/sys/boot/sparc64/loader/metadata.c 138249 2004-12-01 04:59:33Z scottl $"); 31 32#include <stand.h> 33#include <sys/param.h> 34#include <sys/reboot.h> 35#include <sys/linker.h> 36 37#include <machine/metadata.h> 38 39#include "bootstrap.h" 40#include "libofw.h" 41 42extern struct tlb_entry *dtlb_store; 43extern struct tlb_entry *itlb_store; 44 45extern int dtlb_slot; 46extern int itlb_slot; 47 48/* 49 * Return a 'boothowto' value corresponding to the kernel arguments in 50 * (kargs) and any relevant environment variables. 51 */ 52static struct 53{ 54 const char *ev; 55 int mask; 56} howto_names[] = { 57 {"boot_askname", RB_ASKNAME}, 58 {"boot_cdrom", RB_CDROM}, 59 {"boot_ddb", RB_KDB}, 60 {"boot_gdb", RB_GDB}, 61 {"boot_single", RB_SINGLE}, 62 {"boot_verbose", RB_VERBOSE}, 63 {"boot_multicons", RB_MULTIPLE}, 64 {"boot_serial", RB_SERIAL}, 65 {NULL, 0} 66}; 67 68int 69md_getboothowto(char *kargs) 70{ 71 char buf[32], buf2[32]; 72 phandle_t options; 73 char *cp; 74 int howto; 75 int active; 76 int i; 77 78 /* Parse kargs */ 79 howto = 0; 80 if (kargs != NULL) { 81 cp = kargs; 82 active = 0; 83 while (*cp != 0) { 84 if (!active && (*cp == '-')) { 85 active = 1; 86 } else if (active) 87 switch (*cp) { 88 case 'a': 89 howto |= RB_ASKNAME; 90 break; 91 case 'C': 92 howto |= RB_CDROM; 93 break; 94 case 'd': 95 howto |= RB_KDB; 96 break; 97 case 'D': 98 howto |= RB_MULTIPLE; 99 break; 100 case 'm': 101 howto |= RB_MUTE; 102 break; 103 case 'g': 104 howto |= RB_GDB; 105 break; 106 case 'h': 107 howto |= RB_SERIAL; 108 break; 109 case 'r': 110 howto |= RB_DFLTROOT; 111 break; 112 case 's': 113 howto |= RB_SINGLE; 114 break; 115 case 'v': 116 howto |= RB_VERBOSE; 117 break; 118 default: 119 active = 0; 120 break; 121 } 122 cp++; 123 } 124 } 125 /* get equivalents from the environment */ 126 for (i = 0; howto_names[i].ev != NULL; i++) 127 if (getenv(howto_names[i].ev) != NULL) 128 howto |= howto_names[i].mask; 129 options = OF_finddevice("/options"); 130 OF_getprop(options, "input-device", buf, sizeof(buf)); 131 OF_getprop(options, "output-device", buf2, sizeof(buf2)); 132 if (strncmp(buf, "tty", sizeof("tty") - 1) == 0 && strncmp(buf2, "tty", 133 sizeof("tty") - 1) == 0) 134 howto |= RB_SERIAL; 135 else if (strcmp(buf, "keyboard") == 0 && strcmp(buf2, "screen") == 0) { 136 phandle_t chosen; 137 ihandle_t stdin, stdout; 138 139 chosen = OF_finddevice("/chosen"); 140 OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)); 141 OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); 142 if (OF_instance_to_package(stdin) == OF_instance_to_package(stdout)) 143 howto |= RB_SERIAL; 144 } 145 return(howto); 146} 147 148/* 149 * Copy the environment into the load area starting at (addr). 150 * Each variable is formatted as <name>=<value>, with a single nul 151 * separating each variable, and a double nul terminating the environment. 152 */ 153vm_offset_t 154md_copyenv(vm_offset_t addr) 155{ 156 struct env_var *ep; 157 158 /* traverse the environment */ 159 for (ep = environ; ep != NULL; ep = ep->ev_next) { 160 archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); 161 addr += strlen(ep->ev_name); 162 archsw.arch_copyin("=", addr, 1); 163 addr++; 164 if (ep->ev_value != NULL) { 165 archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); 166 addr += strlen(ep->ev_value); 167 } 168 archsw.arch_copyin("", addr, 1); 169 addr++; 170 } 171 archsw.arch_copyin("", addr, 1); 172 addr++; 173 return(addr); 174} 175 176/* 177 * Copy module-related data into the load area, where it can be 178 * used as a directory for loaded modules. 179 * 180 * Module data is presented in a self-describing format. Each datum 181 * is preceded by a 32-bit identifier and a 32-bit size field. 182 * 183 * Currently, the following data are saved: 184 * 185 * MOD_NAME (variable) module name (string) 186 * MOD_TYPE (variable) module type (string) 187 * MOD_ARGS (variable) module parameters (string) 188 * MOD_ADDR sizeof(vm_offset_t) module load address 189 * MOD_SIZE sizeof(size_t) module size 190 * MOD_METADATA (variable) type-specific metadata 191 */ 192#define COPY32(v, a, c) { \ 193 u_int32_t x = (v); \ 194 if (c) \ 195 archsw.arch_copyin(&x, a, sizeof(x)); \ 196 a += sizeof(x); \ 197} 198 199#define MOD_STR(t, a, s, c) { \ 200 COPY32(t, a, c); \ 201 COPY32(strlen(s) + 1, a, c) \ 202 if (c) \ 203 archsw.arch_copyin(s, a, strlen(s) + 1);\ 204 a += roundup(strlen(s) + 1, sizeof(u_long));\ 205} 206 207#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) 208#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) 209#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) 210 211#define MOD_VAR(t, a, s, c) { \ 212 COPY32(t, a, c); \ 213 COPY32(sizeof(s), a, c); \ 214 if (c) \ 215 archsw.arch_copyin(&s, a, sizeof(s)); \ 216 a += roundup(sizeof(s), sizeof(u_long)); \ 217} 218 219#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) 220#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) 221 222#define MOD_METADATA(a, mm, c) { \ 223 COPY32(MODINFO_METADATA | mm->md_type, a, c);\ 224 COPY32(mm->md_size, a, c); \ 225 if (c) \ 226 archsw.arch_copyin(mm->md_data, a, mm->md_size);\ 227 a += roundup(mm->md_size, sizeof(u_long)); \ 228} 229 230#define MOD_END(a, c) { \ 231 COPY32(MODINFO_END, a, c); \ 232 COPY32(0, a, c); \ 233} 234 235vm_offset_t 236md_copymodules(vm_offset_t addr) 237{ 238 struct preloaded_file *fp; 239 struct file_metadata *md; 240 int c; 241 242 c = addr != 0; 243 /* start with the first module on the list, should be the kernel */ 244 for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 245 246 MOD_NAME(addr, fp->f_name, c); /* this field must come first */ 247 MOD_TYPE(addr, fp->f_type, c); 248 if (fp->f_args) 249 MOD_ARGS(addr, fp->f_args, c); 250 MOD_ADDR(addr, fp->f_addr, c); 251 MOD_SIZE(addr, fp->f_size, c); 252 for (md = fp->f_metadata; md != NULL; md = md->md_next) { 253 if (!(md->md_type & MODINFOMD_NOCOPY)) { 254 MOD_METADATA(addr, md, c); 255 } 256 } 257 } 258 MOD_END(addr, c); 259 return(addr); 260} 261 262/* 263 * Load the information expected by a sparc64 kernel. 264 * 265 * - The 'boothowto' argument is constructed 266 * - The 'bootdev' argument is constructed 267 * - The kernel environment is copied into kernel space. 268 * - Module metadata are formatted and placed in kernel space. 269 */ 270int 271md_load(char *args, vm_offset_t *modulep) 272{ 273 struct preloaded_file *kfp; 274 struct preloaded_file *xp; 275 struct file_metadata *md; 276 vm_offset_t kernend; 277 vm_offset_t addr; 278 vm_offset_t envp; 279 vm_offset_t size; 280 char *rootdevname; 281 int howto; 282 283 howto = md_getboothowto(args); 284 285 /* 286 * Allow the environment variable 'rootdev' to override the supplied device 287 * This should perhaps go to MI code and/or have $rootdev tested/set by 288 * MI code before launching the kernel. 289 */ 290 if ((rootdevname = getenv("rootdev")) == NULL) 291 rootdevname = getenv("currdev"); 292 getrootmount(rootdevname); 293 294 /* find the last module in the chain */ 295 addr = 0; 296 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 297 if (addr < (xp->f_addr + xp->f_size)) 298 addr = xp->f_addr + xp->f_size; 299 } 300 /* pad to a page boundary */ 301 addr = roundup(addr, PAGE_SIZE); 302 303 /* copy our environment */ 304 envp = addr; 305 addr = md_copyenv(addr); 306 307 /* pad to a page boundary */ 308 addr = roundup(addr, PAGE_SIZE); 309 310 kernend = 0; 311 kfp = file_findfile(NULL, "elf64 kernel"); 312 if (kfp == NULL) 313 kfp = file_findfile(NULL, "elf kernel"); 314 if (kfp == NULL) 315 panic("can't find kernel file"); 316 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 317 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 318 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 319 file_addmetadata(kfp, MODINFOMD_DTLB_SLOTS, sizeof dtlb_slot, &dtlb_slot); 320 file_addmetadata(kfp, MODINFOMD_ITLB_SLOTS, sizeof itlb_slot, &itlb_slot); 321 file_addmetadata(kfp, MODINFOMD_DTLB, 322 dtlb_slot * sizeof(*dtlb_store), dtlb_store); 323 file_addmetadata(kfp, MODINFOMD_ITLB, 324 itlb_slot * sizeof(*itlb_store), itlb_store); 325 326 *modulep = addr; 327 size = md_copymodules(0); 328 kernend = roundup(addr + size, PAGE_SIZE); 329 330 md = file_findmetadata(kfp, MODINFOMD_KERNEND); 331 bcopy(&kernend, md->md_data, sizeof kernend); 332 333 (void)md_copymodules(addr); 334 335 return(0); 336} 337