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