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 /* 37 * Preloaded module support 38 */ 39 40 vm_offset_t preload_addr_relocate = 0; 41 caddr_t preload_metadata; 42 43 /* 44 * Search for the preloaded module (name) 45 */ 46 caddr_t 47 preload_search_by_name(const char *name) 48 { 49 caddr_t curp; 50 uint32_t *hdr; 51 int next; 52 53 if (preload_metadata != NULL) { 54 55 curp = preload_metadata; 56 for (;;) { 57 hdr = (uint32_t *)curp; 58 if (hdr[0] == 0 && hdr[1] == 0) 59 break; 60 61 /* Search for a MODINFO_NAME field */ 62 if ((hdr[0] == MODINFO_NAME) && 63 !strcmp(name, curp + sizeof(uint32_t) * 2)) 64 return(curp); 65 66 /* skip to next field */ 67 next = sizeof(uint32_t) * 2 + hdr[1]; 68 next = roundup(next, sizeof(u_long)); 69 curp += next; 70 } 71 } 72 return(NULL); 73 } 74 75 /* 76 * Search for the first preloaded module of (type) 77 */ 78 caddr_t 79 preload_search_by_type(const char *type) 80 { 81 caddr_t curp, lname; 82 uint32_t *hdr; 83 int next; 84 85 if (preload_metadata != NULL) { 86 87 curp = preload_metadata; 88 lname = NULL; 89 for (;;) { 90 hdr = (uint32_t *)curp; 91 if (hdr[0] == 0 && hdr[1] == 0) 92 break; 93 94 /* remember the start of each record */ 95 if (hdr[0] == MODINFO_NAME) 96 lname = curp; 97 98 /* Search for a MODINFO_TYPE field */ 99 if ((hdr[0] == MODINFO_TYPE) && 100 !strcmp(type, curp + sizeof(uint32_t) * 2)) 101 return(lname); 102 103 /* skip to next field */ 104 next = sizeof(uint32_t) * 2 + hdr[1]; 105 next = roundup(next, sizeof(u_long)); 106 curp += next; 107 } 108 } 109 return(NULL); 110 } 111 112 /* 113 * Walk through the preloaded module list 114 */ 115 caddr_t 116 preload_search_next_name(caddr_t base) 117 { 118 caddr_t curp; 119 uint32_t *hdr; 120 int next; 121 122 if (preload_metadata != NULL) { 123 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 curp; 208 uint32_t *hdr; 209 int next; 210 int clearing; 211 212 if (preload_metadata != NULL) { 213 214 clearing = 0; 215 curp = preload_metadata; 216 for (;;) { 217 hdr = (uint32_t *)curp; 218 if (hdr[0] == 0 && hdr[1] == 0) 219 break; 220 221 /* Search for a MODINFO_NAME field */ 222 if (hdr[0] == MODINFO_NAME) { 223 if (!strcmp(name, curp + sizeof(uint32_t) * 2)) 224 clearing = 1; /* got it, start clearing */ 225 else if (clearing) 226 clearing = 0; /* at next one now.. better stop */ 227 } 228 if (clearing) 229 hdr[0] = MODINFO_EMPTY; 230 231 /* skip to next field */ 232 next = sizeof(uint32_t) * 2 + hdr[1]; 233 next = roundup(next, sizeof(u_long)); 234 curp += next; 235 } 236 } 237 } 238 239 void * 240 preload_fetch_addr(caddr_t mod) 241 { 242 caddr_t *mdp; 243 244 mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR); 245 if (mdp == NULL) 246 return (NULL); 247 return (*mdp + preload_addr_relocate); 248 } 249 250 size_t 251 preload_fetch_size(caddr_t mod) 252 { 253 size_t *mdp; 254 255 mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE); 256 if (mdp == NULL) 257 return (0); 258 return (*mdp); 259 } 260 261 /* Called from locore. Convert physical pointers to kvm. Sigh. */ 262 void 263 preload_bootstrap_relocate(vm_offset_t offset) 264 { 265 caddr_t curp; 266 uint32_t *hdr; 267 vm_offset_t *ptr; 268 int next; 269 270 if (preload_metadata != NULL) { 271 272 curp = preload_metadata; 273 for (;;) { 274 hdr = (uint32_t *)curp; 275 if (hdr[0] == 0 && hdr[1] == 0) 276 break; 277 278 /* Deal with the ones that we know we have to fix */ 279 switch (hdr[0]) { 280 case MODINFO_ADDR: 281 case MODINFO_METADATA|MODINFOMD_SSYM: 282 case MODINFO_METADATA|MODINFOMD_ESYM: 283 ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); 284 *ptr += offset; 285 break; 286 } 287 /* The rest is beyond us for now */ 288 289 /* skip to next field */ 290 next = sizeof(uint32_t) * 2 + hdr[1]; 291 next = roundup(next, sizeof(u_long)); 292 curp += next; 293 } 294 } 295 } 296