/*-1* Copyright (c) 1998 Michael Smith <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*25* from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.626*/27#include <stand.h>28#include <sys/param.h>29#include <sys/linker.h>30#include <sys/boot.h>31#include <sys/reboot.h>32#if defined(LOADER_FDT_SUPPORT)33#include <fdt_platform.h>34#endif3536#ifdef __arm__37#include <machine/elf.h>38#endif39#include <machine/metadata.h>4041#include "bootstrap.h"42#include "modinfo.h"4344/*45* Copy module-related data into the load area, where it can be46* used as a directory for loaded modules.47*48* Module data is presented in a self-describing format. Each datum49* is preceded by a 32-bit identifier and a 32-bit size field.50*51* Currently, the following data are saved:52*53* MOD_NAME (variable) module name (string)54* MOD_TYPE (variable) module type (string)55* MOD_ARGS (variable) module parameters (string)56* MOD_ADDR sizeof(vm_offset_t) module load address57* MOD_SIZE sizeof(size_t) module size58* MOD_METADATA (variable) type-specific metadata59*60* Clients are required to define a MOD_ALIGN(l) macro which rounds the passed61* in length to the required alignment for the kernel being booted.62*/6364#define COPY32(v, a, c) { \65uint32_t x = (v); \66if (c) \67archsw.arch_copyin(&x, a, sizeof(x)); \68a += sizeof(x); \69}7071#define MOD_STR(t, a, s, c) { \72COPY32(t, a, c); \73COPY32(strlen(s) + 1, a, c) \74if (c) \75archsw.arch_copyin(s, a, strlen(s) + 1);\76a += MOD_ALIGN(strlen(s) + 1); \77}7879#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c)80#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c)81#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c)8283#define MOD_VAR(t, a, s, c) { \84COPY32(t, a, c); \85COPY32(sizeof(s), a, c); \86if (c) \87archsw.arch_copyin(&s, a, sizeof(s)); \88a += MOD_ALIGN(sizeof(s)); \89}9091#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c)92#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c)9394#define MOD_METADATA(a, mm, c) { \95COPY32(MODINFO_METADATA | mm->md_type, a, c);\96COPY32(mm->md_size, a, c); \97if (c) { \98archsw.arch_copyin(mm->md_data, a, mm->md_size);\99mm->md_addr = a; \100} \101a += MOD_ALIGN(mm->md_size); \102}103104#define MOD_END(a, c) { \105COPY32(MODINFO_END, a, c); \106COPY32(0, a, c); \107}108109#define MOD_ALIGN(l) roundup(l, align)110111const char md_modtype[] = MODTYPE;112const char md_kerntype[] = KERNTYPE;113const char md_modtype_obj[] = MODTYPE_OBJ;114const char md_kerntype_mb[] = KERNTYPE_MB;115116vm_offset_t117md_copymodules(vm_offset_t addr, bool kern64)118{119struct preloaded_file *fp;120struct file_metadata *md;121uint64_t scratch64;122uint32_t scratch32;123int c;124int align;125126align = kern64 ? sizeof(uint64_t) : sizeof(uint32_t);127c = addr != 0;128/* start with the first module on the list, should be the kernel */129for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {130131MOD_NAME(addr, fp->f_name, c); /* this field must come first */132MOD_TYPE(addr, fp->f_type, c);133if (fp->f_args)134MOD_ARGS(addr, fp->f_args, c);135if (kern64) {136scratch64 = fp->f_addr;137MOD_ADDR(addr, scratch64, c);138scratch64 = fp->f_size;139MOD_SIZE(addr, scratch64, c);140} else {141scratch32 = fp->f_addr;142#ifdef __arm__143scratch32 -= __elfN(relocation_offset);144#endif145MOD_ADDR(addr, scratch32, c);146MOD_SIZE(addr, fp->f_size, c);147}148for (md = fp->f_metadata; md != NULL; md = md->md_next) {149if (!(md->md_type & MODINFOMD_NOCOPY)) {150MOD_METADATA(addr, md, c);151}152}153}154MOD_END(addr, c);155return(addr);156}157158/*159* Copy the environment into the load area starting at (addr).160* Each variable is formatted as <name>=<value>, with a single nul161* separating each variable, and a double nul terminating the environment.162*/163vm_offset_t164md_copyenv(vm_offset_t start)165{166struct env_var *ep;167vm_offset_t addr, last;168size_t len;169170addr = last = start;171172/* Traverse the environment. */173for (ep = environ; ep != NULL; ep = ep->ev_next) {174if ((ep->ev_flags & EV_NOKENV) != 0)175continue;176len = strlen(ep->ev_name);177if ((size_t)archsw.arch_copyin(ep->ev_name, addr, len) != len)178break;179addr += len;180if (archsw.arch_copyin("=", addr, 1) != 1)181break;182addr++;183if (ep->ev_value != NULL) {184len = strlen(ep->ev_value);185if ((size_t)archsw.arch_copyin(ep->ev_value, addr, len) != len)186break;187addr += len;188}189if (archsw.arch_copyin("", addr, 1) != 1)190break;191last = ++addr;192}193194if (archsw.arch_copyin("", last++, 1) != 1)195last = start;196return(last);197}198199/*200* Take the ending address and round it up to the currently required201* alignment. This typically is the page size, but is the larger of the compiled202* kernel page size, the loader page size, and the typical page size on the203* platform.204*205* XXX For the moment, it's just PAGE_SIZE to make the refactoring go faster,206* but needs to hook-in the replacement of arch_loadaddr.207*208* Also, we may need other logical things when dealing with different types of209* page sizes and/or masking or sizes. This works well for addr and sizes, but210* not for masks.211*212* Also, this is different than the MOD_ALIGN macro above, which is used for213* aligning elements in the metadata lists, not for whare modules can begin.214*/215vm_offset_t216md_align(vm_offset_t addr)217{218return (roundup(addr, PAGE_SIZE));219}220221222