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