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