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