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