140090Smsmith/*- 240090Smsmith * Copyright (c) 1998 Michael Smith 340090Smsmith * All rights reserved. 440090Smsmith * 540090Smsmith * Redistribution and use in source and binary forms, with or without 640090Smsmith * modification, are permitted provided that the following conditions 740090Smsmith * are met: 840090Smsmith * 1. Redistributions of source code must retain the above copyright 940090Smsmith * notice, this list of conditions and the following disclaimer. 1040090Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1140090Smsmith * notice, this list of conditions and the following disclaimer in the 1240090Smsmith * documentation and/or other materials provided with the distribution. 1340090Smsmith * 1440090Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1540090Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1640090Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1740090Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1840090Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1940090Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2040090Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2140090Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2240090Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2340090Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2440090Smsmith * SUCH DAMAGE. 2540090Smsmith */ 2640090Smsmith 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/kern/subr_module.c 337262 2018-08-03 15:42:39Z markj $"); 29116182Sobrien 3040090Smsmith#include <sys/param.h> 3140090Smsmith#include <sys/systm.h> 3240090Smsmith#include <sys/linker.h> 3340090Smsmith 34337262Smarkj#include <vm/vm.h> 35337262Smarkj#include <vm/vm_extern.h> 36337262Smarkj 3740090Smsmith/* 3840090Smsmith * Preloaded module support 3940090Smsmith */ 4040090Smsmith 41218494Smarcelvm_offset_t preload_addr_relocate = 0; 42218494Smarcelcaddr_t preload_metadata; 4340090Smsmith 4440090Smsmith/* 4540090Smsmith * Search for the preloaded module (name) 4640090Smsmith */ 4740090Smsmithcaddr_t 4840157Speterpreload_search_by_name(const char *name) 4940090Smsmith{ 5040090Smsmith caddr_t curp; 51209390Sed uint32_t *hdr; 5240157Speter int next; 5340090Smsmith 5440157Speter if (preload_metadata != NULL) { 5540090Smsmith 5640157Speter curp = preload_metadata; 5740090Smsmith for (;;) { 58209390Sed hdr = (uint32_t *)curp; 5940157Speter if (hdr[0] == 0 && hdr[1] == 0) 6040090Smsmith break; 6140090Smsmith 6240090Smsmith /* Search for a MODINFO_NAME field */ 6340090Smsmith if ((hdr[0] == MODINFO_NAME) && 64209390Sed !strcmp(name, curp + sizeof(uint32_t) * 2)) 6540090Smsmith return(curp); 6640090Smsmith 6740090Smsmith /* skip to next field */ 68209390Sed next = sizeof(uint32_t) * 2 + hdr[1]; 6940336Speter next = roundup(next, sizeof(u_long)); 7040157Speter curp += next; 7140090Smsmith } 7240090Smsmith } 7340090Smsmith return(NULL); 7440090Smsmith} 7540090Smsmith 7640090Smsmith/* 7740090Smsmith * Search for the first preloaded module of (type) 7840090Smsmith */ 7940090Smsmithcaddr_t 8040157Speterpreload_search_by_type(const char *type) 8140090Smsmith{ 8240090Smsmith caddr_t curp, lname; 83209390Sed uint32_t *hdr; 8440157Speter int next; 8540090Smsmith 8640157Speter if (preload_metadata != NULL) { 8740090Smsmith 8840157Speter curp = preload_metadata; 8940090Smsmith lname = NULL; 9040090Smsmith for (;;) { 91209390Sed hdr = (uint32_t *)curp; 9240157Speter if (hdr[0] == 0 && hdr[1] == 0) 9340090Smsmith break; 9440090Smsmith 9540090Smsmith /* remember the start of each record */ 9640090Smsmith if (hdr[0] == MODINFO_NAME) 9740090Smsmith lname = curp; 9840090Smsmith 9940090Smsmith /* Search for a MODINFO_TYPE field */ 10040090Smsmith if ((hdr[0] == MODINFO_TYPE) && 101209390Sed !strcmp(type, curp + sizeof(uint32_t) * 2)) 10240090Smsmith return(lname); 10340090Smsmith 10440090Smsmith /* skip to next field */ 105209390Sed next = sizeof(uint32_t) * 2 + hdr[1]; 10640336Speter next = roundup(next, sizeof(u_long)); 10740157Speter curp += next; 10840090Smsmith } 10940090Smsmith } 11040090Smsmith return(NULL); 11140090Smsmith} 11240090Smsmith 11340090Smsmith/* 11440157Speter * Walk through the preloaded module list 11540157Speter */ 11640157Spetercaddr_t 11740157Speterpreload_search_next_name(caddr_t base) 11840157Speter{ 11940157Speter caddr_t curp; 120209390Sed uint32_t *hdr; 12140157Speter int next; 12240157Speter 12340157Speter if (preload_metadata != NULL) { 12440157Speter 12540157Speter /* Pick up where we left off last time */ 12640157Speter if (base) { 12740157Speter /* skip to next field */ 12840157Speter curp = base; 129209390Sed hdr = (uint32_t *)curp; 130209390Sed next = sizeof(uint32_t) * 2 + hdr[1]; 13140336Speter next = roundup(next, sizeof(u_long)); 13240157Speter curp += next; 13340157Speter } else 13440157Speter curp = preload_metadata; 13540157Speter 13640157Speter for (;;) { 137209390Sed hdr = (uint32_t *)curp; 13840157Speter if (hdr[0] == 0 && hdr[1] == 0) 13940157Speter break; 14040157Speter 14140157Speter /* Found a new record? */ 14240157Speter if (hdr[0] == MODINFO_NAME) 14340157Speter return curp; 14440157Speter 14540157Speter /* skip to next field */ 146209390Sed next = sizeof(uint32_t) * 2 + hdr[1]; 14740336Speter next = roundup(next, sizeof(u_long)); 14840157Speter curp += next; 14940157Speter } 15040157Speter } 15140157Speter return(NULL); 15240157Speter} 15340157Speter 15440157Speter/* 15540090Smsmith * Given a preloaded module handle (mod), return a pointer 15640090Smsmith * to the data for the attribute (inf). 15740090Smsmith */ 15840090Smsmithcaddr_t 15940157Speterpreload_search_info(caddr_t mod, int inf) 16040090Smsmith{ 16140090Smsmith caddr_t curp; 162209390Sed uint32_t *hdr; 163209390Sed uint32_t type = 0; 16440157Speter int next; 16540090Smsmith 166287000Sroyger if (mod == NULL) 167287000Sroyger return (NULL); 168287000Sroyger 16940090Smsmith curp = mod; 17040090Smsmith for (;;) { 171209390Sed hdr = (uint32_t *)curp; 17240090Smsmith /* end of module data? */ 17340157Speter if (hdr[0] == 0 && hdr[1] == 0) 17440090Smsmith break; 17540090Smsmith /* 17640090Smsmith * We give up once we've looped back to what we were looking at 17740090Smsmith * first - this should normally be a MODINFO_NAME field. 17840090Smsmith */ 17940090Smsmith if (type == 0) { 18040090Smsmith type = hdr[0]; 18140090Smsmith } else { 18240090Smsmith if (hdr[0] == type) 18340090Smsmith break; 18440090Smsmith } 18540090Smsmith 18640090Smsmith /* 18740090Smsmith * Attribute match? Return pointer to data. 18872645Sasmodai * Consumer may safely assume that size value precedes 18940090Smsmith * data. 19040090Smsmith */ 19140090Smsmith if (hdr[0] == inf) 192209390Sed return(curp + (sizeof(uint32_t) * 2)); 19340090Smsmith 19440090Smsmith /* skip to next field */ 195209390Sed next = sizeof(uint32_t) * 2 + hdr[1]; 19640336Speter next = roundup(next, sizeof(u_long)); 19740157Speter curp += next; 19840090Smsmith } 19940090Smsmith return(NULL); 20040090Smsmith} 20140090Smsmith 20240157Speter/* 20340157Speter * Delete a preload record by name. 20440157Speter */ 20540157Spetervoid 20640157Speterpreload_delete_name(const char *name) 20740157Speter{ 208337262Smarkj caddr_t addr, curp; 209337262Smarkj uint32_t *hdr, sz; 21040157Speter int next; 21140157Speter int clearing; 212337262Smarkj 213337262Smarkj addr = 0; 214337262Smarkj sz = 0; 21540157Speter 21640157Speter if (preload_metadata != NULL) { 217337262Smarkj 21840157Speter clearing = 0; 21940157Speter curp = preload_metadata; 22040157Speter for (;;) { 221209390Sed hdr = (uint32_t *)curp; 222337262Smarkj if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) { 223337262Smarkj /* Free memory used to store the file. */ 224337262Smarkj if (addr != 0 && sz != 0) 225337262Smarkj kmem_bootstrap_free((vm_offset_t)addr, sz); 226337262Smarkj addr = 0; 227337262Smarkj sz = 0; 22840157Speter 229337262Smarkj if (hdr[0] == 0) 230337262Smarkj break; 231209390Sed if (!strcmp(name, curp + sizeof(uint32_t) * 2)) 23240157Speter clearing = 1; /* got it, start clearing */ 233337262Smarkj else if (clearing) { 23440157Speter clearing = 0; /* at next one now.. better stop */ 235337262Smarkj } 23640157Speter } 237337262Smarkj if (clearing) { 238337262Smarkj if (hdr[0] == MODINFO_ADDR) 239337262Smarkj addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2); 240337262Smarkj else if (hdr[0] == MODINFO_SIZE) 241337262Smarkj sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2); 24240157Speter hdr[0] = MODINFO_EMPTY; 243337262Smarkj } 24440157Speter 24540157Speter /* skip to next field */ 246209390Sed next = sizeof(uint32_t) * 2 + hdr[1]; 24740336Speter next = roundup(next, sizeof(u_long)); 24840157Speter curp += next; 24940157Speter } 25040157Speter } 25140157Speter} 25240157Speter 253218494Smarcelvoid * 254218494Smarcelpreload_fetch_addr(caddr_t mod) 255218494Smarcel{ 256218494Smarcel caddr_t *mdp; 257218494Smarcel 258218494Smarcel mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR); 259218494Smarcel if (mdp == NULL) 260218494Smarcel return (NULL); 261218494Smarcel return (*mdp + preload_addr_relocate); 262218494Smarcel} 263218494Smarcel 264218494Smarcelsize_t 265218494Smarcelpreload_fetch_size(caddr_t mod) 266218494Smarcel{ 267218494Smarcel size_t *mdp; 268218494Smarcel 269218494Smarcel mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE); 270218494Smarcel if (mdp == NULL) 271218494Smarcel return (0); 272218494Smarcel return (*mdp); 273218494Smarcel} 274218494Smarcel 275276391Simp/* Called from locore. Convert physical pointers to kvm. Sigh. */ 27640157Spetervoid 27740157Speterpreload_bootstrap_relocate(vm_offset_t offset) 27840157Speter{ 27940157Speter caddr_t curp; 280209390Sed uint32_t *hdr; 28140157Speter vm_offset_t *ptr; 28240157Speter int next; 28340157Speter 28440157Speter if (preload_metadata != NULL) { 28540157Speter 28640157Speter curp = preload_metadata; 28740157Speter for (;;) { 288209390Sed hdr = (uint32_t *)curp; 28940157Speter if (hdr[0] == 0 && hdr[1] == 0) 29040157Speter break; 29140157Speter 29240252Speter /* Deal with the ones that we know we have to fix */ 29340252Speter switch (hdr[0]) { 29440252Speter case MODINFO_ADDR: 29540252Speter case MODINFO_METADATA|MODINFOMD_SSYM: 29640252Speter case MODINFO_METADATA|MODINFOMD_ESYM: 297209390Sed ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); 29840157Speter *ptr += offset; 29940252Speter break; 30040157Speter } 30140157Speter /* The rest is beyond us for now */ 30240157Speter 30340157Speter /* skip to next field */ 304209390Sed next = sizeof(uint32_t) * 2 + hdr[1]; 30540336Speter next = roundup(next, sizeof(u_long)); 30640157Speter curp += next; 30740157Speter } 30840157Speter } 30940157Speter} 310