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/cpufunc.h> 36 #include <machine/metadata.h> 37 #include <machine/psl.h> 38 #include <machine/specialreg.h> 39 #include "bootstrap.h" 40 #include "libi386.h" 41 #include "btxv86.h" 42 43 #ifdef LOADER_GELI_SUPPORT 44 #include "geliboot.h" 45 46 static const size_t keybuf_size = sizeof(struct keybuf) + 47 (GELI_MAX_KEYS * sizeof(struct keybuf_ent)); 48 #endif 49 50 /* 51 * Copy module-related data into the load area, where it can be 52 * used as a directory for loaded modules. 53 * 54 * Module data is presented in a self-describing format. Each datum 55 * is preceded by a 32-bit identifier and a 32-bit size field. 56 * 57 * Currently, the following data are saved: 58 * 59 * MOD_NAME (variable) module name (string) 60 * MOD_TYPE (variable) module type (string) 61 * MOD_ARGS (variable) module parameters (string) 62 * MOD_ADDR sizeof(vm_offset_t) module load address 63 * MOD_SIZE sizeof(size_t) module size 64 * MOD_METADATA (variable) type-specific metadata 65 */ 66 #define COPY32(v, a, c) { \ 67 uint32_t x = (v); \ 68 if (c) \ 69 i386_copyin(&x, a, sizeof(x)); \ 70 a += sizeof(x); \ 71 } 72 73 #define MOD_STR(t, a, s, c) { \ 74 COPY32(t, a, c); \ 75 COPY32(strlen(s) + 1, a, c); \ 76 if (c) \ 77 i386_copyin(s, a, strlen(s) + 1); \ 78 a += roundup(strlen(s) + 1, sizeof(uint64_t));\ 79 } 80 81 #define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) 82 #define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) 83 #define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) 84 85 #define MOD_VAR(t, a, s, c) { \ 86 COPY32(t, a, c); \ 87 COPY32(sizeof(s), a, c); \ 88 if (c) \ 89 i386_copyin(&s, a, sizeof(s)); \ 90 a += roundup(sizeof(s), sizeof(uint64_t)); \ 91 } 92 93 #define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) 94 #define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) 95 96 #define MOD_METADATA(a, mm, c) { \ 97 COPY32(MODINFO_METADATA | mm->md_type, a, c); \ 98 COPY32(mm->md_size, a, c); \ 99 if (c) \ 100 i386_copyin(mm->md_data, a, mm->md_size); \ 101 a += roundup(mm->md_size, sizeof(uint64_t));\ 102 } 103 104 #define MOD_END(a, c) { \ 105 COPY32(MODINFO_END, a, c); \ 106 COPY32(0, a, c); \ 107 } 108 109 static vm_offset_t 110 bi_copymodules64(vm_offset_t addr) 111 { 112 struct preloaded_file *fp; 113 struct file_metadata *md; 114 int c; 115 uint64_t v; 116 117 c = addr != 0; 118 /* start with the first module on the list, should be the kernel */ 119 for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 120 121 MOD_NAME(addr, fp->f_name, c); /* this field must come first */ 122 MOD_TYPE(addr, fp->f_type, c); 123 if (fp->f_args) 124 MOD_ARGS(addr, fp->f_args, c); 125 v = fp->f_addr; 126 MOD_ADDR(addr, v, c); 127 v = fp->f_size; 128 MOD_SIZE(addr, v, c); 129 for (md = fp->f_metadata; md != NULL; md = md->md_next) 130 if (!(md->md_type & MODINFOMD_NOCOPY)) 131 MOD_METADATA(addr, md, c); 132 } 133 MOD_END(addr, c); 134 return(addr); 135 } 136 137 /* 138 * Check to see if this CPU supports long mode. 139 */ 140 static int 141 bi_checkcpu(void) 142 { 143 char *cpu_vendor; 144 int vendor[3]; 145 int eflags; 146 unsigned int regs[4]; 147 148 /* Check for presence of "cpuid". */ 149 eflags = read_eflags(); 150 write_eflags(eflags ^ PSL_ID); 151 if (!((eflags ^ read_eflags()) & PSL_ID)) 152 return (0); 153 154 /* Fetch the vendor string. */ 155 do_cpuid(0, regs); 156 vendor[0] = regs[1]; 157 vendor[1] = regs[3]; 158 vendor[2] = regs[2]; 159 cpu_vendor = (char *)vendor; 160 161 /* Check for vendors that support AMD features. */ 162 if (strncmp(cpu_vendor, INTEL_VENDOR_ID, 12) != 0 && 163 strncmp(cpu_vendor, AMD_VENDOR_ID, 12) != 0 && 164 strncmp(cpu_vendor, CENTAUR_VENDOR_ID, 12) != 0) 165 return (0); 166 167 /* Has to support AMD features. */ 168 do_cpuid(0x80000000, regs); 169 if (!(regs[0] >= 0x80000001)) 170 return (0); 171 172 /* Check for long mode. */ 173 do_cpuid(0x80000001, regs); 174 return (regs[3] & AMDID_LM); 175 } 176 177 /* 178 * Load the information expected by an amd64 kernel. 179 * 180 * - The 'boothowto' argument is constructed 181 * - The 'bootdev' argument is constructed 182 * - The 'bootinfo' struct is constructed, and copied into the kernel space. 183 * - The kernel environment is copied into kernel space. 184 * - Module metadata are formatted and placed in kernel space. 185 */ 186 int 187 bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, 188 vm_offset_t *kernendp, int add_smap) 189 { 190 struct preloaded_file *xp, *kfp; 191 struct i386_devdesc *rootdev; 192 struct file_metadata *md; 193 uint64_t kernend; 194 uint64_t envp; 195 uint64_t module; 196 vm_offset_t size; 197 char *rootdevname; 198 int howto; 199 #ifdef LOADER_GELI_SUPPORT 200 char buf[keybuf_size]; 201 struct keybuf *keybuf = (struct keybuf *)buf; 202 #endif 203 204 if (!bi_checkcpu()) { 205 printf("CPU doesn't support long mode\n"); 206 return (EINVAL); 207 } 208 209 howto = bi_getboothowto(args); 210 211 /* 212 * Allow the environment variable 'rootdev' to override the supplied device 213 * This should perhaps go to MI code and/or have $rootdev tested/set by 214 * MI code before launching the kernel. 215 */ 216 rootdevname = getenv("rootdev"); 217 i386_getdev((void **)(&rootdev), rootdevname, NULL); 218 if (rootdev == NULL) { /* bad $rootdev/$currdev */ 219 printf("can't determine root device\n"); 220 return(EINVAL); 221 } 222 223 /* Try reading the /etc/fstab file to select the root device */ 224 getrootmount(i386_fmtdev((void *)rootdev)); 225 226 if (addr == 0) { 227 /* find the last module in the chain */ 228 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 229 if (addr < (xp->f_addr + xp->f_size)) 230 addr = xp->f_addr + xp->f_size; 231 } 232 } 233 /* pad to a page boundary */ 234 addr = roundup(addr, PAGE_SIZE); 235 236 /* place the metadata before anything */ 237 module = *modulep = addr; 238 239 kfp = file_findfile(NULL, "elf kernel"); 240 if (kfp == NULL) 241 kfp = file_findfile(NULL, "elf64 kernel"); 242 if (kfp == NULL) 243 panic("can't find kernel file"); 244 kernend = 0; /* fill it in later */ 245 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 246 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 247 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 248 file_addmetadata(kfp, MODINFOMD_MODULEP, sizeof module, &module); 249 if (add_smap != 0) 250 bios_addsmapdata(kfp); 251 252 #ifdef LOADER_GELI_SUPPORT 253 geli_fill_keybuf(keybuf); 254 file_addmetadata(kfp, MODINFOMD_KEYBUF, keybuf_size, buf); 255 bzero(buf, sizeof(buf)); 256 #endif 257 258 size = bi_copymodules64(0); 259 260 /* copy our environment */ 261 envp = roundup(addr + size, PAGE_SIZE); 262 addr = bi_copyenv(envp); 263 264 /* set kernend */ 265 kernend = roundup(addr, PAGE_SIZE); 266 *kernendp = kernend; 267 268 /* patch MODINFOMD_KERNEND */ 269 md = file_findmetadata(kfp, MODINFOMD_KERNEND); 270 bcopy(&kernend, md->md_data, sizeof kernend); 271 272 /* patch MODINFOMD_ENVP */ 273 md = file_findmetadata(kfp, MODINFOMD_ENVP); 274 bcopy(&envp, md->md_data, sizeof envp); 275 276 /* copy module list and metadata */ 277 (void)bi_copymodules64(*modulep); 278 279 return(0); 280 } 281