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