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 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <stand.h> 31 #include <sys/param.h> 32 #include <sys/reboot.h> 33 #include <sys/linker.h> 34 #include <machine/bootinfo.h> 35 #include <machine/metadata.h> 36 #include "bootstrap.h" 37 #include "libi386.h" 38 #include "btxv86.h" 39 40 #ifdef LOADER_GELI_SUPPORT 41 #include "geliboot.h" 42 43 static const size_t keybuf_size = sizeof(struct keybuf) + 44 (GELI_MAX_KEYS * sizeof(struct keybuf_ent)); 45 #endif 46 47 static struct bootinfo bi; 48 49 /* 50 * Copy module-related data into the load area, where it can be 51 * used as a directory for loaded modules. 52 * 53 * Module data is presented in a self-describing format. Each datum 54 * is preceded by a 32-bit identifier and a 32-bit size field. 55 * 56 * Currently, the following data are saved: 57 * 58 * MOD_NAME (variable) module name (string) 59 * MOD_TYPE (variable) module type (string) 60 * MOD_ARGS (variable) module parameters (string) 61 * MOD_ADDR sizeof(vm_offset_t) module load address 62 * MOD_SIZE sizeof(size_t) module size 63 * MOD_METADATA (variable) type-specific metadata 64 */ 65 #define COPY32(v, a, c) { \ 66 uint32_t x = (v); \ 67 if (c) \ 68 i386_copyin(&x, a, sizeof(x)); \ 69 a += sizeof(x); \ 70 } 71 72 #define MOD_STR(t, a, s, c) { \ 73 COPY32(t, a, c); \ 74 COPY32(strlen(s) + 1, a, c); \ 75 if (c) \ 76 i386_copyin(s, a, strlen(s) + 1); \ 77 a += roundup(strlen(s) + 1, sizeof(u_long));\ 78 } 79 80 #define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) 81 #define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) 82 #define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) 83 84 #define MOD_VAR(t, a, s, c) { \ 85 COPY32(t, a, c); \ 86 COPY32(sizeof(s), a, c); \ 87 if (c) \ 88 i386_copyin(&s, a, sizeof(s)); \ 89 a += roundup(sizeof(s), sizeof(u_long)); \ 90 } 91 92 #define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) 93 #define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) 94 95 #define MOD_METADATA(a, mm, c) { \ 96 COPY32(MODINFO_METADATA | mm->md_type, a, c); \ 97 COPY32(mm->md_size, a, c); \ 98 if (c) \ 99 i386_copyin(mm->md_data, a, mm->md_size); \ 100 a += roundup(mm->md_size, sizeof(u_long));\ 101 } 102 103 #define MOD_END(a, c) { \ 104 COPY32(MODINFO_END, a, c); \ 105 COPY32(0, a, c); \ 106 } 107 108 static vm_offset_t 109 bi_copymodules32(vm_offset_t addr) 110 { 111 struct preloaded_file *fp; 112 struct file_metadata *md; 113 int c; 114 115 c = addr != 0; 116 /* start with the first module on the list, should be the kernel */ 117 for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 118 119 MOD_NAME(addr, fp->f_name, c); /* this field must come first */ 120 MOD_TYPE(addr, fp->f_type, c); 121 if (fp->f_args) 122 MOD_ARGS(addr, fp->f_args, c); 123 MOD_ADDR(addr, fp->f_addr, c); 124 MOD_SIZE(addr, fp->f_size, c); 125 for (md = fp->f_metadata; md != NULL; md = md->md_next) 126 if (!(md->md_type & MODINFOMD_NOCOPY)) 127 MOD_METADATA(addr, md, c); 128 } 129 MOD_END(addr, c); 130 return(addr); 131 } 132 133 /* 134 * Load the information expected by an i386 kernel. 135 * 136 * - The 'boothowto' argument is constructed 137 * - The 'bootdev' argument is constructed 138 * - The 'bootinfo' struct is constructed, and copied into the kernel space. 139 * - The kernel environment is copied into kernel space. 140 * - Module metadata are formatted and placed in kernel space. 141 */ 142 int 143 bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp) 144 { 145 struct preloaded_file *xp, *kfp; 146 struct i386_devdesc *rootdev; 147 struct file_metadata *md; 148 vm_offset_t addr; 149 vm_offset_t kernend; 150 vm_offset_t envp; 151 vm_offset_t size; 152 vm_offset_t ssym, esym; 153 char *rootdevname; 154 int bootdevnr, i, howto; 155 char *kernelname; 156 const char *kernelpath; 157 #ifdef LOADER_GELI_SUPPORT 158 char buf[keybuf_size]; 159 struct keybuf *keybuf = (struct keybuf *)buf; 160 #endif 161 162 howto = bi_getboothowto(args); 163 164 /* 165 * Allow the environment variable 'rootdev' to override the supplied device 166 * This should perhaps go to MI code and/or have $rootdev tested/set by 167 * MI code before launching the kernel. 168 */ 169 rootdevname = getenv("rootdev"); 170 i386_getdev((void **)(&rootdev), rootdevname, NULL); 171 if (rootdev == NULL) { /* bad $rootdev/$currdev */ 172 printf("can't determine root device\n"); 173 return(EINVAL); 174 } 175 176 /* Try reading the /etc/fstab file to select the root device */ 177 getrootmount(i386_fmtdev((void *)rootdev)); 178 179 /* Do legacy rootdev guessing */ 180 181 /* XXX - use a default bootdev of 0. Is this ok??? */ 182 bootdevnr = 0; 183 184 switch(rootdev->dd.d_dev->dv_type) { 185 case DEVT_CD: 186 /* Pass in BIOS device number. */ 187 bi.bi_bios_dev = bc_unit2bios(rootdev->dd.d_unit); 188 bootdevnr = bc_getdev(rootdev); 189 break; 190 191 case DEVT_DISK: 192 /* pass in the BIOS device number of the current disk */ 193 bi.bi_bios_dev = bd_unit2bios(rootdev->dd.d_unit); 194 bootdevnr = bd_getdev(rootdev); 195 break; 196 197 case DEVT_NET: 198 case DEVT_ZFS: 199 break; 200 201 default: 202 printf("WARNING - don't know how to boot from device type %d\n", 203 rootdev->dd.d_dev->dv_type); 204 } 205 if (bootdevnr == -1) { 206 printf("root device %s invalid\n", i386_fmtdev(rootdev)); 207 return (EINVAL); 208 } 209 free(rootdev); 210 211 /* find the last module in the chain */ 212 addr = 0; 213 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 214 if (addr < (xp->f_addr + xp->f_size)) 215 addr = xp->f_addr + xp->f_size; 216 } 217 /* pad to a page boundary */ 218 addr = roundup(addr, PAGE_SIZE); 219 220 /* copy our environment */ 221 envp = addr; 222 addr = bi_copyenv(addr); 223 224 /* pad to a page boundary */ 225 addr = roundup(addr, PAGE_SIZE); 226 227 kfp = file_findfile(NULL, "elf kernel"); 228 if (kfp == NULL) 229 kfp = file_findfile(NULL, "elf32 kernel"); 230 if (kfp == NULL) 231 panic("can't find kernel file"); 232 kernend = 0; /* fill it in later */ 233 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 234 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 235 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 236 bios_addsmapdata(kfp); 237 #ifdef LOADER_GELI_SUPPORT 238 geli_fill_keybuf(keybuf); 239 file_addmetadata(kfp, MODINFOMD_KEYBUF, keybuf_size, buf); 240 bzero(buf, sizeof(buf)); 241 #endif 242 243 /* Figure out the size and location of the metadata */ 244 *modulep = addr; 245 size = bi_copymodules32(0); 246 kernend = roundup(addr + size, PAGE_SIZE); 247 *kernendp = kernend; 248 249 /* patch MODINFOMD_KERNEND */ 250 md = file_findmetadata(kfp, MODINFOMD_KERNEND); 251 bcopy(&kernend, md->md_data, sizeof kernend); 252 253 /* copy module list and metadata */ 254 (void)bi_copymodules32(addr); 255 256 ssym = esym = 0; 257 md = file_findmetadata(kfp, MODINFOMD_SSYM); 258 if (md != NULL) 259 ssym = *((vm_offset_t *)&(md->md_data)); 260 md = file_findmetadata(kfp, MODINFOMD_ESYM); 261 if (md != NULL) 262 esym = *((vm_offset_t *)&(md->md_data)); 263 if (ssym == 0 || esym == 0) 264 ssym = esym = 0; /* sanity */ 265 266 /* legacy bootinfo structure */ 267 kernelname = getenv("kernelname"); 268 i386_getdev(NULL, kernelname, &kernelpath); 269 bi.bi_version = BOOTINFO_VERSION; 270 bi.bi_kernelname = 0; /* XXX char * -> kernel name */ 271 bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */ 272 bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */ 273 for (i = 0; i < N_BIOS_GEOM; i++) 274 bi.bi_bios_geom[i] = bd_getbigeom(i); 275 bi.bi_size = sizeof(bi); 276 bi.bi_memsizes_valid = 1; 277 bi.bi_basemem = bios_basemem / 1024; 278 bi.bi_extmem = bios_extmem / 1024; 279 bi.bi_envp = envp; 280 bi.bi_modulep = *modulep; 281 bi.bi_kernend = kernend; 282 bi.bi_kernelname = VTOP(kernelpath); 283 bi.bi_symtab = ssym; /* XXX this is only the primary kernel symtab */ 284 bi.bi_esymtab = esym; 285 286 /* legacy boot arguments */ 287 *howtop = howto | RB_BOOTINFO; 288 *bootdevp = bootdevnr; 289 *bip = VTOP(&bi); 290 291 return(0); 292 } 293