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 #include <sys/sbuf.h> 33 #include <sys/sysctl.h> 34 35 #include <machine/metadata.h> 36 37 /* 38 * Preloaded module support 39 */ 40 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 u_int32_t *hdr; 51 int next; 52 int i; 53 char *scanname; 54 55 if (preload_metadata == NULL) 56 return(NULL); 57 58 curp = preload_metadata; 59 for (;;) { 60 hdr = (u_int32_t *)curp; 61 if (hdr[0] == 0 && hdr[1] == 0) 62 break; 63 64 /* 65 * Search for a MODINFO_NAME field. the boot loader really 66 * ought to strip the path names 67 */ 68 if (hdr[0] == MODINFO_NAME) { 69 scanname = curp + sizeof(u_int32_t) * 2; 70 i = strlen(scanname); 71 while (i > 0 && scanname[i-1] != '/') 72 --i; 73 if (strcmp(name, scanname) == 0) 74 return(curp); 75 if (strcmp(name, scanname + i) == 0) 76 return(curp); 77 } 78 /* skip to next field */ 79 next = sizeof(u_int32_t) * 2 + hdr[1]; 80 next = roundup(next, sizeof(u_long)); 81 curp += next; 82 } 83 return(NULL); 84 } 85 86 /* 87 * Search for the first preloaded module of (type) 88 */ 89 caddr_t 90 preload_search_by_type(const char *type) 91 { 92 caddr_t curp, lname; 93 u_int32_t *hdr; 94 int next; 95 96 if (preload_metadata != NULL) { 97 98 curp = preload_metadata; 99 lname = NULL; 100 for (;;) { 101 hdr = (u_int32_t *)curp; 102 if (hdr[0] == 0 && hdr[1] == 0) 103 break; 104 105 /* remember the start of each record */ 106 if (hdr[0] == MODINFO_NAME) 107 lname = curp; 108 109 /* Search for a MODINFO_TYPE field */ 110 if ((hdr[0] == MODINFO_TYPE) && 111 !strcmp(type, curp + sizeof(u_int32_t) * 2)) 112 return(lname); 113 114 /* skip to next field */ 115 next = sizeof(u_int32_t) * 2 + hdr[1]; 116 next = roundup(next, sizeof(u_long)); 117 curp += next; 118 } 119 } 120 return(NULL); 121 } 122 123 /* 124 * Walk through the preloaded module list 125 */ 126 caddr_t 127 preload_search_next_name(caddr_t base) 128 { 129 caddr_t curp; 130 u_int32_t *hdr; 131 int next; 132 133 if (preload_metadata != NULL) { 134 135 /* Pick up where we left off last time */ 136 if (base) { 137 /* skip to next field */ 138 curp = base; 139 hdr = (u_int32_t *)curp; 140 next = sizeof(u_int32_t) * 2 + hdr[1]; 141 next = roundup(next, sizeof(u_long)); 142 curp += next; 143 } else 144 curp = preload_metadata; 145 146 for (;;) { 147 hdr = (u_int32_t *)curp; 148 if (hdr[0] == 0 && hdr[1] == 0) 149 break; 150 151 /* Found a new record? */ 152 if (hdr[0] == MODINFO_NAME) 153 return curp; 154 155 /* skip to next field */ 156 next = sizeof(u_int32_t) * 2 + hdr[1]; 157 next = roundup(next, sizeof(u_long)); 158 curp += next; 159 } 160 } 161 return(NULL); 162 } 163 164 /* 165 * Given a preloaded module handle (mod), return a pointer 166 * to the data for the attribute (inf). 167 */ 168 caddr_t 169 preload_search_info(caddr_t mod, int inf) 170 { 171 caddr_t curp; 172 u_int32_t *hdr; 173 u_int32_t type = 0; 174 int next; 175 176 curp = mod; 177 for (;;) { 178 hdr = (u_int32_t *)curp; 179 /* end of module data? */ 180 if (hdr[0] == 0 && hdr[1] == 0) 181 break; 182 /* 183 * We give up once we've looped back to what we were looking at 184 * first - this should normally be a MODINFO_NAME field. 185 */ 186 if (type == 0) { 187 type = hdr[0]; 188 } else { 189 if (hdr[0] == type) 190 break; 191 } 192 193 /* 194 * Attribute match? Return pointer to data. 195 * Consumer may safely assume that size value preceeds 196 * data. 197 */ 198 if (hdr[0] == inf) 199 return(curp + (sizeof(u_int32_t) * 2)); 200 201 /* skip to next field */ 202 next = sizeof(u_int32_t) * 2 + hdr[1]; 203 next = roundup(next, sizeof(u_long)); 204 curp += next; 205 } 206 return(NULL); 207 } 208 209 /* 210 * Delete a preload record by path name. 211 */ 212 void 213 preload_delete_name(const char *name) 214 { 215 caddr_t curp; 216 u_int32_t *hdr; 217 int next; 218 int clearing; 219 220 if (preload_metadata != NULL) { 221 clearing = 0; 222 curp = preload_metadata; 223 for (;;) { 224 hdr = (u_int32_t *)curp; 225 if (hdr[0] == 0 && hdr[1] == 0) 226 break; 227 228 /* Search for a MODINFO_NAME field */ 229 if (hdr[0] == MODINFO_NAME) { 230 if (strcmp(name, curp + sizeof(u_int32_t) * 2) == 0) 231 clearing = 1; /* start clearing */ 232 else if (clearing) 233 clearing = 0; /* at next module now, stop clearing */ 234 } 235 if (clearing) 236 hdr[0] = MODINFO_EMPTY; 237 238 /* skip to next field */ 239 next = sizeof(u_int32_t) * 2 + hdr[1]; 240 next = roundup(next, sizeof(u_long)); 241 curp += next; 242 } 243 } 244 } 245 246 /* Called from hammer_time() on pc64. Convert physical pointers to kvm. Sigh. */ 247 void 248 preload_bootstrap_relocate(vm_offset_t offset) 249 { 250 caddr_t curp; 251 u_int32_t *hdr; 252 vm_offset_t *ptr; 253 int next; 254 255 if (preload_metadata != NULL) { 256 257 curp = preload_metadata; 258 for (;;) { 259 hdr = (u_int32_t *)curp; 260 if (hdr[0] == 0 && hdr[1] == 0) 261 break; 262 263 /* Deal with the ones that we know we have to fix */ 264 switch (hdr[0]) { 265 case MODINFO_ADDR: 266 case MODINFO_METADATA|MODINFOMD_SSYM: 267 case MODINFO_METADATA|MODINFOMD_ESYM: 268 ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2)); 269 *ptr += offset; 270 break; 271 } 272 /* The rest is beyond us for now */ 273 274 /* skip to next field */ 275 next = sizeof(u_int32_t) * 2 + hdr[1]; 276 next = roundup(next, sizeof(u_long)); 277 curp += next; 278 } 279 } 280 } 281 282 /* 283 * Parse the modinfo type and append to the sbuf. 284 */ 285 static void 286 preload_modinfo_type(struct sbuf *sbp, int type) 287 { 288 if ((type & MODINFO_METADATA) == 0) { 289 switch (type) { 290 case MODINFO_END: 291 sbuf_cat(sbp, "MODINFO_END"); 292 break; 293 case MODINFO_NAME: 294 sbuf_cat(sbp, "MODINFO_NAME"); 295 break; 296 case MODINFO_TYPE: 297 sbuf_cat(sbp, "MODINFO_TYPE"); 298 break; 299 case MODINFO_ADDR: 300 sbuf_cat(sbp, "MODINFO_ADDR"); 301 break; 302 case MODINFO_SIZE: 303 sbuf_cat(sbp, "MODINFO_SIZE"); 304 break; 305 case MODINFO_EMPTY: 306 sbuf_cat(sbp, "MODINFO_EMPTY"); 307 break; 308 case MODINFO_ARGS: 309 sbuf_cat(sbp, "MODINFO_ARGS"); 310 break; 311 default: 312 sbuf_cat(sbp, "unrecognized modinfo attribute"); 313 } 314 315 return; 316 } 317 318 sbuf_cat(sbp, "MODINFO_METADATA | "); 319 switch (type & ~MODINFO_METADATA) { 320 case MODINFOMD_ELFHDR: 321 sbuf_cat(sbp, "MODINFOMD_ELFHDR"); 322 break; 323 case MODINFOMD_SSYM: 324 sbuf_cat(sbp, "MODINFOMD_SSYM"); 325 break; 326 case MODINFOMD_ESYM: 327 sbuf_cat(sbp, "MODINFOMD_ESYM"); 328 break; 329 case MODINFOMD_DYNAMIC: 330 sbuf_cat(sbp, "MODINFOMD_DYNAMIC"); 331 break; 332 case MODINFOMD_ENVP: 333 sbuf_cat(sbp, "MODINFOMD_ENVP"); 334 break; 335 case MODINFOMD_HOWTO: 336 sbuf_cat(sbp, "MODINFOMD_HOWTO"); 337 break; 338 case MODINFOMD_KERNEND: 339 sbuf_cat(sbp, "MODINFOMD_KERNEND"); 340 break; 341 case MODINFOMD_SHDR: 342 sbuf_cat(sbp, "MODINFOMD_SHDR"); 343 break; 344 case MODINFOMD_FW_HANDLE: 345 sbuf_cat(sbp, "MODINFOMD_FW_HANDLE"); 346 break; 347 case MODINFOMD_SMAP: 348 sbuf_cat(sbp, "MODINFOMD_SMAP"); 349 break; 350 case MODINFOMD_EFI_MAP: 351 sbuf_cat(sbp, "MODINFOMD_EFI_MAP"); 352 break; 353 case MODINFOMD_EFI_FB: 354 sbuf_cat(sbp, "MODINFOMD_EFI_FB"); 355 break; 356 default: 357 sbuf_cat(sbp, "unrecognized metadata type"); 358 } 359 } 360 361 /* 362 * Print the modinfo value, depending on type. 363 */ 364 static void 365 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len) 366 { 367 switch (type) { 368 case MODINFO_NAME: 369 case MODINFO_TYPE: 370 case MODINFO_ARGS: 371 sbuf_printf(sbp, "%s", (char *)bptr); 372 break; 373 case MODINFO_SIZE: 374 sbuf_printf(sbp, "%lu", *(u_long *)bptr); 375 break; 376 case MODINFO_ADDR: 377 case MODINFO_METADATA | MODINFOMD_SSYM: 378 case MODINFO_METADATA | MODINFOMD_ESYM: 379 case MODINFO_METADATA | MODINFOMD_DYNAMIC: 380 case MODINFO_METADATA | MODINFOMD_KERNEND: 381 case MODINFO_METADATA | MODINFOMD_ENVP: 382 case MODINFO_METADATA | MODINFOMD_SMAP: 383 case MODINFO_METADATA | MODINFOMD_EFI_FB: 384 sbuf_printf(sbp, "0x%016lx", *(vm_offset_t *)bptr); 385 break; 386 case MODINFO_METADATA | MODINFOMD_HOWTO: 387 sbuf_printf(sbp, "0x%08x", *bptr); 388 break; 389 case MODINFO_METADATA | MODINFOMD_SHDR: 390 case MODINFO_METADATA | MODINFOMD_ELFHDR: 391 case MODINFO_METADATA | MODINFOMD_FW_HANDLE: 392 case MODINFO_METADATA | MODINFOMD_EFI_MAP: 393 /* Don't print data buffers. */ 394 sbuf_cat(sbp, "buffer contents omitted"); 395 break; 396 default: 397 break; 398 } 399 } 400 401 static void 402 preload_dump_internal(struct sbuf *sbp) 403 { 404 uint32_t *bptr, type, len; 405 406 sbuf_putc(sbp, '\n'); 407 408 /* Iterate through the TLV-encoded sections. */ 409 bptr = (uint32_t *)preload_metadata; 410 while (bptr[0] != MODINFO_END) { 411 sbuf_printf(sbp, " %p:\n", bptr); 412 413 type = *bptr++; 414 sbuf_printf(sbp, "\ttype:\t(%#04x) ", type); 415 preload_modinfo_type(sbp, type); 416 sbuf_putc(sbp, '\n'); 417 418 len = *bptr++; 419 sbuf_printf(sbp, "\tlen:\t%u\n", len); 420 421 sbuf_cat(sbp, "\tvalue:\t"); 422 preload_modinfo_value(sbp, bptr, type, len); 423 sbuf_putc(sbp, '\n'); 424 425 bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t); 426 } 427 } 428 429 static int 430 sysctl_preload_dump(SYSCTL_HANDLER_ARGS) 431 { 432 struct sbuf sb; 433 int error; 434 435 if (preload_metadata == NULL) 436 return (EINVAL); 437 438 sbuf_new_for_sysctl(&sb, NULL, 512, req); 439 preload_dump_internal(&sb); 440 441 error = sbuf_finish(&sb); 442 sbuf_delete(&sb); 443 444 return (error); 445 } 446 447 SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo, 448 CTLTYPE_STRING | CTLFLAG_RD, 449 NULL, 0, sysctl_preload_dump, "A", 450 "pretty-print the bootloader metadata"); 451