xref: /freebsd/stand/common/modinfo.c (revision 86077f4fd11070518a6d04eee7fdb93cbbfb1b52)
15d1531d9SWarner Losh /*-
25d1531d9SWarner Losh  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
35d1531d9SWarner Losh  * All rights reserved.
45d1531d9SWarner Losh  *
55d1531d9SWarner Losh  * Redistribution and use in source and binary forms, with or without
65d1531d9SWarner Losh  * modification, are permitted provided that the following conditions
75d1531d9SWarner Losh  * are met:
85d1531d9SWarner Losh  * 1. Redistributions of source code must retain the above copyright
95d1531d9SWarner Losh  *    notice, this list of conditions and the following disclaimer.
105d1531d9SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
115d1531d9SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
125d1531d9SWarner Losh  *    documentation and/or other materials provided with the distribution.
135d1531d9SWarner Losh  *
145d1531d9SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
155d1531d9SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165d1531d9SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
175d1531d9SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
185d1531d9SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
195d1531d9SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
205d1531d9SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
215d1531d9SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225d1531d9SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235d1531d9SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
245d1531d9SWarner Losh  * SUCH DAMAGE.
255d1531d9SWarner Losh  *
265d1531d9SWarner Losh  *	from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.6
275d1531d9SWarner Losh  */
285d1531d9SWarner Losh #include <stand.h>
295d1531d9SWarner Losh #include <sys/param.h>
305d1531d9SWarner Losh #include <sys/linker.h>
315d1531d9SWarner Losh #include <sys/boot.h>
325d1531d9SWarner Losh #include <sys/reboot.h>
335d1531d9SWarner Losh #if defined(LOADER_FDT_SUPPORT)
345d1531d9SWarner Losh #include <fdt_platform.h>
355d1531d9SWarner Losh #endif
365d1531d9SWarner Losh 
375d1531d9SWarner Losh #ifdef __arm__
385d1531d9SWarner Losh #include <machine/elf.h>
395d1531d9SWarner Losh #endif
405d1531d9SWarner Losh #include <machine/metadata.h>
415d1531d9SWarner Losh 
425d1531d9SWarner Losh #include "bootstrap.h"
435d1531d9SWarner Losh #include "modinfo.h"
445d1531d9SWarner Losh 
452e6ed47aSWarner Losh /*
462e6ed47aSWarner Losh  * Copy module-related data into the load area, where it can be
472e6ed47aSWarner Losh  * used as a directory for loaded modules.
482e6ed47aSWarner Losh  *
492e6ed47aSWarner Losh  * Module data is presented in a self-describing format.  Each datum
502e6ed47aSWarner Losh  * is preceded by a 32-bit identifier and a 32-bit size field.
512e6ed47aSWarner Losh  *
522e6ed47aSWarner Losh  * Currently, the following data are saved:
532e6ed47aSWarner Losh  *
542e6ed47aSWarner Losh  * MOD_NAME	(variable)		module name (string)
552e6ed47aSWarner Losh  * MOD_TYPE	(variable)		module type (string)
562e6ed47aSWarner Losh  * MOD_ARGS	(variable)		module parameters (string)
572e6ed47aSWarner Losh  * MOD_ADDR	sizeof(vm_offset_t)	module load address
582e6ed47aSWarner Losh  * MOD_SIZE	sizeof(size_t)		module size
592e6ed47aSWarner Losh  * MOD_METADATA	(variable)		type-specific metadata
602e6ed47aSWarner Losh  *
612e6ed47aSWarner Losh  * Clients are required to define a MOD_ALIGN(l) macro which rounds the passed
622e6ed47aSWarner Losh  * in length to the required alignment for the kernel being booted.
632e6ed47aSWarner Losh  */
642e6ed47aSWarner Losh 
652e6ed47aSWarner Losh #define COPY32(v, a, c) {			\
662e6ed47aSWarner Losh     uint32_t	x = (v);			\
672e6ed47aSWarner Losh     if (c)					\
682e6ed47aSWarner Losh         archsw.arch_copyin(&x, a, sizeof(x));	\
692e6ed47aSWarner Losh     a += sizeof(x);				\
702e6ed47aSWarner Losh }
712e6ed47aSWarner Losh 
722e6ed47aSWarner Losh #define MOD_STR(t, a, s, c) {			\
732e6ed47aSWarner Losh     COPY32(t, a, c);				\
742e6ed47aSWarner Losh     COPY32(strlen(s) + 1, a, c)			\
752e6ed47aSWarner Losh     if (c)					\
762e6ed47aSWarner Losh         archsw.arch_copyin(s, a, strlen(s) + 1);\
772e6ed47aSWarner Losh     a += MOD_ALIGN(strlen(s) + 1);		\
782e6ed47aSWarner Losh }
792e6ed47aSWarner Losh 
802e6ed47aSWarner Losh #define MOD_NAME(a, s, c)	MOD_STR(MODINFO_NAME, a, s, c)
812e6ed47aSWarner Losh #define MOD_TYPE(a, s, c)	MOD_STR(MODINFO_TYPE, a, s, c)
822e6ed47aSWarner Losh #define MOD_ARGS(a, s, c)	MOD_STR(MODINFO_ARGS, a, s, c)
832e6ed47aSWarner Losh 
842e6ed47aSWarner Losh #define MOD_VAR(t, a, s, c) {			\
852e6ed47aSWarner Losh     COPY32(t, a, c);				\
862e6ed47aSWarner Losh     COPY32(sizeof(s), a, c);			\
872e6ed47aSWarner Losh     if (c)					\
882e6ed47aSWarner Losh         archsw.arch_copyin(&s, a, sizeof(s));	\
892e6ed47aSWarner Losh     a += MOD_ALIGN(sizeof(s));			\
902e6ed47aSWarner Losh }
912e6ed47aSWarner Losh 
922e6ed47aSWarner Losh #define MOD_ADDR(a, s, c)	MOD_VAR(MODINFO_ADDR, a, s, c)
932e6ed47aSWarner Losh #define MOD_SIZE(a, s, c)	MOD_VAR(MODINFO_SIZE, a, s, c)
942e6ed47aSWarner Losh 
952e6ed47aSWarner Losh #define MOD_METADATA(a, mm, c) {		\
962e6ed47aSWarner Losh     COPY32(MODINFO_METADATA | mm->md_type, a, c);\
972e6ed47aSWarner Losh     COPY32(mm->md_size, a, c);			\
989f726967SWarner Losh     if (c) {					\
992e6ed47aSWarner Losh         archsw.arch_copyin(mm->md_data, a, mm->md_size);\
1009f726967SWarner Losh 	mm->md_addr = a;			\
1019f726967SWarner Losh     }						\
1022e6ed47aSWarner Losh     a += MOD_ALIGN(mm->md_size);		\
1032e6ed47aSWarner Losh }
1042e6ed47aSWarner Losh 
1052e6ed47aSWarner Losh #define MOD_END(a, c) {				\
1062e6ed47aSWarner Losh     COPY32(MODINFO_END, a, c);			\
1072e6ed47aSWarner Losh     COPY32(0, a, c);				\
1082e6ed47aSWarner Losh }
1092e6ed47aSWarner Losh 
1105d1531d9SWarner Losh #define MOD_ALIGN(l)	roundup(l, align)
1115d1531d9SWarner Losh 
112*86077f4fSAhmad Khalifa const char md_modtype[] = MODTYPE;
113*86077f4fSAhmad Khalifa const char md_kerntype[] = KERNTYPE;
114*86077f4fSAhmad Khalifa const char md_modtype_obj[] = MODTYPE_OBJ;
115*86077f4fSAhmad Khalifa const char md_kerntype_mb[] = KERNTYPE_MB;
116*86077f4fSAhmad Khalifa 
1175d1531d9SWarner Losh vm_offset_t
md_copymodules(vm_offset_t addr,bool kern64)1185d1531d9SWarner Losh md_copymodules(vm_offset_t addr, bool kern64)
1195d1531d9SWarner Losh {
1205d1531d9SWarner Losh 	struct preloaded_file	*fp;
1215d1531d9SWarner Losh 	struct file_metadata	*md;
1225d1531d9SWarner Losh 	uint64_t		scratch64;
1235d1531d9SWarner Losh 	uint32_t		scratch32;
1245d1531d9SWarner Losh 	int			c;
1252e6ed47aSWarner Losh 	int			align;
1265d1531d9SWarner Losh 
1272e6ed47aSWarner Losh 	align = kern64 ? sizeof(uint64_t) : sizeof(uint32_t);
1285d1531d9SWarner Losh 	c = addr != 0;
1295d1531d9SWarner Losh 	/* start with the first module on the list, should be the kernel */
1305d1531d9SWarner Losh 	for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
1315d1531d9SWarner Losh 
1325d1531d9SWarner Losh 		MOD_NAME(addr, fp->f_name, c);	/* this field must come first */
1335d1531d9SWarner Losh 		MOD_TYPE(addr, fp->f_type, c);
1345d1531d9SWarner Losh 		if (fp->f_args)
1355d1531d9SWarner Losh 			MOD_ARGS(addr, fp->f_args, c);
1365d1531d9SWarner Losh 		if (kern64) {
1375d1531d9SWarner Losh 			scratch64 = fp->f_addr;
1385d1531d9SWarner Losh 			MOD_ADDR(addr, scratch64, c);
1395d1531d9SWarner Losh 			scratch64 = fp->f_size;
1405d1531d9SWarner Losh 			MOD_SIZE(addr, scratch64, c);
1415d1531d9SWarner Losh 		} else {
1425d1531d9SWarner Losh 			scratch32 = fp->f_addr;
1435d1531d9SWarner Losh #ifdef __arm__
1445d1531d9SWarner Losh 			scratch32 -= __elfN(relocation_offset);
1455d1531d9SWarner Losh #endif
1465d1531d9SWarner Losh 			MOD_ADDR(addr, scratch32, c);
1475d1531d9SWarner Losh 			MOD_SIZE(addr, fp->f_size, c);
1485d1531d9SWarner Losh 		}
1495d1531d9SWarner Losh 		for (md = fp->f_metadata; md != NULL; md = md->md_next) {
1505d1531d9SWarner Losh 			if (!(md->md_type & MODINFOMD_NOCOPY)) {
1515d1531d9SWarner Losh 				MOD_METADATA(addr, md, c);
1525d1531d9SWarner Losh 			}
1535d1531d9SWarner Losh 		}
1545d1531d9SWarner Losh 	}
1555d1531d9SWarner Losh 	MOD_END(addr, c);
1565d1531d9SWarner Losh 	return(addr);
1575d1531d9SWarner Losh }
158fc352701SWarner Losh 
159fc352701SWarner Losh /*
160fc352701SWarner Losh  * Copy the environment into the load area starting at (addr).
161fc352701SWarner Losh  * Each variable is formatted as <name>=<value>, with a single nul
162fc352701SWarner Losh  * separating each variable, and a double nul terminating the environment.
163fc352701SWarner Losh  */
164fc352701SWarner Losh vm_offset_t
md_copyenv(vm_offset_t start)165fc352701SWarner Losh md_copyenv(vm_offset_t start)
166fc352701SWarner Losh {
167fc352701SWarner Losh 	struct env_var *ep;
168fc352701SWarner Losh 	vm_offset_t addr, last;
169fc352701SWarner Losh 	size_t len;
170fc352701SWarner Losh 
171fc352701SWarner Losh 	addr = last = start;
172fc352701SWarner Losh 
173fc352701SWarner Losh 	/* Traverse the environment. */
174fc352701SWarner Losh 	for (ep = environ; ep != NULL; ep = ep->ev_next) {
175fc352701SWarner Losh 		len = strlen(ep->ev_name);
176fc352701SWarner Losh 		if ((size_t)archsw.arch_copyin(ep->ev_name, addr, len) != len)
177fc352701SWarner Losh 			break;
178fc352701SWarner Losh 		addr += len;
179fc352701SWarner Losh 		if (archsw.arch_copyin("=", addr, 1) != 1)
180fc352701SWarner Losh 			break;
181fc352701SWarner Losh 		addr++;
182fc352701SWarner Losh 		if (ep->ev_value != NULL) {
183fc352701SWarner Losh 			len = strlen(ep->ev_value);
184fc352701SWarner Losh 			if ((size_t)archsw.arch_copyin(ep->ev_value, addr, len) != len)
185fc352701SWarner Losh 				break;
186fc352701SWarner Losh 			addr += len;
187fc352701SWarner Losh 		}
188fc352701SWarner Losh 		if (archsw.arch_copyin("", addr, 1) != 1)
189fc352701SWarner Losh 			break;
190fc352701SWarner Losh 		last = ++addr;
191fc352701SWarner Losh 	}
192fc352701SWarner Losh 
193fc352701SWarner Losh 	if (archsw.arch_copyin("", last++, 1) != 1)
194fc352701SWarner Losh 		last = start;
195fc352701SWarner Losh 	return(last);
196fc352701SWarner Losh }
197