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 if (mod == NULL) 164 return (NULL); 165 166 curp = mod; 167 for (;;) { 168 hdr = (uint32_t *)curp; 169 /* end of module data? */ 170 if (hdr[0] == 0 && hdr[1] == 0) 171 break; 172 /* 173 * We give up once we've looped back to what we were looking at 174 * first - this should normally be a MODINFO_NAME field. 175 */ 176 if (type == 0) { 177 type = hdr[0]; 178 } else { 179 if (hdr[0] == type) 180 break; 181 } 182 183 /* 184 * Attribute match? Return pointer to data. 185 * Consumer may safely assume that size value precedes 186 * data. 187 */ 188 if (hdr[0] == inf) 189 return(curp + (sizeof(uint32_t) * 2)); 190 191 /* skip to next field */ 192 next = sizeof(uint32_t) * 2 + hdr[1]; 193 next = roundup(next, sizeof(u_long)); 194 curp += next; 195 } 196 return(NULL); 197 } 198 199 /* 200 * Delete a preload record by name. 201 */ 202 void 203 preload_delete_name(const char *name) 204 { 205 caddr_t curp; 206 uint32_t *hdr; 207 int next; 208 int clearing; 209 210 if (preload_metadata != NULL) { 211 212 clearing = 0; 213 curp = preload_metadata; 214 for (;;) { 215 hdr = (uint32_t *)curp; 216 if (hdr[0] == 0 && hdr[1] == 0) 217 break; 218 219 /* Search for a MODINFO_NAME field */ 220 if (hdr[0] == MODINFO_NAME) { 221 if (!strcmp(name, curp + sizeof(uint32_t) * 2)) 222 clearing = 1; /* got it, start clearing */ 223 else if (clearing) 224 clearing = 0; /* at next one now.. better stop */ 225 } 226 if (clearing) 227 hdr[0] = MODINFO_EMPTY; 228 229 /* skip to next field */ 230 next = sizeof(uint32_t) * 2 + hdr[1]; 231 next = roundup(next, sizeof(u_long)); 232 curp += next; 233 } 234 } 235 } 236 237 void * 238 preload_fetch_addr(caddr_t mod) 239 { 240 caddr_t *mdp; 241 242 mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR); 243 if (mdp == NULL) 244 return (NULL); 245 return (*mdp + preload_addr_relocate); 246 } 247 248 size_t 249 preload_fetch_size(caddr_t mod) 250 { 251 size_t *mdp; 252 253 mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE); 254 if (mdp == NULL) 255 return (0); 256 return (*mdp); 257 } 258 259 /* Called from locore. Convert physical pointers to kvm. Sigh. */ 260 void 261 preload_bootstrap_relocate(vm_offset_t offset) 262 { 263 caddr_t curp; 264 uint32_t *hdr; 265 vm_offset_t *ptr; 266 int next; 267 268 if (preload_metadata != NULL) { 269 270 curp = preload_metadata; 271 for (;;) { 272 hdr = (uint32_t *)curp; 273 if (hdr[0] == 0 && hdr[1] == 0) 274 break; 275 276 /* Deal with the ones that we know we have to fix */ 277 switch (hdr[0]) { 278 case MODINFO_ADDR: 279 case MODINFO_METADATA|MODINFOMD_SSYM: 280 case MODINFO_METADATA|MODINFOMD_ESYM: 281 ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); 282 *ptr += offset; 283 break; 284 } 285 /* The rest is beyond us for now */ 286 287 /* skip to next field */ 288 next = sizeof(uint32_t) * 2 + hdr[1]; 289 next = roundup(next, sizeof(u_long)); 290 curp += next; 291 } 292 } 293 } 294