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 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 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