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$");
29116182Sobrien
3040090Smsmith#include <sys/param.h>
3140090Smsmith#include <sys/systm.h>
3240090Smsmith#include <sys/linker.h>
3340090Smsmith
3440090Smsmith/*
3540090Smsmith * Preloaded module support
3640090Smsmith */
3740090Smsmith
38218494Smarcelvm_offset_t preload_addr_relocate = 0;
39218494Smarcelcaddr_t preload_metadata;
4040090Smsmith
4140090Smsmith/*
4240090Smsmith * Search for the preloaded module (name)
4340090Smsmith */
4440090Smsmithcaddr_t
4540157Speterpreload_search_by_name(const char *name)
4640090Smsmith{
4740090Smsmith    caddr_t	curp;
48209390Sed    uint32_t	*hdr;
4940157Speter    int		next;
5040090Smsmith
5140157Speter    if (preload_metadata != NULL) {
5240090Smsmith
5340157Speter	curp = preload_metadata;
5440090Smsmith	for (;;) {
55209390Sed	    hdr = (uint32_t *)curp;
5640157Speter	    if (hdr[0] == 0 && hdr[1] == 0)
5740090Smsmith		break;
5840090Smsmith
5940090Smsmith	    /* Search for a MODINFO_NAME field */
6040090Smsmith	    if ((hdr[0] == MODINFO_NAME) &&
61209390Sed		!strcmp(name, curp + sizeof(uint32_t) * 2))
6240090Smsmith		return(curp);
6340090Smsmith
6440090Smsmith	    /* skip to next field */
65209390Sed	    next = sizeof(uint32_t) * 2 + hdr[1];
6640336Speter	    next = roundup(next, sizeof(u_long));
6740157Speter	    curp += next;
6840090Smsmith	}
6940090Smsmith    }
7040090Smsmith    return(NULL);
7140090Smsmith}
7240090Smsmith
7340090Smsmith/*
7440090Smsmith * Search for the first preloaded module of (type)
7540090Smsmith */
7640090Smsmithcaddr_t
7740157Speterpreload_search_by_type(const char *type)
7840090Smsmith{
7940090Smsmith    caddr_t	curp, lname;
80209390Sed    uint32_t	*hdr;
8140157Speter    int		next;
8240090Smsmith
8340157Speter    if (preload_metadata != NULL) {
8440090Smsmith
8540157Speter	curp = preload_metadata;
8640090Smsmith	lname = NULL;
8740090Smsmith	for (;;) {
88209390Sed	    hdr = (uint32_t *)curp;
8940157Speter	    if (hdr[0] == 0 && hdr[1] == 0)
9040090Smsmith		break;
9140090Smsmith
9240090Smsmith	    /* remember the start of each record */
9340090Smsmith	    if (hdr[0] == MODINFO_NAME)
9440090Smsmith		lname = curp;
9540090Smsmith
9640090Smsmith	    /* Search for a MODINFO_TYPE field */
9740090Smsmith	    if ((hdr[0] == MODINFO_TYPE) &&
98209390Sed		!strcmp(type, curp + sizeof(uint32_t) * 2))
9940090Smsmith		return(lname);
10040090Smsmith
10140090Smsmith	    /* skip to next field */
102209390Sed	    next = sizeof(uint32_t) * 2 + hdr[1];
10340336Speter	    next = roundup(next, sizeof(u_long));
10440157Speter	    curp += next;
10540090Smsmith	}
10640090Smsmith    }
10740090Smsmith    return(NULL);
10840090Smsmith}
10940090Smsmith
11040090Smsmith/*
11140157Speter * Walk through the preloaded module list
11240157Speter */
11340157Spetercaddr_t
11440157Speterpreload_search_next_name(caddr_t base)
11540157Speter{
11640157Speter    caddr_t	curp;
117209390Sed    uint32_t	*hdr;
11840157Speter    int		next;
11940157Speter
12040157Speter    if (preload_metadata != NULL) {
12140157Speter
12240157Speter	/* Pick up where we left off last time */
12340157Speter	if (base) {
12440157Speter	    /* skip to next field */
12540157Speter	    curp = base;
126209390Sed	    hdr = (uint32_t *)curp;
127209390Sed	    next = sizeof(uint32_t) * 2 + hdr[1];
12840336Speter	    next = roundup(next, sizeof(u_long));
12940157Speter	    curp += next;
13040157Speter	} else
13140157Speter	    curp = preload_metadata;
13240157Speter
13340157Speter	for (;;) {
134209390Sed	    hdr = (uint32_t *)curp;
13540157Speter	    if (hdr[0] == 0 && hdr[1] == 0)
13640157Speter		break;
13740157Speter
13840157Speter	    /* Found a new record? */
13940157Speter	    if (hdr[0] == MODINFO_NAME)
14040157Speter		return curp;
14140157Speter
14240157Speter	    /* skip to next field */
143209390Sed	    next = sizeof(uint32_t) * 2 + hdr[1];
14440336Speter	    next = roundup(next, sizeof(u_long));
14540157Speter	    curp += next;
14640157Speter	}
14740157Speter    }
14840157Speter    return(NULL);
14940157Speter}
15040157Speter
15140157Speter/*
15240090Smsmith * Given a preloaded module handle (mod), return a pointer
15340090Smsmith * to the data for the attribute (inf).
15440090Smsmith */
15540090Smsmithcaddr_t
15640157Speterpreload_search_info(caddr_t mod, int inf)
15740090Smsmith{
15840090Smsmith    caddr_t	curp;
159209390Sed    uint32_t	*hdr;
160209390Sed    uint32_t	type = 0;
16140157Speter    int		next;
16240090Smsmith
16340090Smsmith    curp = mod;
16440090Smsmith    for (;;) {
165209390Sed	hdr = (uint32_t *)curp;
16640090Smsmith	/* end of module data? */
16740157Speter	if (hdr[0] == 0 && hdr[1] == 0)
16840090Smsmith	    break;
16940090Smsmith	/*
17040090Smsmith	 * We give up once we've looped back to what we were looking at
17140090Smsmith	 * first - this should normally be a MODINFO_NAME field.
17240090Smsmith	 */
17340090Smsmith	if (type == 0) {
17440090Smsmith	    type = hdr[0];
17540090Smsmith	} else {
17640090Smsmith	    if (hdr[0] == type)
17740090Smsmith		break;
17840090Smsmith	}
17940090Smsmith
18040090Smsmith	/*
18140090Smsmith	 * Attribute match? Return pointer to data.
18272645Sasmodai	 * Consumer may safely assume that size value precedes
18340090Smsmith	 * data.
18440090Smsmith	 */
18540090Smsmith	if (hdr[0] == inf)
186209390Sed	    return(curp + (sizeof(uint32_t) * 2));
18740090Smsmith
18840090Smsmith	/* skip to next field */
189209390Sed	next = sizeof(uint32_t) * 2 + hdr[1];
19040336Speter	next = roundup(next, sizeof(u_long));
19140157Speter	curp += next;
19240090Smsmith    }
19340090Smsmith    return(NULL);
19440090Smsmith}
19540090Smsmith
19640157Speter/*
19740157Speter * Delete a preload record by name.
19840157Speter */
19940157Spetervoid
20040157Speterpreload_delete_name(const char *name)
20140157Speter{
20240157Speter    caddr_t	curp;
203209390Sed    uint32_t	*hdr;
20440157Speter    int		next;
20540157Speter    int		clearing;
20640157Speter
20740157Speter    if (preload_metadata != NULL) {
20840157Speter
20940157Speter	clearing = 0;
21040157Speter	curp = preload_metadata;
21140157Speter	for (;;) {
212209390Sed	    hdr = (uint32_t *)curp;
21340157Speter	    if (hdr[0] == 0 && hdr[1] == 0)
21440157Speter		break;
21540157Speter
21640157Speter	    /* Search for a MODINFO_NAME field */
21740157Speter	    if (hdr[0] == MODINFO_NAME) {
218209390Sed		if (!strcmp(name, curp + sizeof(uint32_t) * 2))
21940157Speter		    clearing = 1;	/* got it, start clearing */
22040157Speter		else if (clearing)
22140157Speter		    clearing = 0;	/* at next one now.. better stop */
22240157Speter	    }
22340157Speter	    if (clearing)
22440157Speter		hdr[0] = MODINFO_EMPTY;
22540157Speter
22640157Speter	    /* skip to next field */
227209390Sed	    next = sizeof(uint32_t) * 2 + hdr[1];
22840336Speter	    next = roundup(next, sizeof(u_long));
22940157Speter	    curp += next;
23040157Speter	}
23140157Speter    }
23240157Speter}
23340157Speter
234218494Smarcelvoid *
235218494Smarcelpreload_fetch_addr(caddr_t mod)
236218494Smarcel{
237218494Smarcel	caddr_t *mdp;
238218494Smarcel
239218494Smarcel	mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
240218494Smarcel	if (mdp == NULL)
241218494Smarcel		return (NULL);
242218494Smarcel	return (*mdp + preload_addr_relocate);
243218494Smarcel}
244218494Smarcel
245218494Smarcelsize_t
246218494Smarcelpreload_fetch_size(caddr_t mod)
247218494Smarcel{
248218494Smarcel	size_t *mdp;
249218494Smarcel
250218494Smarcel	mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
251218494Smarcel	if (mdp == NULL)
252218494Smarcel		return (0);
253218494Smarcel	return (*mdp);
254218494Smarcel}
255218494Smarcel
25640157Speter/* Called from locore on i386.  Convert physical pointers to kvm. Sigh. */
25740157Spetervoid
25840157Speterpreload_bootstrap_relocate(vm_offset_t offset)
25940157Speter{
26040157Speter    caddr_t	curp;
261209390Sed    uint32_t	*hdr;
26240157Speter    vm_offset_t	*ptr;
26340157Speter    int		next;
26440157Speter
26540157Speter    if (preload_metadata != NULL) {
26640157Speter
26740157Speter	curp = preload_metadata;
26840157Speter	for (;;) {
269209390Sed	    hdr = (uint32_t *)curp;
27040157Speter	    if (hdr[0] == 0 && hdr[1] == 0)
27140157Speter		break;
27240157Speter
27340252Speter	    /* Deal with the ones that we know we have to fix */
27440252Speter	    switch (hdr[0]) {
27540252Speter	    case MODINFO_ADDR:
27640252Speter	    case MODINFO_METADATA|MODINFOMD_SSYM:
27740252Speter	    case MODINFO_METADATA|MODINFOMD_ESYM:
278209390Sed		ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
27940157Speter		*ptr += offset;
28040252Speter		break;
28140157Speter	    }
28240157Speter	    /* The rest is beyond us for now */
28340157Speter
28440157Speter	    /* skip to next field */
285209390Sed	    next = sizeof(uint32_t) * 2 + hdr[1];
28640336Speter	    next = roundup(next, sizeof(u_long));
28740157Speter	    curp += next;
28840157Speter	}
28940157Speter    }
29040157Speter}
291