1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1998 Michael Smith 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/linker.h> 35 36 #include <vm/vm.h> 37 #include <vm/vm_extern.h> 38 39 /* 40 * Preloaded module support 41 */ 42 43 vm_offset_t preload_addr_relocate = 0; 44 caddr_t preload_metadata; 45 46 /* 47 * Search for the preloaded module (name) 48 */ 49 caddr_t 50 preload_search_by_name(const char *name) 51 { 52 caddr_t curp; 53 uint32_t *hdr; 54 int next; 55 56 if (preload_metadata != NULL) { 57 curp = preload_metadata; 58 for (;;) { 59 hdr = (uint32_t *)curp; 60 if (hdr[0] == 0 && hdr[1] == 0) 61 break; 62 63 /* Search for a MODINFO_NAME field */ 64 if ((hdr[0] == MODINFO_NAME) && 65 !strcmp(name, curp + sizeof(uint32_t) * 2)) 66 return(curp); 67 68 /* skip to next field */ 69 next = sizeof(uint32_t) * 2 + hdr[1]; 70 next = roundup(next, sizeof(u_long)); 71 curp += next; 72 } 73 } 74 return(NULL); 75 } 76 77 /* 78 * Search for the first preloaded module of (type) 79 */ 80 caddr_t 81 preload_search_by_type(const char *type) 82 { 83 caddr_t curp, lname; 84 uint32_t *hdr; 85 int next; 86 87 if (preload_metadata != NULL) { 88 curp = preload_metadata; 89 lname = NULL; 90 for (;;) { 91 hdr = (uint32_t *)curp; 92 if (hdr[0] == 0 && hdr[1] == 0) 93 break; 94 95 /* remember the start of each record */ 96 if (hdr[0] == MODINFO_NAME) 97 lname = curp; 98 99 /* Search for a MODINFO_TYPE field */ 100 if ((hdr[0] == MODINFO_TYPE) && 101 !strcmp(type, curp + sizeof(uint32_t) * 2)) 102 return(lname); 103 104 /* skip to next field */ 105 next = sizeof(uint32_t) * 2 + hdr[1]; 106 next = roundup(next, sizeof(u_long)); 107 curp += next; 108 } 109 } 110 return(NULL); 111 } 112 113 /* 114 * Walk through the preloaded module list 115 */ 116 caddr_t 117 preload_search_next_name(caddr_t base) 118 { 119 caddr_t curp; 120 uint32_t *hdr; 121 int next; 122 123 if (preload_metadata != NULL) { 124 /* Pick up where we left off last time */ 125 if (base) { 126 /* skip to next field */ 127 curp = base; 128 hdr = (uint32_t *)curp; 129 next = sizeof(uint32_t) * 2 + hdr[1]; 130 next = roundup(next, sizeof(u_long)); 131 curp += next; 132 } else 133 curp = preload_metadata; 134 135 for (;;) { 136 hdr = (uint32_t *)curp; 137 if (hdr[0] == 0 && hdr[1] == 0) 138 break; 139 140 /* Found a new record? */ 141 if (hdr[0] == MODINFO_NAME) 142 return curp; 143 144 /* skip to next field */ 145 next = sizeof(uint32_t) * 2 + hdr[1]; 146 next = roundup(next, sizeof(u_long)); 147 curp += next; 148 } 149 } 150 return(NULL); 151 } 152 153 /* 154 * Given a preloaded module handle (mod), return a pointer 155 * to the data for the attribute (inf). 156 */ 157 caddr_t 158 preload_search_info(caddr_t mod, int inf) 159 { 160 caddr_t curp; 161 uint32_t *hdr; 162 uint32_t type = 0; 163 int next; 164 165 if (mod == NULL) 166 return (NULL); 167 168 curp = mod; 169 for (;;) { 170 hdr = (uint32_t *)curp; 171 /* end of module data? */ 172 if (hdr[0] == 0 && hdr[1] == 0) 173 break; 174 /* 175 * We give up once we've looped back to what we were looking at 176 * first - this should normally be a MODINFO_NAME field. 177 */ 178 if (type == 0) { 179 type = hdr[0]; 180 } else { 181 if (hdr[0] == type) 182 break; 183 } 184 185 /* 186 * Attribute match? Return pointer to data. 187 * Consumer may safely assume that size value precedes 188 * data. 189 */ 190 if (hdr[0] == inf) 191 return(curp + (sizeof(uint32_t) * 2)); 192 193 /* skip to next field */ 194 next = sizeof(uint32_t) * 2 + hdr[1]; 195 next = roundup(next, sizeof(u_long)); 196 curp += next; 197 } 198 return(NULL); 199 } 200 201 /* 202 * Delete a preload record by name. 203 */ 204 void 205 preload_delete_name(const char *name) 206 { 207 caddr_t addr, curp; 208 uint32_t *hdr, sz; 209 int next; 210 int clearing; 211 212 addr = 0; 213 sz = 0; 214 215 if (preload_metadata != NULL) { 216 clearing = 0; 217 curp = preload_metadata; 218 for (;;) { 219 hdr = (uint32_t *)curp; 220 if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) { 221 /* Free memory used to store the file. */ 222 if (addr != 0 && sz != 0) 223 kmem_bootstrap_free((vm_offset_t)addr, sz); 224 addr = 0; 225 sz = 0; 226 227 if (hdr[0] == 0) 228 break; 229 if (!strcmp(name, curp + sizeof(uint32_t) * 2)) 230 clearing = 1; /* got it, start clearing */ 231 else if (clearing) { 232 clearing = 0; /* at next one now.. better stop */ 233 } 234 } 235 if (clearing) { 236 if (hdr[0] == MODINFO_ADDR) 237 addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2); 238 else if (hdr[0] == MODINFO_SIZE) 239 sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2); 240 hdr[0] = MODINFO_EMPTY; 241 } 242 243 /* skip to next field */ 244 next = sizeof(uint32_t) * 2 + hdr[1]; 245 next = roundup(next, sizeof(u_long)); 246 curp += next; 247 } 248 } 249 } 250 251 void * 252 preload_fetch_addr(caddr_t mod) 253 { 254 caddr_t *mdp; 255 256 mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR); 257 if (mdp == NULL) 258 return (NULL); 259 return (*mdp + preload_addr_relocate); 260 } 261 262 size_t 263 preload_fetch_size(caddr_t mod) 264 { 265 size_t *mdp; 266 267 mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE); 268 if (mdp == NULL) 269 return (0); 270 return (*mdp); 271 } 272 273 /* Called from locore. Convert physical pointers to kvm. Sigh. */ 274 void 275 preload_bootstrap_relocate(vm_offset_t offset) 276 { 277 caddr_t curp; 278 uint32_t *hdr; 279 vm_offset_t *ptr; 280 int next; 281 282 if (preload_metadata != NULL) { 283 curp = preload_metadata; 284 for (;;) { 285 hdr = (uint32_t *)curp; 286 if (hdr[0] == 0 && hdr[1] == 0) 287 break; 288 289 /* Deal with the ones that we know we have to fix */ 290 switch (hdr[0]) { 291 case MODINFO_ADDR: 292 case MODINFO_METADATA|MODINFOMD_SSYM: 293 case MODINFO_METADATA|MODINFOMD_ESYM: 294 ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); 295 *ptr += offset; 296 break; 297 } 298 /* The rest is beyond us for now */ 299 300 /* skip to next field */ 301 next = sizeof(uint32_t) * 2 + hdr[1]; 302 next = roundup(next, sizeof(u_long)); 303 curp += next; 304 } 305 } 306 } 307