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/sparc64/loader/metadata.c,v 1.6 27 */ 28 29 #include <sys/cdefs.h> 30 #include <stand.h> 31 #include <sys/param.h> 32 #include <sys/linker.h> 33 #include <sys/boot.h> 34 #include <sys/reboot.h> 35 #if defined(LOADER_FDT_SUPPORT) 36 #include <fdt_platform.h> 37 #endif 38 39 #ifdef __arm__ 40 #include <machine/elf.h> 41 #endif 42 #include <machine/metadata.h> 43 44 #include "bootstrap.h" 45 #include "modinfo.h" 46 47 #ifdef LOADER_GELI_SUPPORT 48 #include "geliboot.h" 49 #endif 50 51 static int 52 md_getboothowto(char *kargs) 53 { 54 int howto; 55 56 /* Parse kargs */ 57 howto = boot_parse_cmdline(kargs); 58 howto |= boot_env_to_howto(); 59 if (!strcmp(getenv("console"), "comconsole")) 60 howto |= RB_SERIAL; 61 if (!strcmp(getenv("console"), "nullconsole")) 62 howto |= RB_MUTE; 63 return(howto); 64 } 65 66 /* 67 * Load the information expected by a kernel. 68 * 69 * - The 'boothowto' argument is constructed 70 * - The 'bootdev' argument is constructed 71 * - The kernel environment is copied into kernel space. 72 * - Module metadata are formatted and placed in kernel space. 73 */ 74 static int 75 md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) 76 { 77 struct preloaded_file *kfp; 78 struct preloaded_file *xp; 79 struct file_metadata *md; 80 vm_offset_t kernend; 81 vm_offset_t addr; 82 vm_offset_t envp; 83 #if defined(LOADER_FDT_SUPPORT) 84 vm_offset_t fdtp; 85 #endif 86 vm_offset_t size; 87 uint64_t scratch64; 88 char *rootdevname; 89 int howto; 90 #ifdef __arm__ 91 vm_offset_t vaddr; 92 int i; 93 94 /* 95 * These metadata addreses must be converted for kernel after 96 * relocation. 97 */ 98 uint32_t mdt[] = { 99 MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, 100 MODINFOMD_ENVP, 101 #if defined(LOADER_FDT_SUPPORT) 102 MODINFOMD_DTBP 103 #endif 104 }; 105 #endif 106 107 howto = md_getboothowto(args); 108 109 /* 110 * Allow the environment variable 'rootdev' to override the supplied 111 * device. This should perhaps go to MI code and/or have $rootdev 112 * tested/set by MI code before launching the kernel. 113 */ 114 rootdevname = getenv("rootdev"); 115 if (rootdevname == NULL) 116 rootdevname = getenv("currdev"); 117 /* Try reading the /etc/fstab file to select the root device */ 118 getrootmount(rootdevname); 119 120 /* Find the last module in the chain */ 121 addr = 0; 122 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 123 if (addr < (xp->f_addr + xp->f_size)) 124 addr = xp->f_addr + xp->f_size; 125 } 126 /* Pad to a page boundary */ 127 addr = roundup(addr, PAGE_SIZE); 128 129 /* Copy our environment */ 130 envp = addr; 131 addr = md_copyenv(addr); 132 133 /* Pad to a page boundary */ 134 addr = roundup(addr, PAGE_SIZE); 135 136 #if defined(LOADER_FDT_SUPPORT) 137 /* Copy out FDT */ 138 fdtp = 0; 139 #if defined(__powerpc__) 140 if (getenv("usefdt") != NULL) 141 #endif 142 { 143 size = fdt_copy(addr); 144 fdtp = addr; 145 addr = roundup(addr + size, PAGE_SIZE); 146 } 147 #endif 148 149 kernend = 0; 150 kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel"); 151 if (kfp == NULL) 152 kfp = file_findfile(NULL, "elf kernel"); 153 if (kfp == NULL) 154 panic("can't find kernel file"); 155 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 156 if (kern64) { 157 scratch64 = envp; 158 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64); 159 #if defined(LOADER_FDT_SUPPORT) 160 if (fdtp != 0) { 161 scratch64 = fdtp; 162 file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64); 163 } 164 #endif 165 scratch64 = kernend; 166 file_addmetadata(kfp, MODINFOMD_KERNEND, 167 sizeof scratch64, &scratch64); 168 } else { 169 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 170 #if defined(LOADER_FDT_SUPPORT) 171 if (fdtp != 0) 172 file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp); 173 #endif 174 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 175 } 176 #ifdef LOADER_GELI_SUPPORT 177 geli_export_key_metadata(kfp); 178 #endif 179 180 *modulep = addr; 181 size = md_copymodules(0, kern64); 182 kernend = roundup(addr + size, PAGE_SIZE); 183 184 md = file_findmetadata(kfp, MODINFOMD_KERNEND); 185 if (kern64) { 186 scratch64 = kernend; 187 bcopy(&scratch64, md->md_data, sizeof scratch64); 188 } else { 189 bcopy(&kernend, md->md_data, sizeof kernend); 190 } 191 192 #ifdef __arm__ 193 /* Convert addresses to the final VA */ 194 *modulep -= __elfN(relocation_offset); 195 196 /* Do relocation fixup on metadata of each module. */ 197 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 198 for (i = 0; i < nitems(mdt); i++) { 199 md = file_findmetadata(xp, mdt[i]); 200 if (md) { 201 bcopy(md->md_data, &vaddr, sizeof vaddr); 202 vaddr -= __elfN(relocation_offset); 203 bcopy(&vaddr, md->md_data, sizeof vaddr); 204 } 205 } 206 } 207 #endif 208 209 (void)md_copymodules(addr, kern64); 210 #if defined(LOADER_FDT_SUPPORT) 211 if (dtb != NULL) 212 *dtb = fdtp; 213 #endif 214 215 return(0); 216 } 217 218 int 219 md_load(char *args, vm_offset_t *modulep, vm_offset_t *dtb) 220 { 221 return (md_load_dual(args, modulep, dtb, 0)); 222 } 223 224 #if defined(__powerpc__) 225 int 226 md_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtb) 227 { 228 return (md_load_dual(args, modulep, dtb, 1)); 229 } 230 #endif 231