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 * $FreeBSD: src/sys/kern/subr_module.c,v 1.6 1999/10/11 15:19:10 peter Exp $ 27 * $DragonFly: src/sys/kern/subr_module.c,v 1.4 2004/05/26 08:32:41 dillon Exp $ 28 */ 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 caddr_t preload_metadata; 39 40 /* 41 * Search for the preloaded module (name) 42 */ 43 caddr_t 44 preload_search_by_name(const char *name) 45 { 46 caddr_t curp; 47 u_int32_t *hdr; 48 int next; 49 int i; 50 char *scanname; 51 52 if (preload_metadata == NULL) 53 return(NULL); 54 55 curp = preload_metadata; 56 for (;;) { 57 hdr = (u_int32_t *)curp; 58 if (hdr[0] == 0 && hdr[1] == 0) 59 break; 60 61 /* 62 * Search for a MODINFO_NAME field. the boot loader really 63 * ought to strip the path names 64 */ 65 if (hdr[0] == MODINFO_NAME) { 66 scanname = curp + sizeof(u_int32_t) * 2; 67 i = strlen(scanname); 68 while (i > 0 && scanname[i-1] != '/') 69 --i; 70 if (strcmp(name, scanname) == 0) 71 return(curp); 72 if (strcmp(name, scanname + i) == 0) 73 return(curp); 74 } 75 /* skip to next field */ 76 next = sizeof(u_int32_t) * 2 + hdr[1]; 77 next = roundup(next, sizeof(u_long)); 78 curp += next; 79 } 80 return(NULL); 81 } 82 83 /* 84 * Search for the first preloaded module of (type) 85 */ 86 caddr_t 87 preload_search_by_type(const char *type) 88 { 89 caddr_t curp, lname; 90 u_int32_t *hdr; 91 int next; 92 93 if (preload_metadata != NULL) { 94 95 curp = preload_metadata; 96 lname = NULL; 97 for (;;) { 98 hdr = (u_int32_t *)curp; 99 if (hdr[0] == 0 && hdr[1] == 0) 100 break; 101 102 /* remember the start of each record */ 103 if (hdr[0] == MODINFO_NAME) 104 lname = curp; 105 106 /* Search for a MODINFO_TYPE field */ 107 if ((hdr[0] == MODINFO_TYPE) && 108 !strcmp(type, curp + sizeof(u_int32_t) * 2)) 109 return(lname); 110 111 /* skip to next field */ 112 next = sizeof(u_int32_t) * 2 + hdr[1]; 113 next = roundup(next, sizeof(u_long)); 114 curp += next; 115 } 116 } 117 return(NULL); 118 } 119 120 /* 121 * Walk through the preloaded module list 122 */ 123 caddr_t 124 preload_search_next_name(caddr_t base) 125 { 126 caddr_t curp; 127 u_int32_t *hdr; 128 int next; 129 130 if (preload_metadata != NULL) { 131 132 /* Pick up where we left off last time */ 133 if (base) { 134 /* skip to next field */ 135 curp = base; 136 hdr = (u_int32_t *)curp; 137 next = sizeof(u_int32_t) * 2 + hdr[1]; 138 next = roundup(next, sizeof(u_long)); 139 curp += next; 140 } else 141 curp = preload_metadata; 142 143 for (;;) { 144 hdr = (u_int32_t *)curp; 145 if (hdr[0] == 0 && hdr[1] == 0) 146 break; 147 148 /* Found a new record? */ 149 if (hdr[0] == MODINFO_NAME) 150 return curp; 151 152 /* skip to next field */ 153 next = sizeof(u_int32_t) * 2 + hdr[1]; 154 next = roundup(next, sizeof(u_long)); 155 curp += next; 156 } 157 } 158 return(NULL); 159 } 160 161 /* 162 * Given a preloaded module handle (mod), return a pointer 163 * to the data for the attribute (inf). 164 */ 165 caddr_t 166 preload_search_info(caddr_t mod, int inf) 167 { 168 caddr_t curp; 169 u_int32_t *hdr; 170 u_int32_t type = 0; 171 int next; 172 173 curp = mod; 174 for (;;) { 175 hdr = (u_int32_t *)curp; 176 /* end of module data? */ 177 if (hdr[0] == 0 && hdr[1] == 0) 178 break; 179 /* 180 * We give up once we've looped back to what we were looking at 181 * first - this should normally be a MODINFO_NAME field. 182 */ 183 if (type == 0) { 184 type = hdr[0]; 185 } else { 186 if (hdr[0] == type) 187 break; 188 } 189 190 /* 191 * Attribute match? Return pointer to data. 192 * Consumer may safely assume that size value preceeds 193 * data. 194 */ 195 if (hdr[0] == inf) 196 return(curp + (sizeof(u_int32_t) * 2)); 197 198 /* skip to next field */ 199 next = sizeof(u_int32_t) * 2 + hdr[1]; 200 next = roundup(next, sizeof(u_long)); 201 curp += next; 202 } 203 return(NULL); 204 } 205 206 /* 207 * Delete a preload record by name. 208 * 209 * XXX we should really pass the base of the preloaded module here and not 210 * require rematching of the name. If the wrong module (or no module) is 211 * deleted, the original preloaded module might be loaded again, causing it's 212 * data to be relocated twice. 213 */ 214 void 215 preload_delete_name(const char *name) 216 { 217 caddr_t curp; 218 u_int32_t *hdr; 219 int next; 220 int clearing; 221 int i; 222 char *scanname; 223 224 if (preload_metadata != NULL) { 225 clearing = 0; 226 curp = preload_metadata; 227 for (;;) { 228 hdr = (u_int32_t *)curp; 229 if (hdr[0] == 0 && hdr[1] == 0) 230 break; 231 232 /* Search for a MODINFO_NAME field */ 233 if (hdr[0] == MODINFO_NAME) { 234 scanname = curp + sizeof(u_int32_t) * 2; 235 i = strlen(scanname); 236 while (i > 0 && scanname[i-1] != '/') 237 --i; 238 if (strcmp(name, scanname) == 0) 239 clearing = 1; 240 else if (strcmp(name, scanname + i) == 0) 241 clearing = 1; 242 else 243 clearing = 0; /* at next module now, stop clearing */ 244 } 245 if (clearing) 246 hdr[0] = MODINFO_EMPTY; 247 248 /* skip to next field */ 249 next = sizeof(u_int32_t) * 2 + hdr[1]; 250 next = roundup(next, sizeof(u_long)); 251 curp += next; 252 } 253 } 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 u_int32_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 = (u_int32_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(u_int32_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(u_int32_t) * 2 + hdr[1]; 286 next = roundup(next, sizeof(u_long)); 287 curp += next; 288 } 289 } 290 } 291