1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1998 Michael Smith 5 * All rights reserved. 6 * Copyright (c) 2020 NetApp Inc. 7 * Copyright (c) 2020 Klara Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/linker.h> 34 #include <sys/sbuf.h> 35 #include <sys/sysctl.h> 36 37 #include <machine/metadata.h> 38 39 #include <vm/vm.h> 40 #include <vm/vm_extern.h> 41 42 /* 43 * Preloaded module support 44 */ 45 46 vm_offset_t preload_addr_relocate = 0; 47 caddr_t preload_metadata; 48 49 /* 50 * Search for the preloaded module (name) 51 */ 52 caddr_t 53 preload_search_by_name(const char *name) 54 { 55 caddr_t curp; 56 uint32_t *hdr; 57 int next; 58 59 if (preload_metadata != NULL) { 60 curp = preload_metadata; 61 for (;;) { 62 hdr = (uint32_t *)curp; 63 if (hdr[0] == 0 && hdr[1] == 0) 64 break; 65 66 /* Search for a MODINFO_NAME field */ 67 if ((hdr[0] == MODINFO_NAME) && 68 !strcmp(name, curp + sizeof(uint32_t) * 2)) 69 return(curp); 70 71 /* skip to next field */ 72 next = sizeof(uint32_t) * 2 + hdr[1]; 73 next = roundup(next, sizeof(u_long)); 74 curp += next; 75 } 76 } 77 return(NULL); 78 } 79 80 /* 81 * Search for the first preloaded module of (type) 82 */ 83 caddr_t 84 preload_search_by_type(const char *type) 85 { 86 caddr_t curp, lname; 87 uint32_t *hdr; 88 int next; 89 90 if (preload_metadata != NULL) { 91 curp = preload_metadata; 92 lname = NULL; 93 for (;;) { 94 hdr = (uint32_t *)curp; 95 if (hdr[0] == 0 && hdr[1] == 0) 96 break; 97 98 /* remember the start of each record */ 99 if (hdr[0] == MODINFO_NAME) 100 lname = curp; 101 102 /* Search for a MODINFO_TYPE field */ 103 if ((hdr[0] == MODINFO_TYPE) && 104 !strcmp(type, curp + sizeof(uint32_t) * 2)) 105 return(lname); 106 107 /* skip to next field */ 108 next = sizeof(uint32_t) * 2 + hdr[1]; 109 next = roundup(next, sizeof(u_long)); 110 curp += next; 111 } 112 } 113 return(NULL); 114 } 115 116 /* 117 * Walk through the preloaded module list 118 */ 119 caddr_t 120 preload_search_next_name(caddr_t base) 121 { 122 caddr_t curp; 123 uint32_t *hdr; 124 int next; 125 126 if (preload_metadata != NULL) { 127 /* Pick up where we left off last time */ 128 if (base) { 129 /* skip to next field */ 130 curp = base; 131 hdr = (uint32_t *)curp; 132 next = sizeof(uint32_t) * 2 + hdr[1]; 133 next = roundup(next, sizeof(u_long)); 134 curp += next; 135 } else 136 curp = preload_metadata; 137 138 for (;;) { 139 hdr = (uint32_t *)curp; 140 if (hdr[0] == 0 && hdr[1] == 0) 141 break; 142 143 /* Found a new record? */ 144 if (hdr[0] == MODINFO_NAME) 145 return curp; 146 147 /* skip to next field */ 148 next = sizeof(uint32_t) * 2 + hdr[1]; 149 next = roundup(next, sizeof(u_long)); 150 curp += next; 151 } 152 } 153 return(NULL); 154 } 155 156 /* 157 * Given a preloaded module handle (mod), return a pointer 158 * to the data for the attribute (inf). 159 */ 160 caddr_t 161 preload_search_info(caddr_t mod, int inf) 162 { 163 caddr_t curp; 164 uint32_t *hdr; 165 uint32_t type = 0; 166 int next; 167 168 if (mod == NULL) 169 return (NULL); 170 171 curp = mod; 172 for (;;) { 173 hdr = (uint32_t *)curp; 174 /* end of module data? */ 175 if (hdr[0] == 0 && hdr[1] == 0) 176 break; 177 /* 178 * We give up once we've looped back to what we were looking at 179 * first - this should normally be a MODINFO_NAME field. 180 */ 181 if (type == 0) { 182 type = hdr[0]; 183 } else { 184 if (hdr[0] == type) 185 break; 186 } 187 188 /* 189 * Attribute match? Return pointer to data. 190 * Consumer may safely assume that size value precedes 191 * data. 192 */ 193 if (hdr[0] == inf) 194 return(curp + (sizeof(uint32_t) * 2)); 195 196 /* skip to next field */ 197 next = sizeof(uint32_t) * 2 + hdr[1]; 198 next = roundup(next, sizeof(u_long)); 199 curp += next; 200 } 201 return(NULL); 202 } 203 204 /* 205 * Delete a preload record by name. 206 */ 207 void 208 preload_delete_name(const char *name) 209 { 210 caddr_t addr, curp; 211 uint32_t *hdr, sz; 212 int next; 213 int clearing; 214 215 addr = 0; 216 sz = 0; 217 218 if (preload_metadata != NULL) { 219 clearing = 0; 220 curp = preload_metadata; 221 for (;;) { 222 hdr = (uint32_t *)curp; 223 if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) { 224 /* Free memory used to store the file. */ 225 if (addr != 0 && sz != 0) 226 kmem_bootstrap_free((vm_offset_t)addr, sz); 227 addr = 0; 228 sz = 0; 229 230 if (hdr[0] == 0) 231 break; 232 if (!strcmp(name, curp + sizeof(uint32_t) * 2)) 233 clearing = 1; /* got it, start clearing */ 234 else if (clearing) { 235 clearing = 0; /* at next one now.. better stop */ 236 } 237 } 238 if (clearing) { 239 if (hdr[0] == MODINFO_ADDR) 240 addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2); 241 else if (hdr[0] == MODINFO_SIZE) 242 sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2); 243 hdr[0] = MODINFO_EMPTY; 244 } 245 246 /* skip to next field */ 247 next = sizeof(uint32_t) * 2 + hdr[1]; 248 next = roundup(next, sizeof(u_long)); 249 curp += next; 250 } 251 } 252 } 253 254 void * 255 preload_fetch_addr(caddr_t mod) 256 { 257 caddr_t *mdp; 258 259 mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR); 260 if (mdp == NULL) 261 return (NULL); 262 return (*mdp + preload_addr_relocate); 263 } 264 265 size_t 266 preload_fetch_size(caddr_t mod) 267 { 268 size_t *mdp; 269 270 mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE); 271 if (mdp == NULL) 272 return (0); 273 return (*mdp); 274 } 275 276 /* Called from locore. Convert physical pointers to kvm. Sigh. */ 277 void 278 preload_bootstrap_relocate(vm_offset_t offset) 279 { 280 caddr_t curp; 281 uint32_t *hdr; 282 vm_offset_t *ptr; 283 int next; 284 285 if (preload_metadata != NULL) { 286 curp = preload_metadata; 287 for (;;) { 288 hdr = (uint32_t *)curp; 289 if (hdr[0] == 0 && hdr[1] == 0) 290 break; 291 292 /* Deal with the ones that we know we have to fix */ 293 switch (hdr[0]) { 294 case MODINFO_ADDR: 295 case MODINFO_METADATA|MODINFOMD_FONT: 296 case MODINFO_METADATA|MODINFOMD_SSYM: 297 case MODINFO_METADATA|MODINFOMD_ESYM: 298 ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); 299 *ptr += offset; 300 break; 301 } 302 /* The rest is beyond us for now */ 303 304 /* skip to next field */ 305 next = sizeof(uint32_t) * 2 + hdr[1]; 306 next = roundup(next, sizeof(u_long)); 307 curp += next; 308 } 309 } 310 } 311 312 /* 313 * Parse the modinfo type and append to the provided sbuf. 314 */ 315 static void 316 preload_modinfo_type(struct sbuf *sbp, int type) 317 { 318 319 if ((type & MODINFO_METADATA) == 0) { 320 switch (type) { 321 case MODINFO_END: 322 sbuf_cat(sbp, "MODINFO_END"); 323 break; 324 case MODINFO_NAME: 325 sbuf_cat(sbp, "MODINFO_NAME"); 326 break; 327 case MODINFO_TYPE: 328 sbuf_cat(sbp, "MODINFO_TYPE"); 329 break; 330 case MODINFO_ADDR: 331 sbuf_cat(sbp, "MODINFO_ADDR"); 332 break; 333 case MODINFO_SIZE: 334 sbuf_cat(sbp, "MODINFO_SIZE"); 335 break; 336 case MODINFO_EMPTY: 337 sbuf_cat(sbp, "MODINFO_EMPTY"); 338 break; 339 case MODINFO_ARGS: 340 sbuf_cat(sbp, "MODINFO_ARGS"); 341 break; 342 default: 343 sbuf_cat(sbp, "unrecognized modinfo attribute"); 344 } 345 346 return; 347 } 348 349 sbuf_cat(sbp, "MODINFO_METADATA | "); 350 switch (type & ~MODINFO_METADATA) { 351 case MODINFOMD_ELFHDR: 352 sbuf_cat(sbp, "MODINFOMD_ELFHDR"); 353 break; 354 case MODINFOMD_SSYM: 355 sbuf_cat(sbp, "MODINFOMD_SSYM"); 356 break; 357 case MODINFOMD_ESYM: 358 sbuf_cat(sbp, "MODINFOMD_ESYM"); 359 break; 360 case MODINFOMD_DYNAMIC: 361 sbuf_cat(sbp, "MODINFOMD_DYNAMIC"); 362 break; 363 case MODINFOMD_ENVP: 364 sbuf_cat(sbp, "MODINFOMD_ENVP"); 365 break; 366 case MODINFOMD_HOWTO: 367 sbuf_cat(sbp, "MODINFOMD_HOWTO"); 368 break; 369 case MODINFOMD_KERNEND: 370 sbuf_cat(sbp, "MODINFOMD_KERNEND"); 371 break; 372 case MODINFOMD_SHDR: 373 sbuf_cat(sbp, "MODINFOMD_SHDR"); 374 break; 375 case MODINFOMD_CTORS_ADDR: 376 sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR"); 377 break; 378 case MODINFOMD_CTORS_SIZE: 379 sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE"); 380 break; 381 case MODINFOMD_FW_HANDLE: 382 sbuf_cat(sbp, "MODINFOMD_FW_HANDLE"); 383 break; 384 case MODINFOMD_KEYBUF: 385 sbuf_cat(sbp, "MODINFOMD_KEYBUF"); 386 break; 387 #ifdef MODINFOMD_SMAP 388 case MODINFOMD_SMAP: 389 sbuf_cat(sbp, "MODINFOMD_SMAP"); 390 break; 391 #endif 392 #ifdef MODINFOMD_SMAP_XATTR 393 case MODINFOMD_SMAP_XATTR: 394 sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR"); 395 break; 396 #endif 397 #ifdef MODINFOMD_DTBP 398 case MODINFOMD_DTBP: 399 sbuf_cat(sbp, "MODINFOMD_DTBP"); 400 break; 401 #endif 402 #ifdef MODINFOMD_EFI_MAP 403 case MODINFOMD_EFI_MAP: 404 sbuf_cat(sbp, "MODINFOMD_EFI_MAP"); 405 break; 406 #endif 407 #ifdef MODINFOMD_EFI_FB 408 case MODINFOMD_EFI_FB: 409 sbuf_cat(sbp, "MODINFOMD_EFI_FB"); 410 break; 411 #endif 412 #ifdef MODINFOMD_MODULEP 413 case MODINFOMD_MODULEP: 414 sbuf_cat(sbp, "MODINFOMD_MODULEP"); 415 break; 416 #endif 417 #ifdef MODINFOMD_VBE_FB 418 case MODINFOMD_VBE_FB: 419 sbuf_cat(sbp, "MODINFOMD_VBE_FB"); 420 break; 421 #endif 422 #ifdef MODINFOMD_FONT 423 case MODINFOMD_FONT: 424 sbuf_cat(sbp, "MODINFOMD_FONT"); 425 break; 426 #endif 427 default: 428 sbuf_cat(sbp, "unrecognized metadata type"); 429 } 430 } 431 432 /* 433 * Print the modinfo value, depending on type. 434 */ 435 static void 436 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len) 437 { 438 #ifdef __LP64__ 439 #define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%016lx", o); 440 #else 441 #define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%08x", o); 442 #endif 443 444 switch (type) { 445 case MODINFO_NAME: 446 case MODINFO_TYPE: 447 case MODINFO_ARGS: 448 sbuf_printf(sbp, "%s", (char *)bptr); 449 break; 450 case MODINFO_SIZE: 451 case MODINFO_METADATA | MODINFOMD_CTORS_SIZE: 452 sbuf_printf(sbp, "%lu", *(u_long *)bptr); 453 break; 454 case MODINFO_ADDR: 455 case MODINFO_METADATA | MODINFOMD_SSYM: 456 case MODINFO_METADATA | MODINFOMD_ESYM: 457 case MODINFO_METADATA | MODINFOMD_DYNAMIC: 458 case MODINFO_METADATA | MODINFOMD_KERNEND: 459 case MODINFO_METADATA | MODINFOMD_ENVP: 460 case MODINFO_METADATA | MODINFOMD_CTORS_ADDR: 461 #ifdef MODINFOMD_SMAP 462 case MODINFO_METADATA | MODINFOMD_SMAP: 463 #endif 464 #ifdef MODINFOMD_SMAP_XATTR 465 case MODINFO_METADATA | MODINFOMD_SMAP_XATTR: 466 #endif 467 #ifdef MODINFOMD_DTBP 468 case MODINFO_METADATA | MODINFOMD_DTBP: 469 #endif 470 #ifdef MODINFOMD_EFI_FB 471 case MODINFO_METADATA | MODINFOMD_EFI_FB: 472 #endif 473 #ifdef MODINFOMD_VBE_FB 474 case MODINFO_METADATA | MODINFOMD_VBE_FB: 475 #endif 476 #ifdef MODINFOMD_FONT 477 case MODINFO_METADATA | MODINFOMD_FONT: 478 #endif 479 sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr); 480 break; 481 case MODINFO_METADATA | MODINFOMD_HOWTO: 482 sbuf_printf(sbp, "0x%08x", *bptr); 483 break; 484 case MODINFO_METADATA | MODINFOMD_SHDR: 485 case MODINFO_METADATA | MODINFOMD_ELFHDR: 486 case MODINFO_METADATA | MODINFOMD_FW_HANDLE: 487 case MODINFO_METADATA | MODINFOMD_KEYBUF: 488 #ifdef MODINFOMD_EFI_MAP 489 case MODINFO_METADATA | MODINFOMD_EFI_MAP: 490 #endif 491 /* Don't print data buffers. */ 492 sbuf_cat(sbp, "buffer contents omitted"); 493 break; 494 default: 495 break; 496 } 497 #undef sbuf_print_vmoffset 498 } 499 500 static void 501 preload_dump_internal(struct sbuf *sbp) 502 { 503 uint32_t *bptr, type, len; 504 505 KASSERT(preload_metadata != NULL, 506 ("%s called without setting up preload_metadata", __func__)); 507 508 /* 509 * Iterate through the TLV-encoded sections. 510 */ 511 bptr = (uint32_t *)preload_metadata; 512 sbuf_putc(sbp, '\n'); 513 while (bptr[0] != MODINFO_END || bptr[1] != MODINFO_END) { 514 sbuf_printf(sbp, " %p:\n", bptr); 515 type = *bptr++; 516 len = *bptr++; 517 518 sbuf_printf(sbp, "\ttype:\t(%#04x) ", type); 519 preload_modinfo_type(sbp, type); 520 sbuf_putc(sbp, '\n'); 521 sbuf_printf(sbp, "\tlen:\t%u\n", len); 522 sbuf_cat(sbp, "\tvalue:\t"); 523 preload_modinfo_value(sbp, bptr, type, len); 524 sbuf_putc(sbp, '\n'); 525 526 bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t); 527 } 528 } 529 530 /* 531 * Print the preloaded data to the console. Called from the machine-dependent 532 * initialization routines, e.g. hammer_time(). 533 */ 534 void 535 preload_dump(void) 536 { 537 char buf[512]; 538 struct sbuf sb; 539 540 /* 541 * This function is expected to be called before malloc is available, 542 * so use a static buffer and struct sbuf. 543 */ 544 sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); 545 sbuf_set_drain(&sb, sbuf_printf_drain, NULL); 546 preload_dump_internal(&sb); 547 548 sbuf_finish(&sb); 549 sbuf_delete(&sb); 550 } 551 552 static int 553 sysctl_preload_dump(SYSCTL_HANDLER_ARGS) 554 { 555 struct sbuf sb; 556 int error; 557 558 if (preload_metadata == NULL) 559 return (EINVAL); 560 561 sbuf_new_for_sysctl(&sb, NULL, 512, req); 562 preload_dump_internal(&sb); 563 564 error = sbuf_finish(&sb); 565 sbuf_delete(&sb); 566 567 return (error); 568 } 569 SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo, 570 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 571 NULL, 0, sysctl_preload_dump, "A", 572 "pretty-print the bootloader metadata"); 573