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