bootinfo.c revision 271132
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * Copyright (c) 2006 Marcel Moolenaar 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: stable/10/sys/boot/ia64/common/bootinfo.c 271132 2014-09-04 20:47:14Z emaste $"); 30 31#include <stand.h> 32#include <string.h> 33#include <sys/param.h> 34#include <sys/reboot.h> 35#include <sys/linker.h> 36#include <sys/boot.h> 37 38#include <efi.h> 39#include <efilib.h> 40 41#include "libia64.h" 42 43static const char howto_switches[] = "aCdrgDmphsv"; 44static int howto_masks[] = { 45 RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, 46 RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE 47}; 48 49int 50bi_getboothowto(char *kargs) 51{ 52 const char *sw; 53 char *opts; 54 int howto, i; 55 56 howto = 0; 57 58 /* Get the boot options from the environment first. */ 59 for (i = 0; howto_names[i].ev != NULL; i++) { 60 if (getenv(howto_names[i].ev) != NULL) 61 howto |= howto_names[i].mask; 62 } 63 64 /* Parse kargs */ 65 if (kargs == NULL) 66 return (howto); 67 68 opts = strchr(kargs, '-'); 69 while (opts != NULL) { 70 while (*(++opts) != '\0') { 71 sw = strchr(howto_switches, *opts); 72 if (sw == NULL) 73 break; 74 howto |= howto_masks[sw - howto_switches]; 75 } 76 opts = strchr(opts, '-'); 77 } 78 79 return (howto); 80} 81 82/* 83 * Copy the environment into the load area starting at (addr). 84 * Each variable is formatted as <name>=<value>, with a single nul 85 * separating each variable, and a double nul terminating the environment. 86 */ 87vm_offset_t 88bi_copyenv(vm_offset_t start) 89{ 90 struct env_var *ep; 91 vm_offset_t addr, last; 92 size_t len; 93 94 addr = last = start; 95 96 /* Traverse the environment. */ 97 for (ep = environ; ep != NULL; ep = ep->ev_next) { 98 len = strlen(ep->ev_name); 99 if (ia64_copyin(ep->ev_name, addr, len) != len) 100 break; 101 addr += len; 102 if (ia64_copyin("=", addr, 1) != 1) 103 break; 104 addr++; 105 if (ep->ev_value != NULL) { 106 len = strlen(ep->ev_value); 107 if (ia64_copyin(ep->ev_value, addr, len) != len) 108 break; 109 addr += len; 110 } 111 if (ia64_copyin("", addr, 1) != 1) 112 break; 113 last = ++addr; 114 } 115 116 if (ia64_copyin("", last++, 1) != 1) 117 last = start; 118 return(last); 119} 120 121/* 122 * Copy module-related data into the load area, where it can be 123 * used as a directory for loaded modules. 124 * 125 * Module data is presented in a self-describing format. Each datum 126 * is preceded by a 32-bit identifier and a 32-bit size field. 127 * 128 * Currently, the following data are saved: 129 * 130 * MOD_NAME (variable) module name (string) 131 * MOD_TYPE (variable) module type (string) 132 * MOD_ARGS (variable) module parameters (string) 133 * MOD_ADDR sizeof(vm_offset_t) module load address 134 * MOD_SIZE sizeof(size_t) module size 135 * MOD_METADATA (variable) type-specific metadata 136 */ 137#define COPY32(v, a) { \ 138 u_int32_t x = (v); \ 139 ia64_copyin(&x, a, sizeof(x)); \ 140 a += sizeof(x); \ 141} 142 143#define MOD_STR(t, a, s) { \ 144 COPY32(t, a); \ 145 COPY32(strlen(s) + 1, a); \ 146 ia64_copyin(s, a, strlen(s) + 1); \ 147 a += roundup(strlen(s) + 1, sizeof(u_int64_t));\ 148} 149 150#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s) 151#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s) 152#define MOD_ARGS(a, s) MOD_STR(MODINFO_ARGS, a, s) 153 154#define MOD_VAR(t, a, s) { \ 155 COPY32(t, a); \ 156 COPY32(sizeof(s), a); \ 157 ia64_copyin(&s, a, sizeof(s)); \ 158 a += roundup(sizeof(s), sizeof(u_int64_t)); \ 159} 160 161#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s) 162#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s) 163 164#define MOD_METADATA(a, mm) { \ 165 COPY32(MODINFO_METADATA | mm->md_type, a); \ 166 COPY32(mm->md_size, a); \ 167 ia64_copyin(mm->md_data, a, mm->md_size); \ 168 a += roundup(mm->md_size, sizeof(u_int64_t));\ 169} 170 171#define MOD_END(a) { \ 172 COPY32(MODINFO_END, a); \ 173 COPY32(0, a); \ 174} 175 176vm_offset_t 177bi_copymodules(vm_offset_t addr) 178{ 179 struct preloaded_file *fp; 180 struct file_metadata *md; 181 182 /* Start with the first module on the list, should be the kernel. */ 183 for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 184 /* The name field must come first. */ 185 MOD_NAME(addr, fp->f_name); 186 MOD_TYPE(addr, fp->f_type); 187 if (fp->f_args) 188 MOD_ARGS(addr, fp->f_args); 189 MOD_ADDR(addr, fp->f_addr); 190 MOD_SIZE(addr, fp->f_size); 191 for (md = fp->f_metadata; md != NULL; md = md->md_next) { 192 if (!(md->md_type & MODINFOMD_NOCOPY)) 193 MOD_METADATA(addr, md); 194 } 195 } 196 MOD_END(addr); 197 return(addr); 198} 199 200/* 201 * Load the information expected by the kernel. 202 * 203 * - The kernel environment is copied into kernel space. 204 * - Module metadata are formatted and placed in kernel space. 205 */ 206int 207ia64_bootinfo(struct preloaded_file *fp, struct bootinfo **res) 208{ 209 struct bootinfo bi; 210 struct preloaded_file *xp; 211 struct file_metadata *md; 212 struct devdesc *rootdev; 213 char *rootdevname; 214 vm_offset_t addr, ssym, esym; 215 int error; 216 217 *res = NULL; 218 bzero(&bi, sizeof(struct bootinfo)); 219 bi.bi_magic = BOOTINFO_MAGIC; 220 bi.bi_version = 1; 221 bi.bi_boothowto = bi_getboothowto(fp->f_args); 222 223 /* 224 * Allow the environment variable 'rootdev' to override the supplied 225 * device. This should perhaps go to MI code and/or have $rootdev 226 * tested/set by MI code before launching the kernel. 227 */ 228 rootdevname = getenv("rootdev"); 229 ia64_getdev((void**)&rootdev, rootdevname, NULL); 230 if (rootdev != NULL) { 231 /* Try reading /etc/fstab to select the root device. */ 232 getrootmount(ia64_fmtdev(rootdev)); 233 free(rootdev); 234 } 235 236 md = file_findmetadata(fp, MODINFOMD_SSYM); 237 ssym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; 238 md = file_findmetadata(fp, MODINFOMD_ESYM); 239 esym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; 240 if (ssym != 0 && esym != 0) { 241 bi.bi_symtab = ssym; 242 bi.bi_esymtab = esym; 243 } 244 245 /* Find the last module in the chain. */ 246 addr = 0; 247 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 248 if (addr < (xp->f_addr + xp->f_size)) 249 addr = xp->f_addr + xp->f_size; 250 } 251 252 addr = (addr + 15) & ~15; 253 254 /* Copy module list and metadata. */ 255 bi.bi_modulep = addr; 256 addr = bi_copymodules(addr); 257 if (addr <= bi.bi_modulep) { 258 addr = bi.bi_modulep; 259 bi.bi_modulep = 0; 260 } 261 262 addr = (addr + 15) & ~15; 263 264 /* Copy our environment. */ 265 bi.bi_envp = addr; 266 addr = bi_copyenv(addr); 267 if (addr <= bi.bi_envp) { 268 addr = bi.bi_envp; 269 bi.bi_envp = 0; 270 } 271 272 addr = (addr + 15) & ~15; 273 bi.bi_kernend = addr; 274 275 error = ia64_platform_bootinfo(&bi, res); 276 if (error) 277 return (error); 278 279 if (IS_LEGACY_KERNEL()) { 280 if (*res == NULL) 281 return (EDOOFUS); 282 283 bcopy(&bi, *res, sizeof(bi)); 284 return (0); 285 } 286 287 bi.bi_pbvm_pgtbl = (uintptr_t)ia64_pgtbl; 288 bi.bi_pbvm_pgtblsz = ia64_pgtblsz; 289 ia64_copyin((void *)bi.bi_memmap, addr, bi.bi_memmap_size); 290 bi.bi_memmap = addr; 291 addr = (addr + bi.bi_memmap_size + 15) & ~15; 292 bi.bi_kernend = addr + sizeof(bi); 293 ia64_copyin(&bi, addr, sizeof(bi)); 294 *res = (void *)addr; 295 return (0); 296} 297