1/*- 2 * Copyright (c) 1998 Michael Smith 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 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/11/sys/kern/subr_module.c 337262 2018-08-03 15:42:39Z markj $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/linker.h> 33 34#include <vm/vm.h> 35#include <vm/vm_extern.h> 36 37/* 38 * Preloaded module support 39 */ 40 41vm_offset_t preload_addr_relocate = 0; 42caddr_t preload_metadata; 43 44/* 45 * Search for the preloaded module (name) 46 */ 47caddr_t 48preload_search_by_name(const char *name) 49{ 50 caddr_t curp; 51 uint32_t *hdr; 52 int next; 53 54 if (preload_metadata != NULL) { 55 56 curp = preload_metadata; 57 for (;;) { 58 hdr = (uint32_t *)curp; 59 if (hdr[0] == 0 && hdr[1] == 0) 60 break; 61 62 /* Search for a MODINFO_NAME field */ 63 if ((hdr[0] == MODINFO_NAME) && 64 !strcmp(name, curp + sizeof(uint32_t) * 2)) 65 return(curp); 66 67 /* skip to next field */ 68 next = sizeof(uint32_t) * 2 + hdr[1]; 69 next = roundup(next, sizeof(u_long)); 70 curp += next; 71 } 72 } 73 return(NULL); 74} 75 76/* 77 * Search for the first preloaded module of (type) 78 */ 79caddr_t 80preload_search_by_type(const char *type) 81{ 82 caddr_t curp, lname; 83 uint32_t *hdr; 84 int next; 85 86 if (preload_metadata != NULL) { 87 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 */ 116caddr_t 117preload_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 125 /* Pick up where we left off last time */ 126 if (base) { 127 /* skip to next field */ 128 curp = base; 129 hdr = (uint32_t *)curp; 130 next = sizeof(uint32_t) * 2 + hdr[1]; 131 next = roundup(next, sizeof(u_long)); 132 curp += next; 133 } else 134 curp = preload_metadata; 135 136 for (;;) { 137 hdr = (uint32_t *)curp; 138 if (hdr[0] == 0 && hdr[1] == 0) 139 break; 140 141 /* Found a new record? */ 142 if (hdr[0] == MODINFO_NAME) 143 return curp; 144 145 /* skip to next field */ 146 next = sizeof(uint32_t) * 2 + hdr[1]; 147 next = roundup(next, sizeof(u_long)); 148 curp += next; 149 } 150 } 151 return(NULL); 152} 153 154/* 155 * Given a preloaded module handle (mod), return a pointer 156 * to the data for the attribute (inf). 157 */ 158caddr_t 159preload_search_info(caddr_t mod, int inf) 160{ 161 caddr_t curp; 162 uint32_t *hdr; 163 uint32_t type = 0; 164 int next; 165 166 if (mod == NULL) 167 return (NULL); 168 169 curp = mod; 170 for (;;) { 171 hdr = (uint32_t *)curp; 172 /* end of module data? */ 173 if (hdr[0] == 0 && hdr[1] == 0) 174 break; 175 /* 176 * We give up once we've looped back to what we were looking at 177 * first - this should normally be a MODINFO_NAME field. 178 */ 179 if (type == 0) { 180 type = hdr[0]; 181 } else { 182 if (hdr[0] == type) 183 break; 184 } 185 186 /* 187 * Attribute match? Return pointer to data. 188 * Consumer may safely assume that size value precedes 189 * data. 190 */ 191 if (hdr[0] == inf) 192 return(curp + (sizeof(uint32_t) * 2)); 193 194 /* skip to next field */ 195 next = sizeof(uint32_t) * 2 + hdr[1]; 196 next = roundup(next, sizeof(u_long)); 197 curp += next; 198 } 199 return(NULL); 200} 201 202/* 203 * Delete a preload record by name. 204 */ 205void 206preload_delete_name(const char *name) 207{ 208 caddr_t addr, curp; 209 uint32_t *hdr, sz; 210 int next; 211 int clearing; 212 213 addr = 0; 214 sz = 0; 215 216 if (preload_metadata != NULL) { 217 218 clearing = 0; 219 curp = preload_metadata; 220 for (;;) { 221 hdr = (uint32_t *)curp; 222 if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) { 223 /* Free memory used to store the file. */ 224 if (addr != 0 && sz != 0) 225 kmem_bootstrap_free((vm_offset_t)addr, sz); 226 addr = 0; 227 sz = 0; 228 229 if (hdr[0] == 0) 230 break; 231 if (!strcmp(name, curp + sizeof(uint32_t) * 2)) 232 clearing = 1; /* got it, start clearing */ 233 else if (clearing) { 234 clearing = 0; /* at next one now.. better stop */ 235 } 236 } 237 if (clearing) { 238 if (hdr[0] == MODINFO_ADDR) 239 addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2); 240 else if (hdr[0] == MODINFO_SIZE) 241 sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2); 242 hdr[0] = MODINFO_EMPTY; 243 } 244 245 /* skip to next field */ 246 next = sizeof(uint32_t) * 2 + hdr[1]; 247 next = roundup(next, sizeof(u_long)); 248 curp += next; 249 } 250 } 251} 252 253void * 254preload_fetch_addr(caddr_t mod) 255{ 256 caddr_t *mdp; 257 258 mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR); 259 if (mdp == NULL) 260 return (NULL); 261 return (*mdp + preload_addr_relocate); 262} 263 264size_t 265preload_fetch_size(caddr_t mod) 266{ 267 size_t *mdp; 268 269 mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE); 270 if (mdp == NULL) 271 return (0); 272 return (*mdp); 273} 274 275/* Called from locore. Convert physical pointers to kvm. Sigh. */ 276void 277preload_bootstrap_relocate(vm_offset_t offset) 278{ 279 caddr_t curp; 280 uint32_t *hdr; 281 vm_offset_t *ptr; 282 int next; 283 284 if (preload_metadata != NULL) { 285 286 curp = preload_metadata; 287 for (;;) { 288 hdr = (uint32_t *)curp; 289 if (hdr[0] == 0 && hdr[1] == 0) 290 break; 291 292 /* Deal with the ones that we know we have to fix */ 293 switch (hdr[0]) { 294 case MODINFO_ADDR: 295 case MODINFO_METADATA|MODINFOMD_SSYM: 296 case MODINFO_METADATA|MODINFOMD_ESYM: 297 ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); 298 *ptr += offset; 299 break; 300 } 301 /* The rest is beyond us for now */ 302 303 /* skip to next field */ 304 next = sizeof(uint32_t) * 2 + hdr[1]; 305 next = roundup(next, sizeof(u_long)); 306 curp += next; 307 } 308 } 309} 310