16ba9413bSMike Smith /*- 26ba9413bSMike Smith * Copyright (c) 1998 Michael Smith 36ba9413bSMike Smith * All rights reserved. 46ba9413bSMike Smith * 56ba9413bSMike Smith * Redistribution and use in source and binary forms, with or without 66ba9413bSMike Smith * modification, are permitted provided that the following conditions 76ba9413bSMike Smith * are met: 86ba9413bSMike Smith * 1. Redistributions of source code must retain the above copyright 96ba9413bSMike Smith * notice, this list of conditions and the following disclaimer. 106ba9413bSMike Smith * 2. Redistributions in binary form must reproduce the above copyright 116ba9413bSMike Smith * notice, this list of conditions and the following disclaimer in the 126ba9413bSMike Smith * documentation and/or other materials provided with the distribution. 136ba9413bSMike Smith * 146ba9413bSMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 156ba9413bSMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 166ba9413bSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 176ba9413bSMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 186ba9413bSMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 196ba9413bSMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 206ba9413bSMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 216ba9413bSMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 226ba9413bSMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 236ba9413bSMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 246ba9413bSMike Smith * SUCH DAMAGE. 256ba9413bSMike Smith */ 266ba9413bSMike Smith 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 306ba9413bSMike Smith #include <sys/param.h> 316ba9413bSMike Smith #include <sys/systm.h> 326ba9413bSMike Smith #include <sys/linker.h> 336ba9413bSMike Smith 346ba9413bSMike Smith /* 356ba9413bSMike Smith * Preloaded module support 366ba9413bSMike Smith */ 376ba9413bSMike Smith 38278e7970SMarcel Moolenaar vm_offset_t preload_addr_relocate = 0; 39e4f1a52fSPeter Wemm caddr_t preload_metadata; 406ba9413bSMike Smith 416ba9413bSMike Smith /* 426ba9413bSMike Smith * Search for the preloaded module (name) 436ba9413bSMike Smith */ 446ba9413bSMike Smith caddr_t 45e4f1a52fSPeter Wemm preload_search_by_name(const char *name) 466ba9413bSMike Smith { 476ba9413bSMike Smith caddr_t curp; 4860ae52f7SEd Schouten uint32_t *hdr; 49e4f1a52fSPeter Wemm int next; 506ba9413bSMike Smith 51e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 526ba9413bSMike Smith 53e4f1a52fSPeter Wemm curp = preload_metadata; 546ba9413bSMike Smith for (;;) { 5560ae52f7SEd Schouten hdr = (uint32_t *)curp; 56e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 576ba9413bSMike Smith break; 586ba9413bSMike Smith 596ba9413bSMike Smith /* Search for a MODINFO_NAME field */ 606ba9413bSMike Smith if ((hdr[0] == MODINFO_NAME) && 6160ae52f7SEd Schouten !strcmp(name, curp + sizeof(uint32_t) * 2)) 626ba9413bSMike Smith return(curp); 636ba9413bSMike Smith 646ba9413bSMike Smith /* skip to next field */ 6560ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 662a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 67e4f1a52fSPeter Wemm curp += next; 686ba9413bSMike Smith } 696ba9413bSMike Smith } 706ba9413bSMike Smith return(NULL); 716ba9413bSMike Smith } 726ba9413bSMike Smith 736ba9413bSMike Smith /* 746ba9413bSMike Smith * Search for the first preloaded module of (type) 756ba9413bSMike Smith */ 766ba9413bSMike Smith caddr_t 77e4f1a52fSPeter Wemm preload_search_by_type(const char *type) 786ba9413bSMike Smith { 796ba9413bSMike Smith caddr_t curp, lname; 8060ae52f7SEd Schouten uint32_t *hdr; 81e4f1a52fSPeter Wemm int next; 826ba9413bSMike Smith 83e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 846ba9413bSMike Smith 85e4f1a52fSPeter Wemm curp = preload_metadata; 866ba9413bSMike Smith lname = NULL; 876ba9413bSMike Smith for (;;) { 8860ae52f7SEd Schouten hdr = (uint32_t *)curp; 89e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 906ba9413bSMike Smith break; 916ba9413bSMike Smith 926ba9413bSMike Smith /* remember the start of each record */ 936ba9413bSMike Smith if (hdr[0] == MODINFO_NAME) 946ba9413bSMike Smith lname = curp; 956ba9413bSMike Smith 966ba9413bSMike Smith /* Search for a MODINFO_TYPE field */ 976ba9413bSMike Smith if ((hdr[0] == MODINFO_TYPE) && 9860ae52f7SEd Schouten !strcmp(type, curp + sizeof(uint32_t) * 2)) 996ba9413bSMike Smith return(lname); 1006ba9413bSMike Smith 1016ba9413bSMike Smith /* skip to next field */ 10260ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 1032a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 104e4f1a52fSPeter Wemm curp += next; 105e4f1a52fSPeter Wemm } 106e4f1a52fSPeter Wemm } 107e4f1a52fSPeter Wemm return(NULL); 108e4f1a52fSPeter Wemm } 109e4f1a52fSPeter Wemm 110e4f1a52fSPeter Wemm /* 111e4f1a52fSPeter Wemm * Walk through the preloaded module list 112e4f1a52fSPeter Wemm */ 113e4f1a52fSPeter Wemm caddr_t 114e4f1a52fSPeter Wemm preload_search_next_name(caddr_t base) 115e4f1a52fSPeter Wemm { 116e4f1a52fSPeter Wemm caddr_t curp; 11760ae52f7SEd Schouten uint32_t *hdr; 118e4f1a52fSPeter Wemm int next; 119e4f1a52fSPeter Wemm 120e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 121e4f1a52fSPeter Wemm 122e4f1a52fSPeter Wemm /* Pick up where we left off last time */ 123e4f1a52fSPeter Wemm if (base) { 124e4f1a52fSPeter Wemm /* skip to next field */ 125e4f1a52fSPeter Wemm curp = base; 12660ae52f7SEd Schouten hdr = (uint32_t *)curp; 12760ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 1282a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 129e4f1a52fSPeter Wemm curp += next; 130e4f1a52fSPeter Wemm } else 131e4f1a52fSPeter Wemm curp = preload_metadata; 132e4f1a52fSPeter Wemm 133e4f1a52fSPeter Wemm for (;;) { 13460ae52f7SEd Schouten hdr = (uint32_t *)curp; 135e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 136e4f1a52fSPeter Wemm break; 137e4f1a52fSPeter Wemm 138e4f1a52fSPeter Wemm /* Found a new record? */ 139e4f1a52fSPeter Wemm if (hdr[0] == MODINFO_NAME) 140e4f1a52fSPeter Wemm return curp; 141e4f1a52fSPeter Wemm 142e4f1a52fSPeter Wemm /* skip to next field */ 14360ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 1442a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 145e4f1a52fSPeter Wemm curp += next; 1466ba9413bSMike Smith } 1476ba9413bSMike Smith } 1486ba9413bSMike Smith return(NULL); 1496ba9413bSMike Smith } 1506ba9413bSMike Smith 1516ba9413bSMike Smith /* 1526ba9413bSMike Smith * Given a preloaded module handle (mod), return a pointer 1536ba9413bSMike Smith * to the data for the attribute (inf). 1546ba9413bSMike Smith */ 1556ba9413bSMike Smith caddr_t 156e4f1a52fSPeter Wemm preload_search_info(caddr_t mod, int inf) 1576ba9413bSMike Smith { 1586ba9413bSMike Smith caddr_t curp; 15960ae52f7SEd Schouten uint32_t *hdr; 16060ae52f7SEd Schouten uint32_t type = 0; 161e4f1a52fSPeter Wemm int next; 1626ba9413bSMike Smith 163*e8234cfeSRoger Pau Monné if (mod == NULL) 164*e8234cfeSRoger Pau Monné return (NULL); 165*e8234cfeSRoger Pau Monné 1666ba9413bSMike Smith curp = mod; 1676ba9413bSMike Smith for (;;) { 16860ae52f7SEd Schouten hdr = (uint32_t *)curp; 1696ba9413bSMike Smith /* end of module data? */ 170e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 1716ba9413bSMike Smith break; 1726ba9413bSMike Smith /* 1736ba9413bSMike Smith * We give up once we've looped back to what we were looking at 1746ba9413bSMike Smith * first - this should normally be a MODINFO_NAME field. 1756ba9413bSMike Smith */ 1766ba9413bSMike Smith if (type == 0) { 1776ba9413bSMike Smith type = hdr[0]; 1786ba9413bSMike Smith } else { 1796ba9413bSMike Smith if (hdr[0] == type) 1806ba9413bSMike Smith break; 1816ba9413bSMike Smith } 1826ba9413bSMike Smith 1836ba9413bSMike Smith /* 1846ba9413bSMike Smith * Attribute match? Return pointer to data. 185d7d97eb0SJeroen Ruigrok van der Werven * Consumer may safely assume that size value precedes 1866ba9413bSMike Smith * data. 1876ba9413bSMike Smith */ 1886ba9413bSMike Smith if (hdr[0] == inf) 18960ae52f7SEd Schouten return(curp + (sizeof(uint32_t) * 2)); 1906ba9413bSMike Smith 1916ba9413bSMike Smith /* skip to next field */ 19260ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 1932a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 194e4f1a52fSPeter Wemm curp += next; 1956ba9413bSMike Smith } 1966ba9413bSMike Smith return(NULL); 1976ba9413bSMike Smith } 1986ba9413bSMike Smith 199e4f1a52fSPeter Wemm /* 200e4f1a52fSPeter Wemm * Delete a preload record by name. 201e4f1a52fSPeter Wemm */ 202e4f1a52fSPeter Wemm void 203e4f1a52fSPeter Wemm preload_delete_name(const char *name) 204e4f1a52fSPeter Wemm { 205e4f1a52fSPeter Wemm caddr_t curp; 20660ae52f7SEd Schouten uint32_t *hdr; 207e4f1a52fSPeter Wemm int next; 208e4f1a52fSPeter Wemm int clearing; 209e4f1a52fSPeter Wemm 210e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 211e4f1a52fSPeter Wemm 212e4f1a52fSPeter Wemm clearing = 0; 213e4f1a52fSPeter Wemm curp = preload_metadata; 214e4f1a52fSPeter Wemm for (;;) { 21560ae52f7SEd Schouten hdr = (uint32_t *)curp; 216e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 217e4f1a52fSPeter Wemm break; 218e4f1a52fSPeter Wemm 219e4f1a52fSPeter Wemm /* Search for a MODINFO_NAME field */ 220e4f1a52fSPeter Wemm if (hdr[0] == MODINFO_NAME) { 22160ae52f7SEd Schouten if (!strcmp(name, curp + sizeof(uint32_t) * 2)) 222e4f1a52fSPeter Wemm clearing = 1; /* got it, start clearing */ 223e4f1a52fSPeter Wemm else if (clearing) 224e4f1a52fSPeter Wemm clearing = 0; /* at next one now.. better stop */ 225e4f1a52fSPeter Wemm } 226e4f1a52fSPeter Wemm if (clearing) 227e4f1a52fSPeter Wemm hdr[0] = MODINFO_EMPTY; 228e4f1a52fSPeter Wemm 229e4f1a52fSPeter Wemm /* skip to next field */ 23060ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 2312a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 232e4f1a52fSPeter Wemm curp += next; 233e4f1a52fSPeter Wemm } 234e4f1a52fSPeter Wemm } 235e4f1a52fSPeter Wemm } 236e4f1a52fSPeter Wemm 237278e7970SMarcel Moolenaar void * 238278e7970SMarcel Moolenaar preload_fetch_addr(caddr_t mod) 239278e7970SMarcel Moolenaar { 240278e7970SMarcel Moolenaar caddr_t *mdp; 241278e7970SMarcel Moolenaar 242278e7970SMarcel Moolenaar mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR); 243278e7970SMarcel Moolenaar if (mdp == NULL) 244278e7970SMarcel Moolenaar return (NULL); 245278e7970SMarcel Moolenaar return (*mdp + preload_addr_relocate); 246278e7970SMarcel Moolenaar } 247278e7970SMarcel Moolenaar 248278e7970SMarcel Moolenaar size_t 249278e7970SMarcel Moolenaar preload_fetch_size(caddr_t mod) 250278e7970SMarcel Moolenaar { 251278e7970SMarcel Moolenaar size_t *mdp; 252278e7970SMarcel Moolenaar 253278e7970SMarcel Moolenaar mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE); 254278e7970SMarcel Moolenaar if (mdp == NULL) 255278e7970SMarcel Moolenaar return (0); 256278e7970SMarcel Moolenaar return (*mdp); 257278e7970SMarcel Moolenaar } 258278e7970SMarcel Moolenaar 25912d7eaa0SWarner Losh /* Called from locore. Convert physical pointers to kvm. Sigh. */ 260e4f1a52fSPeter Wemm void 261e4f1a52fSPeter Wemm preload_bootstrap_relocate(vm_offset_t offset) 262e4f1a52fSPeter Wemm { 263e4f1a52fSPeter Wemm caddr_t curp; 26460ae52f7SEd Schouten uint32_t *hdr; 265e4f1a52fSPeter Wemm vm_offset_t *ptr; 266e4f1a52fSPeter Wemm int next; 267e4f1a52fSPeter Wemm 268e4f1a52fSPeter Wemm if (preload_metadata != NULL) { 269e4f1a52fSPeter Wemm 270e4f1a52fSPeter Wemm curp = preload_metadata; 271e4f1a52fSPeter Wemm for (;;) { 27260ae52f7SEd Schouten hdr = (uint32_t *)curp; 273e4f1a52fSPeter Wemm if (hdr[0] == 0 && hdr[1] == 0) 274e4f1a52fSPeter Wemm break; 275e4f1a52fSPeter Wemm 2762da2eeacSPeter Wemm /* Deal with the ones that we know we have to fix */ 2772da2eeacSPeter Wemm switch (hdr[0]) { 2782da2eeacSPeter Wemm case MODINFO_ADDR: 2792da2eeacSPeter Wemm case MODINFO_METADATA|MODINFOMD_SSYM: 2802da2eeacSPeter Wemm case MODINFO_METADATA|MODINFOMD_ESYM: 28160ae52f7SEd Schouten ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); 282e4f1a52fSPeter Wemm *ptr += offset; 2832da2eeacSPeter Wemm break; 284e4f1a52fSPeter Wemm } 285e4f1a52fSPeter Wemm /* The rest is beyond us for now */ 286e4f1a52fSPeter Wemm 287e4f1a52fSPeter Wemm /* skip to next field */ 28860ae52f7SEd Schouten next = sizeof(uint32_t) * 2 + hdr[1]; 2892a26e9eaSPeter Wemm next = roundup(next, sizeof(u_long)); 290e4f1a52fSPeter Wemm curp += next; 291e4f1a52fSPeter Wemm } 292e4f1a52fSPeter Wemm } 293e4f1a52fSPeter Wemm } 294