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 58 curp = preload_metadata; 59 for (;;) { 60 hdr = (uint32_t *)curp; 61 if (hdr[0] == 0 && hdr[1] == 0) 62 break; 63 64 /* Search for a MODINFO_NAME field */ 65 if ((hdr[0] == MODINFO_NAME) && 66 !strcmp(name, curp + sizeof(uint32_t) * 2)) 67 return(curp); 68 69 /* skip to next field */ 70 next = sizeof(uint32_t) * 2 + hdr[1]; 71 next = roundup(next, sizeof(u_long)); 72 curp += next; 73 } 74 } 75 return(NULL); 76 } 77 78 /* 79 * Search for the first preloaded module of (type) 80 */ 81 caddr_t 82 preload_search_by_type(const char *type) 83 { 84 caddr_t curp, lname; 85 uint32_t *hdr; 86 int next; 87 88 if (preload_metadata != NULL) { 89 90 curp = preload_metadata; 91 lname = NULL; 92 for (;;) { 93 hdr = (uint32_t *)curp; 94 if (hdr[0] == 0 && hdr[1] == 0) 95 break; 96 97 /* remember the start of each record */ 98 if (hdr[0] == MODINFO_NAME) 99 lname = curp; 100 101 /* Search for a MODINFO_TYPE field */ 102 if ((hdr[0] == MODINFO_TYPE) && 103 !strcmp(type, curp + sizeof(uint32_t) * 2)) 104 return(lname); 105 106 /* skip to next field */ 107 next = sizeof(uint32_t) * 2 + hdr[1]; 108 next = roundup(next, sizeof(u_long)); 109 curp += next; 110 } 111 } 112 return(NULL); 113 } 114 115 /* 116 * Walk through the preloaded module list 117 */ 118 caddr_t 119 preload_search_next_name(caddr_t base) 120 { 121 caddr_t curp; 122 uint32_t *hdr; 123 int next; 124 125 if (preload_metadata != NULL) { 126 127 /* Pick up where we left off last time */ 128 if (base) { 129 /* skip to next field */ 130 curp = base; 131 hdr = (uint32_t *)curp; 132 next = sizeof(uint32_t) * 2 + hdr[1]; 133 next = roundup(next, sizeof(u_long)); 134 curp += next; 135 } else 136 curp = preload_metadata; 137 138 for (;;) { 139 hdr = (uint32_t *)curp; 140 if (hdr[0] == 0 && hdr[1] == 0) 141 break; 142 143 /* Found a new record? */ 144 if (hdr[0] == MODINFO_NAME) 145 return curp; 146 147 /* skip to next field */ 148 next = sizeof(uint32_t) * 2 + hdr[1]; 149 next = roundup(next, sizeof(u_long)); 150 curp += next; 151 } 152 } 153 return(NULL); 154 } 155 156 /* 157 * Given a preloaded module handle (mod), return a pointer 158 * to the data for the attribute (inf). 159 */ 160 caddr_t 161 preload_search_info(caddr_t mod, int inf) 162 { 163 caddr_t curp; 164 uint32_t *hdr; 165 uint32_t type = 0; 166 int next; 167 168 if (mod == NULL) 169 return (NULL); 170 171 curp = mod; 172 for (;;) { 173 hdr = (uint32_t *)curp; 174 /* end of module data? */ 175 if (hdr[0] == 0 && hdr[1] == 0) 176 break; 177 /* 178 * We give up once we've looped back to what we were looking at 179 * first - this should normally be a MODINFO_NAME field. 180 */ 181 if (type == 0) { 182 type = hdr[0]; 183 } else { 184 if (hdr[0] == type) 185 break; 186 } 187 188 /* 189 * Attribute match? Return pointer to data. 190 * Consumer may safely assume that size value precedes 191 * data. 192 */ 193 if (hdr[0] == inf) 194 return(curp + (sizeof(uint32_t) * 2)); 195 196 /* skip to next field */ 197 next = sizeof(uint32_t) * 2 + hdr[1]; 198 next = roundup(next, sizeof(u_long)); 199 curp += next; 200 } 201 return(NULL); 202 } 203 204 /* 205 * Delete a preload record by name. 206 */ 207 void 208 preload_delete_name(const char *name) 209 { 210 caddr_t addr, curp; 211 uint32_t *hdr, sz; 212 int next; 213 int clearing; 214 215 addr = 0; 216 sz = 0; 217 218 if (preload_metadata != NULL) { 219 220 clearing = 0; 221 curp = preload_metadata; 222 for (;;) { 223 hdr = (uint32_t *)curp; 224 if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) { 225 /* Free memory used to store the file. */ 226 if (addr != 0 && sz != 0) 227 kmem_bootstrap_free((vm_offset_t)addr, sz); 228 addr = 0; 229 sz = 0; 230 231 if (hdr[0] == 0) 232 break; 233 if (!strcmp(name, curp + sizeof(uint32_t) * 2)) 234 clearing = 1; /* got it, start clearing */ 235 else if (clearing) { 236 clearing = 0; /* at next one now.. better stop */ 237 } 238 } 239 if (clearing) { 240 if (hdr[0] == MODINFO_ADDR) 241 addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2); 242 else if (hdr[0] == MODINFO_SIZE) 243 sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2); 244 hdr[0] = MODINFO_EMPTY; 245 } 246 247 /* skip to next field */ 248 next = sizeof(uint32_t) * 2 + hdr[1]; 249 next = roundup(next, sizeof(u_long)); 250 curp += next; 251 } 252 } 253 } 254 255 void * 256 preload_fetch_addr(caddr_t mod) 257 { 258 caddr_t *mdp; 259 260 mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR); 261 if (mdp == NULL) 262 return (NULL); 263 return (*mdp + preload_addr_relocate); 264 } 265 266 size_t 267 preload_fetch_size(caddr_t mod) 268 { 269 size_t *mdp; 270 271 mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE); 272 if (mdp == NULL) 273 return (0); 274 return (*mdp); 275 } 276 277 /* Called from locore. Convert physical pointers to kvm. Sigh. */ 278 void 279 preload_bootstrap_relocate(vm_offset_t offset) 280 { 281 caddr_t curp; 282 uint32_t *hdr; 283 vm_offset_t *ptr; 284 int next; 285 286 if (preload_metadata != NULL) { 287 288 curp = preload_metadata; 289 for (;;) { 290 hdr = (uint32_t *)curp; 291 if (hdr[0] == 0 && hdr[1] == 0) 292 break; 293 294 /* Deal with the ones that we know we have to fix */ 295 switch (hdr[0]) { 296 case MODINFO_ADDR: 297 case MODINFO_METADATA|MODINFOMD_SSYM: 298 case MODINFO_METADATA|MODINFOMD_ESYM: 299 ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); 300 *ptr += offset; 301 break; 302 } 303 /* The rest is beyond us for now */ 304 305 /* skip to next field */ 306 next = sizeof(uint32_t) * 2 + hdr[1]; 307 next = roundup(next, sizeof(u_long)); 308 curp += next; 309 } 310 } 311 } 312