16ba9413bSMike Smith /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 46ba9413bSMike Smith * Copyright (c) 1998 Michael Smith 56ba9413bSMike Smith * All rights reserved. 622e6a670SMitchell Horne * Copyright (c) 2020 NetApp Inc. 722e6a670SMitchell Horne * Copyright (c) 2020 Klara Inc. 86ba9413bSMike Smith * 96ba9413bSMike Smith * Redistribution and use in source and binary forms, with or without 106ba9413bSMike Smith * modification, are permitted provided that the following conditions 116ba9413bSMike Smith * are met: 126ba9413bSMike Smith * 1. Redistributions of source code must retain the above copyright 136ba9413bSMike Smith * notice, this list of conditions and the following disclaimer. 146ba9413bSMike Smith * 2. Redistributions in binary form must reproduce the above copyright 156ba9413bSMike Smith * notice, this list of conditions and the following disclaimer in the 166ba9413bSMike Smith * documentation and/or other materials provided with the distribution. 176ba9413bSMike Smith * 186ba9413bSMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 196ba9413bSMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 206ba9413bSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 216ba9413bSMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 226ba9413bSMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 236ba9413bSMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 246ba9413bSMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 256ba9413bSMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 266ba9413bSMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 276ba9413bSMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 286ba9413bSMike Smith * SUCH DAMAGE. 296ba9413bSMike Smith */ 306ba9413bSMike Smith 316ba9413bSMike Smith #include <sys/param.h> 326ba9413bSMike Smith #include <sys/systm.h> 336ba9413bSMike Smith #include <sys/linker.h> 3422e6a670SMitchell Horne #include <sys/sbuf.h> 3522e6a670SMitchell Horne #include <sys/sysctl.h> 3622e6a670SMitchell Horne 3722e6a670SMitchell Horne #include <machine/metadata.h> 386ba9413bSMike Smith 39483f692eSMark Johnston #include <vm/vm.h> 40483f692eSMark Johnston #include <vm/vm_extern.h> 41483f692eSMark Johnston 426ba9413bSMike Smith /* 436ba9413bSMike Smith * Preloaded module support 446ba9413bSMike Smith */ 456ba9413bSMike Smith 46278e7970SMarcel Moolenaar vm_offset_t preload_addr_relocate = 0; 47*b72ae900SAhmad Khalifa caddr_t preload_metadata, preload_kmdp; 48*b72ae900SAhmad Khalifa 49*b72ae900SAhmad Khalifa void 50*b72ae900SAhmad Khalifa preload_initkmdp(bool fatal) 51*b72ae900SAhmad Khalifa { 52*b72ae900SAhmad Khalifa preload_kmdp = preload_search_by_type("elf kernel"); 53*b72ae900SAhmad Khalifa 54*b72ae900SAhmad Khalifa if (preload_kmdp == NULL && fatal) 55*b72ae900SAhmad Khalifa panic("unable to find kernel metadata"); 56*b72ae900SAhmad Khalifa } 576ba9413bSMike Smith 586ba9413bSMike Smith /* 596ba9413bSMike Smith * Search for the preloaded module (name) 606ba9413bSMike Smith */ 616ba9413bSMike Smith caddr_t 62e4f1a52fSPeter Wemm preload_search_by_name(const char *name) 636ba9413bSMike Smith { 646ba9413bSMike Smith caddr_t curp; 6560ae52f7SEd Schouten uint32_t *hdr; 66e4f1a52fSPeter Wemm int next; 676ba9413bSMike Smith 68e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 69e4f1a52fSPeter Wemm curp = preload_metadata; 706ba9413bSMike Smith for (;;) { 7160ae52f7SEd Schouten hdr = (uint32_t *)curp; 72e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 736ba9413bSMike Smith break; 746ba9413bSMike Smith 756ba9413bSMike Smith /* Search for a MODINFO_NAME field */ 766ba9413bSMike Smith if ((hdr[0] == MODINFO_NAME) && 7760ae52f7SEd Schouten !strcmp(name, curp + sizeof(uint32_t) * 2)) 786ba9413bSMike Smith return(curp); 796ba9413bSMike Smith 806ba9413bSMike Smith /* skip to next field */ 8160ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 822a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 83e4f1a52fSPeter Wemm curp += next; 846ba9413bSMike Smith } 856ba9413bSMike Smith } 866ba9413bSMike Smith return(NULL); 876ba9413bSMike Smith } 886ba9413bSMike Smith 896ba9413bSMike Smith /* 906ba9413bSMike Smith * Search for the first preloaded module of (type) 916ba9413bSMike Smith */ 926ba9413bSMike Smith caddr_t 93e4f1a52fSPeter Wemm preload_search_by_type(const char *type) 946ba9413bSMike Smith { 956ba9413bSMike Smith caddr_t curp, lname; 9660ae52f7SEd Schouten uint32_t *hdr; 97e4f1a52fSPeter Wemm int next; 986ba9413bSMike Smith 99e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 100e4f1a52fSPeter Wemm curp = preload_metadata; 1016ba9413bSMike Smith lname = NULL; 1026ba9413bSMike Smith for (;;) { 10360ae52f7SEd Schouten hdr = (uint32_t *)curp; 104e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 1056ba9413bSMike Smith break; 1066ba9413bSMike Smith 1076ba9413bSMike Smith /* remember the start of each record */ 1086ba9413bSMike Smith if (hdr[0] == MODINFO_NAME) 1096ba9413bSMike Smith lname = curp; 1106ba9413bSMike Smith 1116ba9413bSMike Smith /* Search for a MODINFO_TYPE field */ 1126ba9413bSMike Smith if ((hdr[0] == MODINFO_TYPE) && 11360ae52f7SEd Schouten !strcmp(type, curp + sizeof(uint32_t) * 2)) 1146ba9413bSMike Smith return(lname); 1156ba9413bSMike Smith 1166ba9413bSMike Smith /* skip to next field */ 11760ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 1182a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 119e4f1a52fSPeter Wemm curp += next; 120e4f1a52fSPeter Wemm } 121e4f1a52fSPeter Wemm } 122e4f1a52fSPeter Wemm return(NULL); 123e4f1a52fSPeter Wemm } 124e4f1a52fSPeter Wemm 125e4f1a52fSPeter Wemm /* 126e4f1a52fSPeter Wemm * Walk through the preloaded module list 127e4f1a52fSPeter Wemm */ 128e4f1a52fSPeter Wemm caddr_t 129e4f1a52fSPeter Wemm preload_search_next_name(caddr_t base) 130e4f1a52fSPeter Wemm { 131e4f1a52fSPeter Wemm caddr_t curp; 13260ae52f7SEd Schouten uint32_t *hdr; 133e4f1a52fSPeter Wemm int next; 134e4f1a52fSPeter Wemm 135e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 136e4f1a52fSPeter Wemm /* Pick up where we left off last time */ 137e4f1a52fSPeter Wemm if (base) { 138e4f1a52fSPeter Wemm /* skip to next field */ 139e4f1a52fSPeter Wemm curp = base; 14060ae52f7SEd Schouten hdr = (uint32_t *)curp; 14160ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 1422a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 143e4f1a52fSPeter Wemm curp += next; 144e4f1a52fSPeter Wemm } else 145e4f1a52fSPeter Wemm curp = preload_metadata; 146e4f1a52fSPeter Wemm 147e4f1a52fSPeter Wemm for (;;) { 14860ae52f7SEd Schouten hdr = (uint32_t *)curp; 149e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 150e4f1a52fSPeter Wemm break; 151e4f1a52fSPeter Wemm 152e4f1a52fSPeter Wemm /* Found a new record? */ 153e4f1a52fSPeter Wemm if (hdr[0] == MODINFO_NAME) 154e4f1a52fSPeter Wemm return curp; 155e4f1a52fSPeter Wemm 156e4f1a52fSPeter Wemm /* skip to next field */ 15760ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 1582a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 159e4f1a52fSPeter Wemm curp += next; 1606ba9413bSMike Smith } 1616ba9413bSMike Smith } 1626ba9413bSMike Smith return(NULL); 1636ba9413bSMike Smith } 1646ba9413bSMike Smith 1656ba9413bSMike Smith /* 1666ba9413bSMike Smith * Given a preloaded module handle (mod), return a pointer 1676ba9413bSMike Smith * to the data for the attribute (inf). 1686ba9413bSMike Smith */ 1696ba9413bSMike Smith caddr_t 170e4f1a52fSPeter Wemm preload_search_info(caddr_t mod, int inf) 1716ba9413bSMike Smith { 1726ba9413bSMike Smith caddr_t curp; 17360ae52f7SEd Schouten uint32_t *hdr; 17460ae52f7SEd Schouten uint32_t type = 0; 175e4f1a52fSPeter Wemm int next; 1766ba9413bSMike Smith 177e8234cfeSRoger Pau Monné if (mod == NULL) 178e8234cfeSRoger Pau Monné return (NULL); 179e8234cfeSRoger Pau Monné 1806ba9413bSMike Smith curp = mod; 1816ba9413bSMike Smith for (;;) { 18260ae52f7SEd Schouten hdr = (uint32_t *)curp; 1836ba9413bSMike Smith /* end of module data? */ 184e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 1856ba9413bSMike Smith break; 1866ba9413bSMike Smith /* 1876ba9413bSMike Smith * We give up once we've looped back to what we were looking at 1886ba9413bSMike Smith * first - this should normally be a MODINFO_NAME field. 1896ba9413bSMike Smith */ 1906ba9413bSMike Smith if (type == 0) { 1916ba9413bSMike Smith type = hdr[0]; 1926ba9413bSMike Smith } else { 1936ba9413bSMike Smith if (hdr[0] == type) 1946ba9413bSMike Smith break; 1956ba9413bSMike Smith } 1966ba9413bSMike Smith 1976ba9413bSMike Smith /* 1986ba9413bSMike Smith * Attribute match? Return pointer to data. 199d7d97eb0SJeroen Ruigrok van der Werven * Consumer may safely assume that size value precedes 2006ba9413bSMike Smith * data. 2016ba9413bSMike Smith */ 2026ba9413bSMike Smith if (hdr[0] == inf) 20360ae52f7SEd Schouten return(curp + (sizeof(uint32_t) * 2)); 2046ba9413bSMike Smith 2056ba9413bSMike Smith /* skip to next field */ 20660ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 2072a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 208e4f1a52fSPeter Wemm curp += next; 2096ba9413bSMike Smith } 2106ba9413bSMike Smith return(NULL); 2116ba9413bSMike Smith } 2126ba9413bSMike Smith 213e4f1a52fSPeter Wemm /* 214e4f1a52fSPeter Wemm * Delete a preload record by name. 215e4f1a52fSPeter Wemm */ 216e4f1a52fSPeter Wemm void 217e4f1a52fSPeter Wemm preload_delete_name(const char *name) 218e4f1a52fSPeter Wemm { 219483f692eSMark Johnston caddr_t addr, curp; 220483f692eSMark Johnston uint32_t *hdr, sz; 221e4f1a52fSPeter Wemm int next; 222e4f1a52fSPeter Wemm int clearing; 223e4f1a52fSPeter Wemm 224483f692eSMark Johnston addr = 0; 225483f692eSMark Johnston sz = 0; 226483f692eSMark Johnston 227e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 228e4f1a52fSPeter Wemm clearing = 0; 229e4f1a52fSPeter Wemm curp = preload_metadata; 230e4f1a52fSPeter Wemm for (;;) { 23160ae52f7SEd Schouten hdr = (uint32_t *)curp; 232483f692eSMark Johnston if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) { 233483f692eSMark Johnston /* Free memory used to store the file. */ 234483f692eSMark Johnston if (addr != 0 && sz != 0) 235483f692eSMark Johnston kmem_bootstrap_free((vm_offset_t)addr, sz); 236483f692eSMark Johnston addr = 0; 237483f692eSMark Johnston sz = 0; 238e4f1a52fSPeter Wemm 239483f692eSMark Johnston if (hdr[0] == 0) 240483f692eSMark Johnston break; 24160ae52f7SEd Schouten if (!strcmp(name, curp + sizeof(uint32_t) * 2)) 242e4f1a52fSPeter Wemm clearing = 1; /* got it, start clearing */ 243483f692eSMark Johnston else if (clearing) { 244e4f1a52fSPeter Wemm clearing = 0; /* at next one now.. better stop */ 245e4f1a52fSPeter Wemm } 246483f692eSMark Johnston } 247483f692eSMark Johnston if (clearing) { 248483f692eSMark Johnston if (hdr[0] == MODINFO_ADDR) 249483f692eSMark Johnston addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2); 250483f692eSMark Johnston else if (hdr[0] == MODINFO_SIZE) 251483f692eSMark Johnston sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2); 252e4f1a52fSPeter Wemm hdr[0] = MODINFO_EMPTY; 253483f692eSMark Johnston } 254e4f1a52fSPeter Wemm 255e4f1a52fSPeter Wemm /* skip to next field */ 25660ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 2572a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 258e4f1a52fSPeter Wemm curp += next; 259e4f1a52fSPeter Wemm } 260e4f1a52fSPeter Wemm } 261e4f1a52fSPeter Wemm } 262e4f1a52fSPeter Wemm 263278e7970SMarcel Moolenaar void * 264278e7970SMarcel Moolenaar preload_fetch_addr(caddr_t mod) 265278e7970SMarcel Moolenaar { 266278e7970SMarcel Moolenaar caddr_t *mdp; 267278e7970SMarcel Moolenaar 268278e7970SMarcel Moolenaar mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR); 269278e7970SMarcel Moolenaar if (mdp == NULL) 270278e7970SMarcel Moolenaar return (NULL); 271278e7970SMarcel Moolenaar return (*mdp + preload_addr_relocate); 272278e7970SMarcel Moolenaar } 273278e7970SMarcel Moolenaar 274278e7970SMarcel Moolenaar size_t 275278e7970SMarcel Moolenaar preload_fetch_size(caddr_t mod) 276278e7970SMarcel Moolenaar { 277278e7970SMarcel Moolenaar size_t *mdp; 278278e7970SMarcel Moolenaar 279278e7970SMarcel Moolenaar mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE); 280278e7970SMarcel Moolenaar if (mdp == NULL) 281278e7970SMarcel Moolenaar return (0); 282278e7970SMarcel Moolenaar return (*mdp); 283278e7970SMarcel Moolenaar } 284278e7970SMarcel Moolenaar 28512d7eaa0SWarner Losh /* Called from locore. Convert physical pointers to kvm. Sigh. */ 286e4f1a52fSPeter Wemm void 287e4f1a52fSPeter Wemm preload_bootstrap_relocate(vm_offset_t offset) 288e4f1a52fSPeter Wemm { 289e4f1a52fSPeter Wemm caddr_t curp; 29060ae52f7SEd Schouten uint32_t *hdr; 291e4f1a52fSPeter Wemm vm_offset_t *ptr; 292e4f1a52fSPeter Wemm int next; 293e4f1a52fSPeter Wemm 294e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 295e4f1a52fSPeter Wemm curp = preload_metadata; 296e4f1a52fSPeter Wemm for (;;) { 29760ae52f7SEd Schouten hdr = (uint32_t *)curp; 298e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 299e4f1a52fSPeter Wemm break; 300e4f1a52fSPeter Wemm 3012da2eeacSPeter Wemm /* Deal with the ones that we know we have to fix */ 3022da2eeacSPeter Wemm switch (hdr[0]) { 3032da2eeacSPeter Wemm case MODINFO_ADDR: 30493b18e37SToomas Soome case MODINFO_METADATA|MODINFOMD_FONT: 305966e53a4SEmmanuel Vadot case MODINFO_METADATA|MODINFOMD_SPLASH: 3062da2eeacSPeter Wemm case MODINFO_METADATA|MODINFOMD_SSYM: 3072da2eeacSPeter Wemm case MODINFO_METADATA|MODINFOMD_ESYM: 30860ae52f7SEd Schouten ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); 309e4f1a52fSPeter Wemm *ptr += offset; 3102da2eeacSPeter Wemm break; 311e4f1a52fSPeter Wemm } 312e4f1a52fSPeter Wemm /* The rest is beyond us for now */ 313e4f1a52fSPeter Wemm 314e4f1a52fSPeter Wemm /* skip to next field */ 31560ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 3162a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 317e4f1a52fSPeter Wemm curp += next; 318e4f1a52fSPeter Wemm } 319e4f1a52fSPeter Wemm } 320e4f1a52fSPeter Wemm } 32122e6a670SMitchell Horne 32222e6a670SMitchell Horne /* 32322e6a670SMitchell Horne * Parse the modinfo type and append to the provided sbuf. 32422e6a670SMitchell Horne */ 32522e6a670SMitchell Horne static void 32622e6a670SMitchell Horne preload_modinfo_type(struct sbuf *sbp, int type) 32722e6a670SMitchell Horne { 32822e6a670SMitchell Horne 32922e6a670SMitchell Horne if ((type & MODINFO_METADATA) == 0) { 33022e6a670SMitchell Horne switch (type) { 33122e6a670SMitchell Horne case MODINFO_END: 33222e6a670SMitchell Horne sbuf_cat(sbp, "MODINFO_END"); 33322e6a670SMitchell Horne break; 33422e6a670SMitchell Horne case MODINFO_NAME: 33522e6a670SMitchell Horne sbuf_cat(sbp, "MODINFO_NAME"); 33622e6a670SMitchell Horne break; 33722e6a670SMitchell Horne case MODINFO_TYPE: 33822e6a670SMitchell Horne sbuf_cat(sbp, "MODINFO_TYPE"); 33922e6a670SMitchell Horne break; 34022e6a670SMitchell Horne case MODINFO_ADDR: 34122e6a670SMitchell Horne sbuf_cat(sbp, "MODINFO_ADDR"); 34222e6a670SMitchell Horne break; 34322e6a670SMitchell Horne case MODINFO_SIZE: 34422e6a670SMitchell Horne sbuf_cat(sbp, "MODINFO_SIZE"); 34522e6a670SMitchell Horne break; 34622e6a670SMitchell Horne case MODINFO_EMPTY: 34722e6a670SMitchell Horne sbuf_cat(sbp, "MODINFO_EMPTY"); 34822e6a670SMitchell Horne break; 34922e6a670SMitchell Horne case MODINFO_ARGS: 35022e6a670SMitchell Horne sbuf_cat(sbp, "MODINFO_ARGS"); 35122e6a670SMitchell Horne break; 35222e6a670SMitchell Horne default: 35322e6a670SMitchell Horne sbuf_cat(sbp, "unrecognized modinfo attribute"); 35422e6a670SMitchell Horne } 35522e6a670SMitchell Horne 35622e6a670SMitchell Horne return; 35722e6a670SMitchell Horne } 35822e6a670SMitchell Horne 35922e6a670SMitchell Horne sbuf_cat(sbp, "MODINFO_METADATA | "); 36022e6a670SMitchell Horne switch (type & ~MODINFO_METADATA) { 36122e6a670SMitchell Horne case MODINFOMD_ELFHDR: 36222e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_ELFHDR"); 36322e6a670SMitchell Horne break; 36422e6a670SMitchell Horne case MODINFOMD_SSYM: 36522e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_SSYM"); 36622e6a670SMitchell Horne break; 36722e6a670SMitchell Horne case MODINFOMD_ESYM: 36822e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_ESYM"); 36922e6a670SMitchell Horne break; 37022e6a670SMitchell Horne case MODINFOMD_DYNAMIC: 37122e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_DYNAMIC"); 37222e6a670SMitchell Horne break; 37322e6a670SMitchell Horne case MODINFOMD_ENVP: 37422e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_ENVP"); 37522e6a670SMitchell Horne break; 37622e6a670SMitchell Horne case MODINFOMD_HOWTO: 37722e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_HOWTO"); 37822e6a670SMitchell Horne break; 37922e6a670SMitchell Horne case MODINFOMD_KERNEND: 38022e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_KERNEND"); 38122e6a670SMitchell Horne break; 38222e6a670SMitchell Horne case MODINFOMD_SHDR: 38322e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_SHDR"); 38422e6a670SMitchell Horne break; 38522e6a670SMitchell Horne case MODINFOMD_CTORS_ADDR: 38622e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR"); 38722e6a670SMitchell Horne break; 38822e6a670SMitchell Horne case MODINFOMD_CTORS_SIZE: 38922e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE"); 39022e6a670SMitchell Horne break; 39122e6a670SMitchell Horne case MODINFOMD_FW_HANDLE: 39222e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_FW_HANDLE"); 39322e6a670SMitchell Horne break; 39422e6a670SMitchell Horne case MODINFOMD_KEYBUF: 39522e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_KEYBUF"); 39622e6a670SMitchell Horne break; 39722e6a670SMitchell Horne #ifdef MODINFOMD_SMAP 39822e6a670SMitchell Horne case MODINFOMD_SMAP: 39922e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_SMAP"); 40022e6a670SMitchell Horne break; 40122e6a670SMitchell Horne #endif 40222e6a670SMitchell Horne #ifdef MODINFOMD_SMAP_XATTR 40322e6a670SMitchell Horne case MODINFOMD_SMAP_XATTR: 40422e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR"); 40522e6a670SMitchell Horne break; 40622e6a670SMitchell Horne #endif 40722e6a670SMitchell Horne #ifdef MODINFOMD_DTBP 40822e6a670SMitchell Horne case MODINFOMD_DTBP: 40922e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_DTBP"); 41022e6a670SMitchell Horne break; 41122e6a670SMitchell Horne #endif 41222e6a670SMitchell Horne #ifdef MODINFOMD_EFI_MAP 41322e6a670SMitchell Horne case MODINFOMD_EFI_MAP: 41422e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_EFI_MAP"); 41522e6a670SMitchell Horne break; 41622e6a670SMitchell Horne #endif 41722e6a670SMitchell Horne #ifdef MODINFOMD_EFI_FB 41822e6a670SMitchell Horne case MODINFOMD_EFI_FB: 41922e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_EFI_FB"); 42022e6a670SMitchell Horne break; 42122e6a670SMitchell Horne #endif 42222e6a670SMitchell Horne #ifdef MODINFOMD_MODULEP 42322e6a670SMitchell Horne case MODINFOMD_MODULEP: 42422e6a670SMitchell Horne sbuf_cat(sbp, "MODINFOMD_MODULEP"); 42522e6a670SMitchell Horne break; 42622e6a670SMitchell Horne #endif 427a4a10b37SToomas Soome #ifdef MODINFOMD_VBE_FB 428a4a10b37SToomas Soome case MODINFOMD_VBE_FB: 429a4a10b37SToomas Soome sbuf_cat(sbp, "MODINFOMD_VBE_FB"); 430a4a10b37SToomas Soome break; 431a4a10b37SToomas Soome #endif 432742653ebSToomas Soome #ifdef MODINFOMD_FONT 433742653ebSToomas Soome case MODINFOMD_FONT: 434742653ebSToomas Soome sbuf_cat(sbp, "MODINFOMD_FONT"); 435742653ebSToomas Soome break; 436742653ebSToomas Soome #endif 437966e53a4SEmmanuel Vadot #ifdef MODINFOMD_SPLASH 438966e53a4SEmmanuel Vadot case MODINFOMD_SPLASH: 439966e53a4SEmmanuel Vadot sbuf_cat(sbp, "MODINFOMD_SPLASH"); 440966e53a4SEmmanuel Vadot break; 441966e53a4SEmmanuel Vadot #endif 44222e6a670SMitchell Horne default: 44322e6a670SMitchell Horne sbuf_cat(sbp, "unrecognized metadata type"); 44422e6a670SMitchell Horne } 44522e6a670SMitchell Horne } 44622e6a670SMitchell Horne 44722e6a670SMitchell Horne /* 44822e6a670SMitchell Horne * Print the modinfo value, depending on type. 44922e6a670SMitchell Horne */ 45022e6a670SMitchell Horne static void 45122e6a670SMitchell Horne preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len) 45222e6a670SMitchell Horne { 45322e6a670SMitchell Horne #ifdef __LP64__ 45422e6a670SMitchell Horne #define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%016lx", o); 45522e6a670SMitchell Horne #else 45622e6a670SMitchell Horne #define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%08x", o); 45722e6a670SMitchell Horne #endif 45822e6a670SMitchell Horne 45922e6a670SMitchell Horne switch (type) { 46022e6a670SMitchell Horne case MODINFO_NAME: 46122e6a670SMitchell Horne case MODINFO_TYPE: 46222e6a670SMitchell Horne case MODINFO_ARGS: 46322e6a670SMitchell Horne sbuf_printf(sbp, "%s", (char *)bptr); 46422e6a670SMitchell Horne break; 46522e6a670SMitchell Horne case MODINFO_SIZE: 46622e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_CTORS_SIZE: 46722e6a670SMitchell Horne sbuf_printf(sbp, "%lu", *(u_long *)bptr); 46822e6a670SMitchell Horne break; 46922e6a670SMitchell Horne case MODINFO_ADDR: 47022e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_SSYM: 47122e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_ESYM: 47222e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_DYNAMIC: 47322e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_KERNEND: 47422e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_ENVP: 47522e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_CTORS_ADDR: 47622e6a670SMitchell Horne #ifdef MODINFOMD_SMAP 47722e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_SMAP: 47822e6a670SMitchell Horne #endif 47922e6a670SMitchell Horne #ifdef MODINFOMD_SMAP_XATTR 48022e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_SMAP_XATTR: 48122e6a670SMitchell Horne #endif 48222e6a670SMitchell Horne #ifdef MODINFOMD_DTBP 48322e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_DTBP: 48422e6a670SMitchell Horne #endif 48522e6a670SMitchell Horne #ifdef MODINFOMD_EFI_FB 48622e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_EFI_FB: 48722e6a670SMitchell Horne #endif 488a4a10b37SToomas Soome #ifdef MODINFOMD_VBE_FB 489a4a10b37SToomas Soome case MODINFO_METADATA | MODINFOMD_VBE_FB: 490a4a10b37SToomas Soome #endif 491742653ebSToomas Soome #ifdef MODINFOMD_FONT 492742653ebSToomas Soome case MODINFO_METADATA | MODINFOMD_FONT: 493742653ebSToomas Soome #endif 494966e53a4SEmmanuel Vadot #ifdef MODINFOMD_SPLASH 495966e53a4SEmmanuel Vadot case MODINFO_METADATA | MODINFOMD_SPLASH: 496966e53a4SEmmanuel Vadot #endif 49722e6a670SMitchell Horne sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr); 49822e6a670SMitchell Horne break; 49922e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_HOWTO: 50022e6a670SMitchell Horne sbuf_printf(sbp, "0x%08x", *bptr); 50122e6a670SMitchell Horne break; 50222e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_SHDR: 50322e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_ELFHDR: 50422e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_FW_HANDLE: 50522e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_KEYBUF: 50622e6a670SMitchell Horne #ifdef MODINFOMD_EFI_MAP 50722e6a670SMitchell Horne case MODINFO_METADATA | MODINFOMD_EFI_MAP: 50822e6a670SMitchell Horne #endif 50922e6a670SMitchell Horne /* Don't print data buffers. */ 51022e6a670SMitchell Horne sbuf_cat(sbp, "buffer contents omitted"); 51122e6a670SMitchell Horne break; 51222e6a670SMitchell Horne default: 51322e6a670SMitchell Horne break; 51422e6a670SMitchell Horne } 51522e6a670SMitchell Horne #undef sbuf_print_vmoffset 51622e6a670SMitchell Horne } 51722e6a670SMitchell Horne 51822e6a670SMitchell Horne static void 51922e6a670SMitchell Horne preload_dump_internal(struct sbuf *sbp) 52022e6a670SMitchell Horne { 52122e6a670SMitchell Horne uint32_t *bptr, type, len; 52222e6a670SMitchell Horne 52322e6a670SMitchell Horne KASSERT(preload_metadata != NULL, 52422e6a670SMitchell Horne ("%s called without setting up preload_metadata", __func__)); 52522e6a670SMitchell Horne 52622e6a670SMitchell Horne /* 52722e6a670SMitchell Horne * Iterate through the TLV-encoded sections. 52822e6a670SMitchell Horne */ 52922e6a670SMitchell Horne bptr = (uint32_t *)preload_metadata; 53022e6a670SMitchell Horne sbuf_putc(sbp, '\n'); 531841dad02SMitchell Horne while (bptr[0] != MODINFO_END || bptr[1] != MODINFO_END) { 53222e6a670SMitchell Horne sbuf_printf(sbp, " %p:\n", bptr); 53322e6a670SMitchell Horne type = *bptr++; 53422e6a670SMitchell Horne len = *bptr++; 53522e6a670SMitchell Horne 53622e6a670SMitchell Horne sbuf_printf(sbp, "\ttype:\t(%#04x) ", type); 53722e6a670SMitchell Horne preload_modinfo_type(sbp, type); 53822e6a670SMitchell Horne sbuf_putc(sbp, '\n'); 53922e6a670SMitchell Horne sbuf_printf(sbp, "\tlen:\t%u\n", len); 54022e6a670SMitchell Horne sbuf_cat(sbp, "\tvalue:\t"); 54122e6a670SMitchell Horne preload_modinfo_value(sbp, bptr, type, len); 54222e6a670SMitchell Horne sbuf_putc(sbp, '\n'); 54322e6a670SMitchell Horne 54422e6a670SMitchell Horne bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t); 54522e6a670SMitchell Horne } 54622e6a670SMitchell Horne } 54722e6a670SMitchell Horne 54822e6a670SMitchell Horne /* 54922e6a670SMitchell Horne * Print the preloaded data to the console. Called from the machine-dependent 55022e6a670SMitchell Horne * initialization routines, e.g. hammer_time(). 55122e6a670SMitchell Horne */ 55222e6a670SMitchell Horne void 55322e6a670SMitchell Horne preload_dump(void) 55422e6a670SMitchell Horne { 55522e6a670SMitchell Horne char buf[512]; 55622e6a670SMitchell Horne struct sbuf sb; 55722e6a670SMitchell Horne 55822e6a670SMitchell Horne /* 55922e6a670SMitchell Horne * This function is expected to be called before malloc is available, 56022e6a670SMitchell Horne * so use a static buffer and struct sbuf. 56122e6a670SMitchell Horne */ 56222e6a670SMitchell Horne sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); 56322e6a670SMitchell Horne sbuf_set_drain(&sb, sbuf_printf_drain, NULL); 56422e6a670SMitchell Horne preload_dump_internal(&sb); 56522e6a670SMitchell Horne 56622e6a670SMitchell Horne sbuf_finish(&sb); 56722e6a670SMitchell Horne sbuf_delete(&sb); 56822e6a670SMitchell Horne } 56922e6a670SMitchell Horne 57022e6a670SMitchell Horne static int 57122e6a670SMitchell Horne sysctl_preload_dump(SYSCTL_HANDLER_ARGS) 57222e6a670SMitchell Horne { 57322e6a670SMitchell Horne struct sbuf sb; 57422e6a670SMitchell Horne int error; 57522e6a670SMitchell Horne 57622e6a670SMitchell Horne if (preload_metadata == NULL) 57722e6a670SMitchell Horne return (EINVAL); 57822e6a670SMitchell Horne 57922e6a670SMitchell Horne sbuf_new_for_sysctl(&sb, NULL, 512, req); 58022e6a670SMitchell Horne preload_dump_internal(&sb); 58122e6a670SMitchell Horne 58222e6a670SMitchell Horne error = sbuf_finish(&sb); 58322e6a670SMitchell Horne sbuf_delete(&sb); 58422e6a670SMitchell Horne 58522e6a670SMitchell Horne return (error); 58622e6a670SMitchell Horne } 58722e6a670SMitchell Horne SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo, 58822e6a670SMitchell Horne CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 58922e6a670SMitchell Horne NULL, 0, sysctl_preload_dump, "A", 59022e6a670SMitchell Horne "pretty-print the bootloader metadata"); 591