rmodules: add support for rmodtool

The following patches were taken from upstreamed and
massaged to work in our repo. The patches are squashed
together.

http://review.coreboot.org/5120
http://review.coreboot.org/5364
http://review.coreboot.org/5365
http://review.coreboot.org/5366
http://review.coreboot.org/5367
http://review.coreboot.org/5368
http://review.coreboot.org/5369
http://review.coreboot.org/5370
http://review.coreboot.org/5371
http://review.coreboot.org/5372
http://review.coreboot.org/5384
http://review.coreboot.org/5373
http://review.coreboot.org/5374
http://review.coreboot.org/5375
http://review.coreboot.org/5376
http://review.coreboot.org/5377
http://review.coreboot.org/5363
http://review.coreboot.org/5378
http://review.coreboot.org/5379
http://review.coreboot.org/5407

BUG=chrome-os-partner:27094
BRANCH=None
CQ-DEPEND=CL:*157856
TEST=Built and booted rambi with these set of patches.

Change-Id: I481352b23f6b60ff495c1a6bd3c21b52d817de3d
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/190921
Reviewed-by: Gabe Black <gabeblack@chromium.org>
This commit is contained in:
Ronald G. Minnich 2014-02-04 17:35:44 -08:00 committed by chrome-internal-fetch
commit 5d262f8dd4
41 changed files with 1865 additions and 438 deletions

1
.gitignore vendored
View file

@ -58,6 +58,7 @@ tarballs/
util/*/.dependencies
util/*/.test
util/cbfstool/cbfstool
util/cbfstool/rmodtool
util/cbmem/.dependencies
util/cbmem/cbmem
util/dumpmmcr/dumpmmcr

View file

@ -255,10 +255,14 @@ build-dirs:
#######################################################################
# Build the tools
CBFSTOOL:=$(obj)/cbfstool
RMODTOOL:=$(obj)/rmodtool
$(CBFSTOOL): $(objutil)/cbfstool/cbfstool
cp $< $@
$(RMODTOOL): $(objutil)/cbfstool/rmodtool
cp $< $@
_WINCHECK=$(shell uname -o 2> /dev/null)
STACK=
ifeq ($(_WINCHECK),Msys)
@ -376,5 +380,5 @@ crosstools: clean-for-update
crossgcc-clean: clean-for-update
$(MAKE) -C util/crossgcc clean
tools: $(objutil)/kconfig/conf $(objutil)/cbfstool/cbfstool $(objutil)/nvramtool/nvramtool $(objutil)/romcc/romcc $(objutil)/sconfig/sconfig
tools: $(objutil)/kconfig/conf $(objutil)/cbfstool/cbfstool $(objutil)/cbfstool/rmodtool $(objutil)/nvramtool/nvramtool $(objutil)/romcc/romcc $(objutil)/sconfig/sconfig

View file

@ -74,7 +74,13 @@ $(obj)/coreboot.pre1: $(CBFSTOOL)
mv $(obj)/coreboot.rom $@
endif
$(obj)/coreboot.rom: $(obj)/coreboot.pre $(objcbfs)/coreboot_ram.elf $(CBFSTOOL) $(call strip_quotes,$(COREBOOT_ROM_DEPENDENCIES)) $$(INTERMEDIATE) $$(VBOOT_STUB_ELF)
ifeq ($(CONFIG_HAVE_REFCODE_BLOB),y)
REFCODE_BLOB=$(obj)/refcode.rmod
$(REFCODE_BLOB): $(RMODTOOL)
$(RMODTOOL) -i $(CONFIG_REFCODE_BLOB_FILE) -o $@
endif
$(obj)/coreboot.rom: $(obj)/coreboot.pre $(objcbfs)/coreboot_ram.elf $(CBFSTOOL) $(call strip_quotes,$(COREBOOT_ROM_DEPENDENCIES)) $$(INTERMEDIATE) $$(VBOOT_STUB) $(REFCODE_BLOB)
@printf " CBFS $(subst $(obj)/,,$(@))\n"
cp $(obj)/coreboot.pre $@.tmp
$(CBFSTOOL) $@.tmp add-stage -f $(objcbfs)/coreboot_ram.elf -n $(CONFIG_CBFS_PREFIX)/coreboot_ram -c $(CBFS_COMPRESS_FLAG)
@ -105,10 +111,10 @@ ifeq ($(CONFIG_INCLUDE_CONFIG_FILE),y)
$(CBFSTOOL) $@.tmp add -f $(obj)/config.tmp -n config -t raw; rm -f $(obj)/config.tmp ; fi
endif
ifeq ($(CONFIG_VBOOT_VERIFY_FIRMWARE),y)
$(CBFSTOOL) $@.tmp add-stage -f $(VBOOT_STUB_ELF) -n $(CONFIG_CBFS_PREFIX)/vboot -c $(CBFS_COMPRESS_FLAG)
$(CBFSTOOL) $@.tmp add-stage -f $(VBOOT_STUB) -n $(CONFIG_CBFS_PREFIX)/vboot -c $(CBFS_COMPRESS_FLAG)
endif
ifeq ($(CONFIG_HAVE_REFCODE_BLOB),y)
$(CBFSTOOL) $@.tmp add-stage -f $(CONFIG_REFCODE_BLOB_FILE) -n $(CONFIG_CBFS_PREFIX)/refcode -c $(CBFS_COMPRESS_FLAG)
$(CBFSTOOL) $@.tmp add-stage -f $(REFCODE_BLOB) -n $(CONFIG_CBFS_PREFIX)/refcode -c $(CBFS_COMPRESS_FLAG)
endif
ifeq ($(CONFIG_PXE_ROM),y)
$(CBFSTOOL) $@.tmp add -f $(CONFIG_PXE_ROM_FILE) -n pci$(CONFIG_PXE_ROM_ID).rom -t raw
@ -170,6 +176,10 @@ ifeq ($(CONFIG_RELOCATABLE_RAMSTAGE),y)
$(eval $(call rmodule_link,$(objcbfs)/coreboot_ram.debug, $(objgenerated)/coreboot_ram.o, $(CONFIG_HEAP_SIZE)))
# The rmodule_link defintion creates an elf file with .rmod extension.
$(objcbfs)/coreboot_ram.elf: $(objcbfs)/coreboot_ram.debug.rmod
cp $< $@
else
$(objcbfs)/coreboot_ram.debug: $(objgenerated)/coreboot_ram.o $(src)/arch/x86/coreboot_ram.ld

View file

@ -8,7 +8,6 @@ ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c
ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios.c
ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpigen.c
ramstage-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.S
ramstage-$(CONFIG_RELOCATABLE_RAMSTAGE) += ramstage_module_header.c
$(obj)/arch/x86/boot/coreboot_table.ramstage.o : $(OPTION_TABLE_H)
$(obj)/arch/x86/boot/smbios.ramstage.o: $(obj)/build.h

View file

@ -19,6 +19,8 @@ thread_stacks:
.section ".textfirst", "ax", @progbits
.code32
.globl _start
.globl __rmodule_entry
__rmodule_entry:
_start:
cli
lgdt %cs:gdtaddr

View file

@ -25,12 +25,12 @@ ramstage-srcs += $(SIPI_BIN)
rmodules-y += sipi_vector.S
rmodules-y += sipi_header.c
$(SIPI_DOTO): $(dir $(SIPI_ELF))sipi_vector.rmodules.o $(dir $(SIPI_ELF))sipi_header.rmodules.o
$(SIPI_DOTO): $(dir $(SIPI_ELF))sipi_vector.rmodules.o
$(CC) $(LDFLAGS) -nostdlib -r -o $@ $^
$(eval $(call rmodule_link,$(SIPI_ELF), $(SIPI_ELF:.elf=.o), 0))
$(eval $(call rmodule_link,$(SIPI_ELF), $(SIPI_DOTO), 0))
$(SIPI_BIN): $(SIPI_ELF)
$(SIPI_BIN): $(SIPI_ELF).rmod
$(OBJCOPY) -O binary $< $@
$(SIPI_BIN).ramstage.o: $(SIPI_BIN)

View file

@ -1,6 +0,0 @@
#include <rmodule.h>
extern void *ap_start;
DEFINE_RMODULE_HEADER(sipi_vector_header, ap_start, RMODULE_TYPE_SIPI_VECTOR);

View file

@ -58,6 +58,8 @@ apic_to_cpu_num:
.text
.code16
.global ap_start
.global __rmodule_entry
__rmodule_entry:
ap_start:
cli
xorl %eax, %eax

View file

@ -164,11 +164,18 @@ static int bsp_setup_msr_save_state(struct smm_relocation_params *relo_params)
/* The relocation work is actually performed in SMM context, but the code
* resides in the ramstage module. This occurs by trampolining from the default
* SMRAM entry point to here. */
static void asmlinkage
cpu_smm_do_relocation(void *arg, int cpu, const struct smm_runtime *runtime)
static void asmlinkage cpu_smm_do_relocation(void *arg)
{
msr_t mtrr_cap;
struct smm_relocation_params *relo_params = arg;
struct smm_relocation_params *relo_params;
const struct smm_module_params *p;
const struct smm_runtime *runtime;
int cpu;
p = arg;
runtime = p->runtime;
relo_params = p->arg;
cpu = p->cpu;
if (cpu >= CONFIG_MAX_CPUS) {
printk(BIOS_CRIT,

View file

@ -4,6 +4,7 @@ subdirs-$(CONFIG_PARALLEL_MP) += name
ramstage-$(CONFIG_PARALLEL_MP) += mp_init.c
SIPI_ELF=$(obj)/cpu/x86/sipi_vector.elf
SIPI_RMOD=$(SIPI_ELF).rmod
SIPI_BIN=$(SIPI_ELF:.elf=)
SIPI_DOTO=$(SIPI_ELF:.elf=.o)
@ -11,14 +12,13 @@ ifeq ($(CONFIG_PARALLEL_MP),y)
ramstage-srcs += $(SIPI_BIN)
endif
rmodules-$(CONFIG_PARALLEL_MP) += sipi_vector.S
rmodules-$(CONFIG_PARALLEL_MP) += sipi_header.c
$(SIPI_DOTO): $(dir $(SIPI_ELF))sipi_vector.rmodules.o $(dir $(SIPI_ELF))sipi_header.rmodules.o
$(SIPI_DOTO): $(dir $(SIPI_ELF))sipi_vector.rmodules.o
$(CC) $(LDFLAGS) -nostdlib -r -o $@ $^
$(eval $(call rmodule_link,$(SIPI_ELF), $(SIPI_ELF:.elf=.o), 0))
$(SIPI_BIN): $(SIPI_ELF)
$(SIPI_BIN): $(SIPI_RMOD)
$(OBJCOPY) -O binary $< $@
$(SIPI_BIN).ramstage.o: $(SIPI_BIN)

View file

@ -1,6 +0,0 @@
#include <rmodule.h>
extern void *ap_start;
DEFINE_RMODULE_HEADER(sipi_vector_header, ap_start, RMODULE_TYPE_SIPI_VECTOR);

View file

@ -58,6 +58,8 @@ ap_count:
.text
.code16
.global ap_start
.global __rmodule_entry
__rmodule_entry:
ap_start:
cli
xorl %eax, %eax

View file

@ -21,10 +21,8 @@ ramstage-$(CONFIG_BACKUP_DEFAULT_SMM_REGION) += backup_default_smm.c
ifeq ($(CONFIG_SMM_MODULES),y)
smmstub-y += smm_stub.S
smmstub-y += smm_module_header.c
smm-y += smiutil.c
smm-y += smm_module_header.c
smm-y += smm_module_handler.c
ramstage-y += smm_module_loader.c
@ -40,7 +38,7 @@ $(obj)/cpu/x86/smm/smmstub.o: $$(smmstub-objs)
# Link the SMM stub module with a 0-byte heap.
$(eval $(call rmodule_link,$(obj)/cpu/x86/smm/smmstub.elf, $(obj)/cpu/x86/smm/smmstub.o, 0))
$(obj)/cpu/x86/smm/smmstub: $(obj)/cpu/x86/smm/smmstub.elf
$(obj)/cpu/x86/smm/smmstub: $(obj)/cpu/x86/smm/smmstub.elf.rmod
$(OBJCOPY) -O binary $< $@
$(obj)/cpu/x86/smm/smmstub.ramstage.o: $(obj)/cpu/x86/smm/smmstub
@ -55,7 +53,7 @@ $(obj)/cpu/x86/smm/smm.o: $$(smm-objs) $(LIBGCC_FILE_NAME)
$(eval $(call rmodule_link,$(obj)/cpu/x86/smm/smm.elf, $(obj)/cpu/x86/smm/smm.o, $(CONFIG_SMM_MODULE_HEAP_SIZE)))
$(obj)/cpu/x86/smm/smm: $(obj)/cpu/x86/smm/smm.elf
$(obj)/cpu/x86/smm/smm: $(obj)/cpu/x86/smm/smm.elf.rmod
$(OBJCOPY) -O binary $< $@
$(obj)/cpu/x86/smm/smm.ramstage.o: $(obj)/cpu/x86/smm/smm

View file

@ -20,6 +20,7 @@
#include <arch/io.h>
#include <console/console.h>
#include <cpu/x86/smm.h>
#include <rmodule.h>
typedef enum { SMI_LOCKED, SMI_UNLOCKED } smi_semaphore;
@ -113,8 +114,16 @@ void *smm_get_save_state(int cpu)
return base;
}
void smm_handler_start(void *arg, int cpu, const struct smm_runtime *runtime)
void asmlinkage smm_handler_start(void *arg)
{
const struct smm_module_params *p;
const struct smm_runtime *runtime;
int cpu;
p = arg;
runtime = p->runtime;
cpu = p->cpu;
/* Make sure to set the global runtime. It's OK to race as the value
* will be the same across CPUs as well as multiple SMIs. */
if (smm_runtime == NULL)
@ -157,6 +166,8 @@ void smm_handler_start(void *arg, int cpu, const struct smm_runtime *runtime)
smi_set_eos();
}
RMODULE_ENTRY(smm_handler_start);
/* Provide a default implementation for all weak handlers so that relocation
* entries in the modules make sense. Without default implementations the
* weak relocations w/o a symbol have a 0 address which is where the modules

View file

@ -1,24 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 ChromeOS Authors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <rmodule.h>
extern char smm_handler_start[];
DEFINE_RMODULE_HEADER(smm_module, smm_handler_start, RMODULE_TYPE_SMM);

View file

@ -61,6 +61,8 @@ fallback_stack_top:
.text
.code16
.global smm_handler_start
.global __rmodule_entry
__rmodule_entry:
smm_handler_start:
movl $(smm_relocate_gdt), %ebx
data32 lgdt (%ebx)
@ -132,11 +134,13 @@ smm_trampoline32:
2:
/* Call into the c-based SMM relocation function with the platform
* parameters. Equivalent to:
* c_handler(c_handler_params, cpu_num, smm_runtime);
* struct arg = { c_handler_params, cpu_num, smm_runtime {;
* c_handler(&arg)
*/
push $(smm_runtime)
push %ecx
push c_handler_arg
push %esp
mov c_handler, %eax
call *%eax

View file

@ -517,14 +517,20 @@ struct smm_runtime {
u8 apic_id_to_cpu[CONFIG_MAX_CPUS];
} __attribute__ ((packed));
typedef void asmlinkage (*smm_handler_t)(void *arg, int cpu,
const struct smm_runtime *runtime);
struct smm_module_params {
void *arg;
int cpu;
const struct smm_runtime *runtime;
};
/* smm_handler_t is called with arg of smm_module_params pointer. */
typedef void asmlinkage (*smm_handler_t)(void *);
#ifdef __SMM__
/* SMM Runtime helpers. */
/* Entry point for SMM modules. */
void smm_handler_start(void *arg, int cpu, const struct smm_runtime *runtime);
void asmlinkage smm_handler_start(void *params);
/* Retrieve SMM save state for a given CPU. WARNING: This does not take into
* account CPUs which are configured to not save their state to RAM. */

View file

@ -0,0 +1,63 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Google Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RMODULE_DEFS_H
#define RMODULE_DEFS_H
#include <stdint.h>
#include <stddef.h>
#define RMODULE_MAGIC 0xf8fe
#define RMODULE_VERSION_1 1
/* All fields with '_offset' in the name are byte offsets into the flat blob.
* The linker and the linker script takes are of assigning the values. */
struct rmodule_header {
uint16_t magic;
uint8_t version;
uint8_t type;
/* The payload represents the program's loadable code and data. */
uint32_t payload_begin_offset;
uint32_t payload_end_offset;
/* Begin and of relocation information about the program module. */
uint32_t relocations_begin_offset;
uint32_t relocations_end_offset;
/* The starting address of the linked program. This address is vital
* for determining relocation offsets as the relocation info and other
* symbols (bss, entry point) need this value as a basis to calculate
* the offsets.
*/
uint32_t module_link_start_address;
/* The module_program_size is the size of memory used while running
* the program. The program is assumed to consume a contiguous amount
* of memory. */
uint32_t module_program_size;
/* This is program's execution entry point. */
uint32_t module_entry_point;
/* Optional parameter structure that can be used to pass data into
* the module. */
uint32_t parameters_begin;
uint32_t parameters_end;
/* BSS section information so the loader can clear the bss. */
uint32_t bss_begin;
uint32_t bss_end;
/* Add some room for growth. */
uint32_t padding[4];
} __attribute__ ((packed));
#endif /* RMODULE_DEFS_H */

View file

@ -21,9 +21,8 @@
#include <stdint.h>
#include <stddef.h>
#define RMODULE_MAGIC 0xf8fe
#define RMODULE_VERSION_1 1
#include <string.h>
#include <rmodule-defs.h>
enum {
RMODULE_TYPE_SMM,
@ -52,34 +51,7 @@ int rmodule_load_alignment(const struct rmodule *m);
int rmodule_calc_region(unsigned int region_alignment, size_t rmodule_size,
size_t *region_size, int *load_offset);
#define FIELD_ENTRY(x_) ((u32)&x_)
#define RMODULE_HEADER(entry_, type_) \
{ \
.magic = RMODULE_MAGIC, \
.version = RMODULE_VERSION_1, \
.type = type_, \
.payload_begin_offset = FIELD_ENTRY(_payload_begin_offset), \
.payload_end_offset = FIELD_ENTRY(_payload_end_offset), \
.relocations_begin_offset = \
FIELD_ENTRY(_relocations_begin_offset), \
.relocations_end_offset = \
FIELD_ENTRY(_relocations_end_offset), \
.module_link_start_address = \
FIELD_ENTRY(_module_link_start_addr), \
.module_program_size = FIELD_ENTRY(_module_program_size), \
.module_entry_point = FIELD_ENTRY(entry_), \
.parameters_begin = FIELD_ENTRY(_module_params_begin), \
.parameters_end = FIELD_ENTRY(_module_params_end), \
.bss_begin = FIELD_ENTRY(_bss), \
.bss_end = FIELD_ENTRY(_ebss), \
}
#define DEFINE_RMODULE_HEADER(name_, entry_, type_) \
struct rmodule_header name_ \
__attribute__ ((section (".module_header"))) = \
RMODULE_HEADER(entry_, type_)
/* Support for loading rmodule stages. This API is only available wwhen
/* Support for loading rmodule stages. This API is only available when
* using dynamic cbmem because it uses the dynamic cbmem API to obtain
* the backing store region for the stage. */
#if CONFIG_DYNAMIC_CBMEM
@ -100,43 +72,6 @@ int rmodule_stage_load(struct rmod_stage_load *rsl, struct cbfs_stage *stage);
int rmodule_stage_load_from_cbfs(struct rmod_stage_load *rsl);
#endif
/* Private data structures below should not be used directly. */
/* All fields with '_offset' in the name are byte offsets into the flat blob.
* The linker and the linker script takes are of assigning the values. */
struct rmodule_header {
u16 magic;
u8 version;
u8 type;
/* The payload represents the program's loadable code and data. */
u32 payload_begin_offset;
u32 payload_end_offset;
/* Begin and of relocation information about the program module. */
u32 relocations_begin_offset;
u32 relocations_end_offset;
/* The starting address of the linked program. This address is vital
* for determining relocation offsets as the reloction info and other
* symbols (bss, entry point) need this value as a basis to calculate
* the offsets.
*/
u32 module_link_start_address;
/* The module_program_size is the size of memory used while running
* the program. The program is assumed to consume a contiguos amount
* of memory. */
u32 module_program_size;
/* This is program's execution entry point. */
u32 module_entry_point;
/* Optional paramter structure that can be used to pass data into
* the module. */
u32 parameters_begin;
u32 parameters_end;
/* BSS section information so the loader can clear the bss. */
u32 bss_begin;
u32 bss_end;
/* Add some room for growth. */
u32 padding[4];
} __attribute__ ((packed));
struct rmodule {
void *location;
struct rmodule_header *header;
@ -145,17 +80,12 @@ struct rmodule {
void *relocations;
};
/* These are the symbols assumed that every module contains. The linker script
* provides these symbols. */
extern char _relocations_begin_offset[];
extern char _relocations_end_offset[];
extern char _payload_end_offset[];
extern char _payload_begin_offset[];
extern char _bss[];
extern char _ebss[];
extern char _module_program_size[];
extern char _module_link_start_addr[];
extern char _module_params_begin[];
extern char _module_params_end[];
#if IS_ENABLED(CONFIG_RELOCATABLE_MODULES)
/* Rmodules have an entry point of named __rmodule_entry. */
#define RMODULE_ENTRY(entry_) \
void __rmodule_entry(void *) __attribute__((alias (STRINGIFY(entry_))))
#else
#define RMODULE_ENTRY(entry_)
#endif
#endif /* RMODULE_H */

View file

@ -150,31 +150,41 @@ romstage-$(CONFIG_RELOCATABLE_RAMSTAGE) += rmodule.c
RMODULE_LDSCRIPT := $(src)/lib/rmodule.ld
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
RMODULE_LDFLAGS := -nostartfiles -shared -z defs -nostdlib -Bsymbolic -T $(RMODULE_LDSCRIPT)
RMODULE_LDFLAGS := -nostartfiles -Wl,--emit-relocs -Wl,-z,defs -Wl,-Bsymbolic -Wl,-T,$(RMODULE_LDSCRIPT)
# rmodule_link_rules is a function that should be called with:
# (1) the object name to link
# (2) the dependencies
# (3) heap size of the relocatable module
# It will create the necessary Make rules.
# It will create the necessary Make rules to create a rmodule. The resulting
# rmdoule is named $(1).rmod
define rmodule_link
$(strip $(1)): $(strip $(2)) $$(RMODULE_LDSCRIPT) $$(obj)/ldoptions
$$(LD) $$(RMODULE_LDFLAGS) --defsym=__heap_size=$(strip $(3)) -o $$@ --start-group $(strip $(2)) $$(LIBGCC_FILE_NAME) --end-group
$$(NM) -n $$@ > $$(basename $$@).map
$(strip $(1)).rmod: $(strip $(1))
$$(RMODTOOL) -i $$^ -o $$@
endef
else
RMODULE_LDFLAGS := -nostartfiles -shared -Wl,-z,defs -Wl,-Bsymbolic -Wl,-T,$(RMODULE_LDSCRIPT)
RMODULE_LDFLAGS := -nostartfiles -Wl,--emit-relocs -Wl,-z,defs -Wl,-Bsymbolic -Wl,-T,$(RMODULE_LDSCRIPT)
# rmodule_link_rules is a function that should be called with:
# (1) the object name to link
# (2) the dependencies
# (3) heap size of the relocatable module
# It will create the necessary Make rules.
# It will create the necessary Make rules to create a rmodule. The resulting
# rmdoule is named $(1).rmod
define rmodule_link
$(strip $(1)): $(strip $(2)) $$(RMODULE_LDSCRIPT) $$(obj)/ldoptions
$(strip $(1)): $(strip $(2)) $$(RMODULE_LDSCRIPT) $$(obj)/ldoptions $$(RMODTOOL)
$$(CC) $$(CFLAGS) $$(RMODULE_LDFLAGS) -Wl,--defsym=__heap_size=$(strip $(3)) -o $$@ -Wl,--start-group $(strip $(2)) $$(LIBGCC_FILE_NAME) -Wl,--end-group
$$(NM) -n $$@ > $$(basename $$@).map
$(strip $(1)).rmod: $(strip $(1))
$$(RMODTOOL) -i $$^ -o $$@
endef
endif

View file

@ -26,78 +26,6 @@
/* Change this define to get more verbose debugging for module loading. */
#define PK_ADJ_LEVEL BIOS_NEVER
#if CONFIG_ARCH_X86
/*
* On X86, the only relocations currently allowed are R_386_RELATIVE which
* have '0' for the symbol info in the relocation metadata (in r_info).
* The reason is that the module is fully linked and just has the relocations'
* locations.
*/
typedef struct {
u32 r_offset;
u32 r_info;
} Elf32_Rel;
#define R_386_RELATIVE 8
#define RELOCTION_ENTRY_SIZE sizeof(Elf32_Rel)
static inline int rmodule_reloc_offset(const void *reloc)
{
const Elf32_Rel *rel = reloc;
return rel->r_offset;
}
static inline int rmodule_reloc_valid(const void *reloc)
{
const Elf32_Rel *rel = reloc;
return (rel->r_info == R_386_RELATIVE);
}
static inline void *remodule_next_reloc(const void *reloc)
{
const Elf32_Rel *rel = reloc;
rel++;
return (void *)rel;
}
#elif CONFIG_ARCH_ARM
/*
* On ARM, the only relocations currently allowed are R_ARM_RELATIVE which
* have '0' for the symbol info in the relocation metadata (in r_info).
* The reason is that the module is fully linked and just has the relocations'
* locations.
*/
typedef struct {
u32 r_offset;
u32 r_info;
} Elf32_Rel;
#define R_ARM_RELATIVE 23
#define RELOCTION_ENTRY_SIZE sizeof(Elf32_Rel)
static inline int rmodule_reloc_offset(const void *reloc)
{
const Elf32_Rel *rel = reloc;
return rel->r_offset;
}
static inline int rmodule_reloc_valid(const void *reloc)
{
const Elf32_Rel *rel = reloc;
return (rel->r_info == R_ARM_RELATIVE);
}
static inline void *remodule_next_reloc(const void *reloc)
{
const Elf32_Rel *rel = reloc;
rel++;
return (void *)rel;
}
#else
#error Arch needs to add relocation information support for RMODULE
#endif
static inline int rmodule_is_loaded(const struct rmodule *module)
{
return module->location != NULL;
@ -105,7 +33,7 @@ static inline int rmodule_is_loaded(const struct rmodule *module)
/* Calculate a loaded program address based on the blob address. */
static inline void *rmodule_load_addr(const struct rmodule *module,
u32 blob_addr)
uintptr_t blob_addr)
{
char *loc = module->location;
return &loc[blob_addr - module->header->module_link_start_address];
@ -185,13 +113,13 @@ static void rmodule_clear_bss(struct rmodule *module)
memset(begin, 0, size);
}
static inline int rmodule_number_relocations(const struct rmodule *module)
static inline size_t rmodule_number_relocations(const struct rmodule *module)
{
int r;
size_t r;
r = module->header->relocations_end_offset;
r -= module->header->relocations_begin_offset;
r /= RELOCTION_ENTRY_SIZE;
r /= sizeof(uintptr_t);
return r;
}
@ -210,51 +138,33 @@ static void rmodule_copy_payload(const struct rmodule *module)
memcpy(module->location, module->payload, module->payload_size);
}
static inline u32 *rmodule_adjustment_location(const struct rmodule *module,
const void *reloc)
{
int reloc_offset;
/* Don't relocate header field entries -- only program relocations. */
reloc_offset = rmodule_reloc_offset(reloc);
if (reloc_offset < module->header->module_link_start_address)
return NULL;
return rmodule_load_addr(module, reloc_offset);
}
static int rmodule_relocate(const struct rmodule *module)
{
int num_relocations;
const void *reloc;
u32 adjustment;
size_t num_relocations;
const uintptr_t *reloc;
uintptr_t adjustment;
/* Each relocation needs to be adjusted relative to the beginning of
* the loaded program. */
adjustment = (u32)rmodule_load_addr(module, 0);
adjustment = (uintptr_t)rmodule_load_addr(module, 0);
reloc = module->relocations;
num_relocations = rmodule_number_relocations(module);
printk(BIOS_DEBUG, "Processing %d relocs with adjust value of 0x%08x\n",
printk(BIOS_DEBUG, "Processing %zu relocs. Offset value of 0x%08x\n",
num_relocations, adjustment);
while (num_relocations > 0) {
u32 *adjust_loc;
if (!rmodule_reloc_valid(reloc))
return -1;
uintptr_t *adjust_loc;
/* If the adjustment location is non-NULL adjust it. */
adjust_loc = rmodule_adjustment_location(module, reloc);
if (adjust_loc != NULL) {
printk(PK_ADJ_LEVEL, "Adjusting %p: 0x%08x -> 0x%08x\n",
adjust_loc = rmodule_load_addr(module, *reloc);
printk(PK_ADJ_LEVEL, "Adjusting %p: 0x%08x -> 0x%08x\n",
adjust_loc, *adjust_loc,
*adjust_loc + adjustment);
*adjust_loc += adjustment;
}
reloc = remodule_next_reloc(reloc);
reloc++;
num_relocations--;
}
@ -266,8 +176,8 @@ int rmodule_load_alignment(const struct rmodule *module)
/* The load alignment is the start of the program's linked address.
* The base address where the program is loaded needs to be a multiple
* of the program's starting link address. That way all data alignment
* in the program is presered. */
return module->header->module_link_start_address;
* in the program is preserved. Default to 4KiB. */
return 4096;
}
int rmodule_load(void *base, struct rmodule *module)

View file

@ -4,13 +4,12 @@
* anywhere in the address space.
*
* NOTE: The program's loadable sections (text, module_params, and data) are
* packed into the flat blob using the AT directive. The rmodule loader assumes
* the entire program resides in one contiguous address space. Therefore,
* alignment for a given section (if required) needs to be done at the end of
* the preceeding section. e.g. if the data section should be aligned to an 8
* byte address the text section should have ALIGN(8) at the end of its section.
* Otherwise there won't be a consistent mapping between the flat blob and the
* loaded program.
* packed into the flat blob. The rmodule loader assumes the entire program
* resides in one contiguous address space. Therefore, alignment for a given
* section (if required) needs to be done at the end of the preceeding section.
* e.g. if the data section should be aligned to an 8 byte address the text
* section should have ALIGN(8) at the end of its section. Otherwise there
* won't be a consistent mapping between the flat blob and the loaded program.
*/
BASE_ADDRESS = 0x00000;
@ -19,21 +18,9 @@ SECTIONS
{
. = BASE_ADDRESS;
.header : AT (0) {
*(.module_header);
. = ALIGN(8);
}
/* Align the start of the module program to a large enough alignment
* so that any data in the program with an alignement property is met.
* Essentially, this alignment is the maximum possible data alignment
* property a program can have. */
. = ALIGN(4096);
_module_link_start_addr = .;
_payload_begin_offset = LOADADDR(.header) + SIZEOF(.header);
.payload : AT (_payload_begin_offset) {
.payload : {
/* C code of the module. */
_ram_seg = .;
*(.textfirst);
*(.text);
*(.text.*);
@ -79,20 +66,20 @@ SECTIONS
/* Data section. */
_sdata = .;
*(.data);
*(.data.*);
. = ALIGN(4);
_edata = .;
. = ALIGN(8);
}
/* _payload_end marks the end of the module's code and data. */
_payload_end_offset = LOADADDR(.payload) + SIZEOF(.payload);
.bss (NOLOAD) : {
/* C uninitialized data of the module. */
_bss = .;
*(.bss);
*(.sbss);
*(.bss.*)
*(.sbss)
*(.sbss.*)
*(COMMON);
. = ALIGN(8);
_ebss = .;
@ -104,38 +91,11 @@ SECTIONS
_heap = .;
. = . + __heap_size;
_eheap = .;
_eram_seg = .;
}
/* _module_program_size is the total memory used by the program. */
_module_program_size = _eheap - _module_link_start_addr;
/* coreboot's ramstage uses the _ram_seg and _eram_seg symbols
* for determining its load location. Provide those to help it out.
* It's a nop for any non-ramstage rmodule. */
_ram_seg = _module_link_start_addr;
_eram_seg = _module_link_start_addr + _module_program_size;
/* The relocation information is linked on top of the BSS section
* because the BSS section takes no space on disk. The relocation data
* resides directly after the data section in the flat binary. */
.relocations ADDR(.bss) : AT (_payload_end_offset) {
*(.rel.*);
}
_relocations_begin_offset = LOADADDR(.relocations);
_relocations_end_offset = _relocations_begin_offset +
SIZEOF(.relocations);
/DISCARD/ : {
/* Drop unnecessary sections. Since these modules are linked
* as shared objects there are dynamic sections. These sections
* aren't needed so drop them. */
*(.comment);
*(.note);
*(.note.*);
*(.dynamic);
*(.dynsym);
*(.dynstr);
*(.gnu.hash);
/* Drop unnecessary sections. */
*(.eh_frame);
}
}

View file

@ -200,11 +200,17 @@ static void adjust_apic_id_map(struct smm_loader_params *smm_params)
runtime->apic_id_to_cpu[i] = mp_get_apic_id(i);
}
static void asmlinkage
cpu_smm_do_relocation(void *arg, int cpu, const struct smm_runtime *runtime)
static void asmlinkage cpu_smm_do_relocation(void *arg)
{
msr_t smrr;
em64t100_smm_state_save_area_t *smm_state;
const struct smm_module_params *p;
const struct smm_runtime *runtime;
int cpu;
p = arg;
runtime = p->runtime;
cpu = p->cpu;
if (cpu >= CONFIG_MAX_CPUS) {
printk(BIOS_CRIT,

View file

@ -55,6 +55,7 @@ VB_INCLUDES += -I$(VB_SOURCE)/firmware/include
INCLUDES += $(VB_INCLUDES)
VBOOT_STUB_ELF = $(obj)/vendorcode/google/chromeos/vbootstub.elf
VBOOT_STUB = $(VBOOT_STUB_ELF).rmod
VBOOT_STUB_DOTO = $(VBOOT_STUB_ELF:.elf=.o)
# Dependency for the vboot rmodules. Ordering matters.

View file

@ -28,10 +28,6 @@
#include "vboot_context.h"
#include "vboot_handoff.h"
static void vboot_wrapper(struct vboot_context *context);
DEFINE_RMODULE_HEADER(vboot_wrapper_header, vboot_wrapper, RMODULE_TYPE_VBOOT);
/* Keep a global context pointer around for the callbacks to use. */
static struct vboot_context *gcontext;
@ -67,12 +63,14 @@ static void parse_component(const struct components *components, int num,
fw->size = (uint32_t)components->entries[num].size;
}
static void vboot_wrapper(struct vboot_context *context)
static void vboot_wrapper(void *arg)
{
int i;
VbError_t res;
const struct components *components;
struct vboot_context *context;
context = arg;
gcontext = context;
VbExDebug("Calling VbInit()\n");
@ -276,3 +274,4 @@ VbError_t VbExTpmSendReceive(const uint8_t *request, uint32_t request_length,
return VBERROR_SUCCESS;
}
RMODULE_ENTRY(vboot_wrapper);

View file

@ -8,28 +8,37 @@ CFLAGS += -Wwrite-strings -Wredundant-decls -Wno-trigraphs
CFLAGS += -Wstrict-aliasing -Wshadow -Werror
LDFLAGS += -g
BINARY:=$(obj)/cbfstool
CBFSTOOL_BINARY:=$(obj)/cbfstool
COMMON:=cbfstool.o common.o cbfs_image.o compress.o fit.o
COMMON+=elfheaders.o cbfs-mkstage.o cbfs-mkpayload.o xdr.o
CBFSTOOL_COMMON:=cbfstool.o common.o cbfs_image.o compress.o fit.o
CBFSTOOL_COMMON+=elfheaders.o cbfs-mkstage.o cbfs-mkpayload.o xdr.o
# LZMA
COMMON+=lzma/lzma.o
COMMON+=lzma/C/LzFind.o lzma/C/LzmaDec.o lzma/C/LzmaEnc.o
CBFSTOOL_COMMON+=lzma/lzma.o
CBFSTOOL_COMMON+=lzma/C/LzFind.o lzma/C/LzmaDec.o lzma/C/LzmaEnc.o
COMMON:=$(addprefix $(obj)/,$(COMMON))
CBFSTOOL_COMMON:=$(addprefix $(obj)/,$(CBFSTOOL_COMMON))
all: dep $(BINARY)
RMODTOOL_BINARY:=$(obj)/rmodtool
RMODTOOL_COMMON:=rmodtool.o rmodule.o common.o elfheaders.o xdr.o
RMODTOOL_COMMON:=$(addprefix $(obj)/,$(RMODTOOL_COMMON))
all: dep $(CBFSTOOL_BINARY) $(RMODTOOL_BINARY)
$(obj)/%.o: %.c
$(HOSTCC) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(COMMON) $(BINARY)
rm -f $(CBFSTOOL_COMMON) $(CBFSTOOL_BINARY)
rm -f $(RMODTOOL_COMMON) $(RMODTOOL_BINARY)
tags:
ctags *.[ch]
$(obj)/cbfstool:$(COMMON)
$(obj)/cbfstool:$(CBFSTOOL_COMMON)
$(HOSTCC) $(CFLAGS) -o $@ $^
$(obj)/rmodtool:$(RMODTOOL_COMMON)
$(HOSTCC) $(CFLAGS) -o $@ $^
dep:

View file

@ -14,10 +14,16 @@ cbfsobj += LzFind.o
cbfsobj += LzmaDec.o
cbfsobj += LzmaEnc.o
CBFSTOOLFLAGS=-D_7ZIP_ST -g
rmodobj += rmodtool.o
rmodobj += rmodule.o
rmodobj += common.o
rmodobj += elfheaders.o
rmodobj += xdr.o
TOOLFLAGS=-D_7ZIP_ST -g
ifeq ($(shell uname -s | cut -c-7 2>/dev/null), MINGW32)
CBFSTOOLFLAGS+=-mno-ms-bitfields
TOOLFLAGS+=-mno-ms-bitfields
endif
$(objutil)/cbfstool:
@ -25,17 +31,21 @@ $(objutil)/cbfstool:
$(objutil)/cbfstool/%.o: $(top)/util/cbfstool/%.c
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
$(HOSTCC) $(CBFSTOOLFLAGS) $(HOSTCFLAGS) -c -o $@ $<
$(HOSTCC) $(TOOLFLAGS) $(HOSTCFLAGS) -c -o $@ $<
$(objutil)/cbfstool/%.o: $(top)/util/cbfstool/lzma/%.c
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
$(HOSTCC) $(CBFSTOOLFLAGS) $(HOSTCFLAGS) -c -o $@ $<
$(HOSTCC) $(TOOLFLAGS) $(HOSTCFLAGS) -c -o $@ $<
$(objutil)/cbfstool/%.o: $(top)/util/cbfstool/lzma/C/%.c
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
$(HOSTCC) $(CBFSTOOLFLAGS) $(HOSTCFLAGS) -c -o $@ $<
$(HOSTCC) $(TOOLFLAGS) $(HOSTCFLAGS) -c -o $@ $<
$(objutil)/cbfstool/cbfstool: $(objutil)/cbfstool $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
$(HOSTCC) $(CBFSTOOLFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
$(HOSTCC) $(TOOLFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
$(objutil)/cbfstool/rmodtool: $(objutil)/cbfstool $(addprefix $(objutil)/cbfstool/,$(rmodobj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
$(HOSTCC) $(TOOLFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(rmodobj))

View file

@ -23,7 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include "elf.h"
#include "elfparsing.h"
#include "common.h"
#include "cbfs.h"
#include "fv.h"

View file

@ -24,7 +24,7 @@
#include <stdlib.h>
#include <string.h>
#include "elf.h"
#include "elfparsing.h"
#include "common.h"
#include "cbfs.h"

View file

@ -122,11 +122,7 @@ struct cbfs_payload {
#define CBFS_NAME(_c) (((char *) (_c)) + sizeof(struct cbfs_file))
#define CBFS_SUBHEADER(_p) ( (void *) ((((uint8_t *) (_p)) + ntohl((_p)->offset))) )
/* elfheaders.c */
int
elf_headers(const struct buffer *pinput,
Elf64_Ehdr *ehdr,
Elf64_Phdr **pphdr,
Elf64_Shdr **pshdr);
/* common.c */
void cbfs_file_get_header(struct buffer *buf, struct cbfs_file *file);
#endif

View file

@ -24,7 +24,6 @@
#include <string.h>
#include "common.h"
#include "elf.h"
#include "cbfs_image.h"
/* The file name align is not defined in CBFS spec -- only a preference by

View file

@ -26,7 +26,6 @@
#include <unistd.h>
#include <getopt.h>
#include "common.h"
#include "elf.h"
#include "cbfs.h"
#include "cbfs_image.h"
#include "fit.h"
@ -37,7 +36,6 @@ struct command {
int (*function) (void);
};
int verbose = 0;
static struct param {
char *cbfs_name;
char *name;

View file

@ -23,11 +23,11 @@
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include "elf.h"
#include "common.h"
#include "cbfs.h"
/* Utilities */
int verbose = 0;
/* Small, OS/libc independent runtime check for endianess */
int is_big_endian(void)
@ -109,6 +109,15 @@ void buffer_delete(struct buffer *buffer)
uint32_t arch = CBFS_ARCHITECTURE_UNKNOWN;
void cbfs_file_get_header(struct buffer *buf, struct cbfs_file *file)
{
bgets(buf, &file->magic, sizeof(file->magic));
file->len = xdr_be.get32(buf);
file->type = xdr_be.get32(buf);
file->checksum = xdr_be.get32(buf);
file->offset = xdr_be.get32(buf);
}
static struct {
uint32_t arch;
const char *name;
@ -150,12 +159,6 @@ const char *arch_to_string(uint32_t a)
}
int iself(unsigned char *input)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) input;
return !memcmp(ehdr->e_ident, ELFMAG, 4);
}
static const struct filetypes_t {
uint32_t type;
const char *name;

View file

@ -54,6 +54,49 @@ struct buffer {
size_t size;
};
static inline void *buffer_get(const struct buffer *b)
{
return b->data;
}
static inline size_t buffer_size(const struct buffer *b)
{
return b->size;
}
static inline void buffer_set_size(struct buffer *b, size_t size)
{
b->size = size;
}
/*
* Splice a buffer into another buffer. If size is zero the entire buffer
* is spliced while if size is non-zero the buffer is spliced starting at
* offset for size bytes. Note that it's up to caller to bounds check.
*/
static inline void buffer_splice(struct buffer *dest, const struct buffer *src,
size_t offset, size_t size)
{
dest->name = src->name;
dest->data = src->data;
dest->size = src->size;
if (size != 0) {
dest->data += offset;
buffer_set_size(dest, size);
}
}
static inline void buffer_clone(struct buffer *dest, const struct buffer *src)
{
buffer_splice(dest, src, 0, 0);
}
static inline void buffer_seek(struct buffer *b, size_t size)
{
b->size -= size;
b->data += size;
}
/* Creates an empty memory buffer with given size.
* Returns 0 on success, otherwise non-zero. */
int buffer_create(struct buffer *buffer, size_t size, const char *name);
@ -74,8 +117,6 @@ extern uint32_t arch;
const char *arch_to_string(uint32_t a);
uint32_t string_to_arch(const char *arch_string);
int iself(unsigned char *input);
typedef int (*comp_func_ptr) (char *, int, char *, int *);
typedef enum { CBFS_COMPRESS_NONE = 0, CBFS_COMPRESS_LZMA = 1 } comp_algo;
@ -104,9 +145,11 @@ int do_lzma_compress(char *in, int in_len, char *out, int *out_len);
int do_lzma_uncompress(char *dst, int dst_len, char *src, int src_len);
/* xdr.c */
struct xdr {
uint8_t (*get8)(struct buffer *input);
uint16_t (*get16)(struct buffer *input);
uint32_t (*get32)(struct buffer *input);
uint64_t (*get64)(struct buffer *input);
void (*put8)(struct buffer *input, uint8_t val);
void (*put16)(struct buffer *input, uint16_t val);
void (*put32)(struct buffer *input, uint32_t val);
void (*put64)(struct buffer *input, uint64_t val);
@ -114,5 +157,7 @@ struct xdr {
/* xdr.c */
extern struct xdr xdr_le, xdr_be;
size_t bgets(struct buffer *input, void *output, size_t len);
size_t bputs(struct buffer *b, const void *data, size_t len);
#endif

View file

@ -21,7 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include "elf.h"
#include "elfparsing.h"
#include "common.h"
#include "cbfs.h"
@ -121,6 +121,13 @@
* in the buffer struct.
*/
static int iself(const void *input)
{
const Elf32_Ehdr *ehdr = input;
return !memcmp(ehdr->e_ident, ELFMAG, 4);
}
/* Get the ident array, so we can figure out
* endian-ness, word size, and in future other useful
* parameters
@ -128,12 +135,25 @@
static void
elf_eident(struct buffer *input, Elf64_Ehdr *ehdr)
{
memmove(ehdr->e_ident, input->data, sizeof(ehdr->e_ident));
input->data += sizeof(ehdr->e_ident);
input->size -= sizeof(ehdr->e_ident);
bgets(input, ehdr->e_ident, sizeof(ehdr->e_ident));
}
static int
check_size(const struct buffer *b, size_t offset, size_t size, const char *desc)
{
if (size == 0)
return 0;
if (offset >= buffer_size(b) || (offset + size) > buffer_size(b)) {
ERROR("The file is not large enough for the '%s'. "
"%ld bytes @ offset %zu, input %zu bytes.\n",
desc, size, offset, buffer_size(b));
return -1;
}
return 0;
}
static void
elf_ehdr(struct buffer *input, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64)
{
@ -169,7 +189,8 @@ elf_phdr(struct buffer *pinput, Elf64_Phdr *phdr,
* pointer the full entsize; rather than get tricky
* we just advance it below.
*/
struct buffer input = *pinput;
struct buffer input;
buffer_clone(&input, pinput);
if (bit64){
phdr->p_type = xdr->get32(&input);
phdr->p_flags = xdr->get32(&input);
@ -189,8 +210,7 @@ elf_phdr(struct buffer *pinput, Elf64_Phdr *phdr,
phdr->p_flags = xdr->get32(&input);
phdr->p_align = xdr->get32(&input);
}
pinput->size -= entsize;
pinput->data += entsize;
buffer_seek(pinput, entsize);
}
static void
@ -228,8 +248,332 @@ elf_shdr(struct buffer *pinput, Elf64_Shdr *shdr,
shdr->sh_addralign = xdr->get32(&input);
shdr->sh_entsize = xdr->get32(&input);
}
pinput->size -= entsize;
pinput->data += entsize;
buffer_seek(pinput, entsize);
}
static int
phdr_read(const struct buffer *in, struct parsed_elf *pelf,
struct xdr *xdr, int bit64)
{
struct buffer b;
Elf64_Phdr *phdr;
Elf64_Ehdr *ehdr;
int i;
ehdr = &pelf->ehdr;
/* cons up an input buffer for the headers.
* Note that the program headers can be anywhere,
* per the ELF spec, You'd be surprised how many ELF
* readers miss this little detail.
*/
buffer_splice(&b, in, ehdr->e_phoff, ehdr->e_phentsize * ehdr->e_phnum);
if (check_size(in, ehdr->e_phoff, buffer_size(&b), "program headers"))
return -1;
/* gather up all the phdrs.
* We do them all at once because there is more
* than one loop over all the phdrs.
*/
phdr = calloc(ehdr->e_phnum, sizeof(*phdr));
for (i = 0; i < ehdr->e_phnum; i++) {
DEBUG("Parsing segment %d\n", i);
elf_phdr(&b, &phdr[i], ehdr->e_phentsize, xdr, bit64);
/* Ensure the contents are valid within the elf file. */
if (check_size(in, phdr[i].p_offset, phdr[i].p_filesz,
"segment contents"))
return -1;
}
pelf->phdr = phdr;
return 0;
}
static int
shdr_read(const struct buffer *in, struct parsed_elf *pelf,
struct xdr *xdr, int bit64)
{
struct buffer b;
Elf64_Shdr *shdr;
Elf64_Ehdr *ehdr;
int i;
ehdr = &pelf->ehdr;
/* cons up an input buffer for the section headers.
* Note that the section headers can be anywhere,
* per the ELF spec, You'd be surprised how many ELF
* readers miss this little detail.
*/
buffer_splice(&b, in, ehdr->e_shoff, ehdr->e_shentsize * ehdr->e_shnum);
if (check_size(in, ehdr->e_shoff, buffer_size(&b), "section headers"))
return -1;
/* gather up all the shdrs. */
shdr = calloc(ehdr->e_shnum, sizeof(*shdr));
for (i = 0; i < ehdr->e_shnum; i++) {
DEBUG("Parsing section %d\n", i);
elf_shdr(&b, &shdr[i], ehdr->e_shentsize, xdr, bit64);
}
pelf->shdr = shdr;
return 0;
}
static int
reloc_read(const struct buffer *in, struct parsed_elf *pelf,
struct xdr *xdr, int bit64)
{
struct buffer b;
Elf64_Word i;
Elf64_Ehdr *ehdr;
ehdr = &pelf->ehdr;
pelf->relocs = calloc(ehdr->e_shnum, sizeof(Elf64_Rela *));
/* Allocate array for each section that contains relocation entries. */
for (i = 0; i < ehdr->e_shnum; i++) {
Elf64_Shdr *shdr;
Elf64_Rela *rela;
Elf64_Xword j;
Elf64_Xword nrelocs;
int is_rela;
shdr = &pelf->shdr[i];
/* Only process REL and RELA sections. */
if (shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA)
continue;
DEBUG("Checking relocation section %u\n", i);
/* Ensure the section that relocations apply is a valid. */
if (shdr->sh_info >= ehdr->e_shnum ||
shdr->sh_info == SHN_UNDEF) {
ERROR("Relocations apply to an invalid section: %u\n",
shdr[i].sh_info);
return -1;
}
is_rela = shdr->sh_type == SHT_RELA;
/* Determine the number relocations in this section. */
nrelocs = shdr->sh_size / shdr->sh_entsize;
pelf->relocs[i] = calloc(nrelocs, sizeof(Elf64_Rela));
buffer_splice(&b, in, shdr->sh_offset, shdr->sh_size);
if (check_size(in, shdr->sh_offset, buffer_size(&b),
"relocation section")) {
ERROR("Relocation section %u failed.\n", i);
return -1;
}
rela = pelf->relocs[i];
for (j = 0; j < nrelocs; j++) {
if (bit64) {
rela->r_offset = xdr->get64(&b);
rela->r_info = xdr->get64(&b);
if (is_rela)
rela->r_addend = xdr->get64(&b);
} else {
uint32_t r_info;
rela->r_offset = xdr->get32(&b);
r_info = xdr->get32(&b);
rela->r_info = ELF64_R_INFO(ELF32_R_SYM(r_info),
ELF32_R_TYPE(r_info));
if (is_rela)
rela->r_addend = xdr->get32(&b);
}
rela++;
}
}
return 0;
}
static int strtab_read(const struct buffer *in, struct parsed_elf *pelf)
{
Elf64_Ehdr *ehdr;
Elf64_Word i;
ehdr = &pelf->ehdr;
if (ehdr->e_shstrndx >= ehdr->e_shnum) {
ERROR("Section header string table index out of range: %d\n",
ehdr->e_shstrndx);
return -1;
}
/* For each section of type SHT_STRTAB create a symtab buffer. */
pelf->strtabs = calloc(ehdr->e_shnum, sizeof(struct buffer *));
for (i = 0; i < ehdr->e_shnum; i++) {
struct buffer *b;
Elf64_Shdr *shdr = &pelf->shdr[i];
if (shdr->sh_type != SHT_STRTAB)
continue;
b = calloc(1, sizeof(*b));
buffer_splice(b, in, shdr->sh_offset, shdr->sh_size);
if (check_size(in, shdr->sh_offset, buffer_size(b), "strtab")) {
ERROR("STRTAB section not within bounds: %d\n", i);
return -1;
}
pelf->strtabs[i] = b;
}
return 0;
}
static int
symtab_read(const struct buffer *in, struct parsed_elf *pelf,
struct xdr *xdr, int bit64)
{
Elf64_Ehdr *ehdr;
Elf64_Shdr *shdr;
Elf64_Half i;
Elf64_Xword nsyms;
Elf64_Sym *sym;
struct buffer b;
ehdr = &pelf->ehdr;
shdr = NULL;
for (i = 0; i < ehdr->e_shnum; i++) {
if (pelf->shdr[i].sh_type != SHT_SYMTAB)
continue;
if (shdr != NULL) {
ERROR("Multiple symbol sections found. %u and %u\n",
(unsigned int)(shdr - pelf->shdr), i);
return -1;
}
shdr = &pelf->shdr[i];
}
if (shdr == NULL) {
ERROR("No symbol table found.\n");
return -1;
}
buffer_splice(&b, in, shdr->sh_offset, shdr->sh_size);
if (check_size(in, shdr->sh_offset, buffer_size(&b), "symtab"))
return -1;
nsyms = shdr->sh_size / shdr->sh_entsize;
pelf->syms = calloc(nsyms, sizeof(Elf64_Sym));
for (i = 0; i < nsyms; i++) {
sym = &pelf->syms[i];
if (bit64) {
sym->st_name = xdr->get32(&b);
sym->st_info = xdr->get8(&b);
sym->st_other = xdr->get8(&b);
sym->st_shndx = xdr->get16(&b);
sym->st_value = xdr->get64(&b);
sym->st_size = xdr->get64(&b);
} else {
sym->st_name = xdr->get32(&b);
sym->st_value = xdr->get32(&b);
sym->st_size = xdr->get32(&b);
sym->st_info = xdr->get8(&b);
sym->st_other = xdr->get8(&b);
sym->st_shndx = xdr->get16(&b);
}
}
return 0;
}
int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags)
{
struct xdr *xdr = &xdr_le;
int bit64 = 0;
struct buffer input;
Elf64_Ehdr *ehdr;
/* Zero out the parsed elf structure. */
memset(pelf, 0, sizeof(*pelf));
if (!iself(buffer_get(pinput))) {
ERROR("The stage file is not in ELF format!\n");
return -1;
}
buffer_clone(&input, pinput);
ehdr = &pelf->ehdr;
elf_eident(&input, ehdr);
bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
/* Assume LE unless we are sure otherwise.
* We're not going to take on the task of
* fully validating the ELF file. That way
* lies madness.
*/
if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
xdr = &xdr_be;
elf_ehdr(&input, ehdr, xdr, bit64);
/* Relocation processing requires section header parsing. */
if (flags & ELF_PARSE_RELOC)
flags |= ELF_PARSE_SHDR;
/* String table processing requires section header parsing. */
if (flags & ELF_PARSE_STRTAB)
flags |= ELF_PARSE_SHDR;
/* Symbole table processing requires section header parsing. */
if (flags & ELF_PARSE_SYMTAB)
flags |= ELF_PARSE_SHDR;
if ((flags & ELF_PARSE_PHDR) && phdr_read(pinput, pelf, xdr, bit64))
goto fail;
if ((flags & ELF_PARSE_SHDR) && shdr_read(pinput, pelf, xdr, bit64))
goto fail;
if ((flags & ELF_PARSE_RELOC) && reloc_read(pinput, pelf, xdr, bit64))
goto fail;
if ((flags & ELF_PARSE_STRTAB) && strtab_read(pinput, pelf))
goto fail;
if ((flags & ELF_PARSE_SYMTAB) && symtab_read(pinput, pelf, xdr, bit64))
goto fail;
return 0;
fail:
parsed_elf_destroy(pelf);
return -1;
}
void parsed_elf_destroy(struct parsed_elf *pelf)
{
Elf64_Half i;
free(pelf->phdr);
free(pelf->shdr);
if (pelf->relocs != NULL) {
for (i = 0; i < pelf->ehdr.e_shnum; i++)
free(pelf->relocs[i]);
}
free(pelf->relocs);
if (pelf->strtabs != NULL) {
for (i = 0; i < pelf->ehdr.e_shnum; i++)
free(pelf->strtabs[i]);
}
free(pelf->strtabs);
free(pelf->syms);
}
/* Get the headers from the buffer.
@ -245,31 +589,20 @@ elf_headers(const struct buffer *pinput,
Elf64_Phdr **pphdr,
Elf64_Shdr **pshdr)
{
int i;
struct xdr *xdr = &xdr_le;
int bit64 = 0;
struct buffer input = *(struct buffer *)pinput;
struct buffer phdr_buf;
struct buffer shdr_buf;
Elf64_Phdr *phdr;
Elf64_Shdr *shdr;
if (!iself((unsigned char *)pinput->data)) {
ERROR("The stage file is not in ELF format!\n");
struct parsed_elf pelf;
int flags;
flags = ELF_PARSE_PHDR;
if (pshdr != NULL)
flags |= ELF_PARSE_SHDR;
if (parse_elf(pinput, &pelf, flags))
return -1;
}
elf_eident(&input, ehdr);
bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
/* Assume LE unless we are sure otherwise.
* We're not going to take on the task of
* fully validating the ELF file. That way
* lies madness.
*/
if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
xdr = &xdr_be;
elf_ehdr(&input, ehdr, xdr, bit64);
/* Copy out the parsed elf header. */
memcpy(ehdr, &pelf.ehdr, sizeof(*ehdr));
// The tool may work in architecture-independent way.
if (arch != CBFS_ARCHITECTURE_UNKNOWN &&
@ -280,65 +613,334 @@ elf_headers(const struct buffer *pinput,
return -1;
}
if (pinput->size < ehdr->e_phoff){
ERROR("The program header offset is greater than "
"the remaining file size."
"%ld bytes left, program header offset is %ld \n",
pinput->size, ehdr->e_phoff);
return -1;
}
/* cons up an input buffer for the headers.
* Note that the program headers can be anywhere,
* per the ELF spec, You'd be surprised how many ELF
* readers miss this little detail.
*/
phdr_buf.data = &pinput->data[ehdr->e_phoff];
phdr_buf.size = ehdr->e_phentsize * ehdr->e_phnum;
if (phdr_buf.size > (pinput->size - ehdr->e_phoff)){
ERROR("The file is not large enough for the program headers."
"%ld bytes left, %ld bytes of headers\n",
pinput->size - ehdr->e_phoff, phdr_buf.size);
return -1;
}
/* gather up all the phdrs.
* We do them all at once because there is more
* than one loop over all the phdrs.
*/
phdr = calloc(sizeof(*phdr), ehdr->e_phnum);
for (i = 0; i < ehdr->e_phnum; i++)
elf_phdr(&phdr_buf, &phdr[i], ehdr->e_phentsize, xdr, bit64);
*pphdr = phdr;
*pphdr = calloc(ehdr->e_phnum, sizeof(Elf64_Phdr));
memcpy(*pphdr, pelf.phdr, ehdr->e_phnum * sizeof(Elf64_Phdr));
if (!pshdr)
return 0;
if (pinput->size < ehdr->e_shoff){
ERROR("The section header offset is greater than "
"the remaining file size."
"%ld bytes left, program header offset is %ld \n",
pinput->size, ehdr->e_shoff);
return -1;
if (pshdr != NULL) {
*pshdr = calloc(ehdr->e_shnum, sizeof(Elf64_Shdr));
memcpy(*pshdr, pelf.shdr, ehdr->e_shnum * sizeof(Elf64_Shdr));
}
/* cons up an input buffer for the section headers.
* Note that the section headers can be anywhere,
* per the ELF spec, You'd be surprised how many ELF
* readers miss this little detail.
*/
shdr_buf.data = &pinput->data[ehdr->e_shoff];
shdr_buf.size = ehdr->e_shentsize * ehdr->e_shnum;
if (shdr_buf.size > (pinput->size - ehdr->e_shoff)){
ERROR("The file is not large enough for the section headers."
"%ld bytes left, %ld bytes of headers\n",
pinput->size - ehdr->e_shoff, shdr_buf.size);
return -1;
}
/* gather up all the shdrs. */
shdr = calloc(sizeof(*shdr), ehdr->e_shnum);
for (i = 0; i < ehdr->e_shnum; i++)
elf_shdr(&shdr_buf, &shdr[i], ehdr->e_shentsize, xdr, bit64);
*pshdr = shdr;
parsed_elf_destroy(&pelf);
return 0;
}
/* ELF Writing Support
*
* The ELF file is written according to the following layout:
* +------------------+
* | ELF Header |
* +------------------+
* | Section Headers |
* +------------------+
* | Program Headers |
* +------------------+
* | String table |
* +------------------+ <- 4KiB Aligned
* | Code/Data |
* +------------------+
*/
/* Arbitray maximum number of sections. */
#define MAX_SECTIONS 16
struct elf_writer_section {
Elf64_Shdr shdr;
struct buffer content;
const char *name;
};
struct elf_writer
{
Elf64_Ehdr ehdr;
struct xdr *xdr;
size_t num_secs;
struct elf_writer_section sections[MAX_SECTIONS];
Elf64_Phdr *phdrs;
struct elf_writer_section *shstrtab;
int bit64;
};
struct elf_writer *elf_writer_init(const Elf64_Ehdr *ehdr)
{
struct elf_writer *ew;
Elf64_Shdr shdr;
struct buffer empty_buffer;
if (!iself(ehdr))
return NULL;
ew = calloc(1, sizeof(*ew));
memcpy(&ew->ehdr, ehdr, sizeof(ew->ehdr));
ew->bit64 = ew->ehdr.e_ident[EI_CLASS] == ELFCLASS64;
/* Set the endinan ops. */
if (ew->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
ew->xdr = &xdr_be;
else
ew->xdr = &xdr_le;
/* Reset count and offsets */
ew->ehdr.e_phoff = 0;
ew->ehdr.e_shoff = 0;
ew->ehdr.e_shnum = 0;
ew->ehdr.e_phnum = 0;
memset(&empty_buffer, 0, sizeof(empty_buffer));
memset(&shdr, 0, sizeof(shdr));
/* Add SHT_NULL section header. */
shdr.sh_type = SHT_NULL;
elf_writer_add_section(ew, &shdr, &empty_buffer, NULL);
/* Add section header string table and maintain reference to it. */
shdr.sh_type = SHT_STRTAB;
elf_writer_add_section(ew, &shdr, &empty_buffer, ".shstrtab");
ew->ehdr.e_shstrndx = ew->num_secs - 1;
ew->shstrtab = &ew->sections[ew->ehdr.e_shstrndx];
return ew;
}
/*
* Clean up any internal state represented by ew. Aftewards the elf_writer
* is invalid.
*/
void elf_writer_destroy(struct elf_writer *ew)
{
if (ew->phdrs != NULL)
free(ew->phdrs);
free(ew);
}
/*
* Add a section to the ELF file. Section type, flags, and memsize are
* maintained from the passed in Elf64_Shdr. The buffer represents the
* content of the section while the name is the name of section itself.
* Returns < 0 on error, 0 on success.
*/
int elf_writer_add_section(struct elf_writer *ew, const Elf64_Shdr *shdr,
struct buffer *contents, const char *name)
{
struct elf_writer_section *newsh;
if (ew->num_secs == MAX_SECTIONS)
return -1;
newsh = &ew->sections[ew->num_secs];
ew->num_secs++;
memcpy(&newsh->shdr, shdr, sizeof(newsh->shdr));
newsh->shdr.sh_offset = 0;
newsh->name = name;
if (contents != NULL)
buffer_clone(&newsh->content, contents);
return 0;
}
static void ehdr_write(struct elf_writer *ew, struct buffer *m)
{
int i;
for (i = 0; i < EI_NIDENT; i++)
ew->xdr->put8(m, ew->ehdr.e_ident[i]);
ew->xdr->put16(m, ew->ehdr.e_type);
ew->xdr->put16(m, ew->ehdr.e_machine);
ew->xdr->put32(m, ew->ehdr.e_version);
if (ew->bit64) {
ew->xdr->put64(m, ew->ehdr.e_entry);
ew->xdr->put64(m, ew->ehdr.e_phoff);
ew->xdr->put64(m, ew->ehdr.e_shoff);
} else {
ew->xdr->put32(m, ew->ehdr.e_entry);
ew->xdr->put32(m, ew->ehdr.e_phoff);
ew->xdr->put32(m, ew->ehdr.e_shoff);
}
ew->xdr->put32(m, ew->ehdr.e_flags);
ew->xdr->put16(m, ew->ehdr.e_ehsize);
ew->xdr->put16(m, ew->ehdr.e_phentsize);
ew->xdr->put16(m, ew->ehdr.e_phnum);
ew->xdr->put16(m, ew->ehdr.e_shentsize);
ew->xdr->put16(m, ew->ehdr.e_shnum);
ew->xdr->put16(m, ew->ehdr.e_shstrndx);
}
static void shdr_write(struct elf_writer *ew, size_t n, struct buffer *m)
{
struct xdr *xdr = ew->xdr;
int bit64 = ew->bit64;
struct elf_writer_section *sec = &ew->sections[n];
Elf64_Shdr *shdr = &sec->shdr;
xdr->put32(m, shdr->sh_name);
xdr->put32(m, shdr->sh_type);
xdr->put32(m, shdr->sh_flags);
if (bit64) {
xdr->put64(m, shdr->sh_addr);
xdr->put64(m, shdr->sh_offset);
xdr->put64(m, shdr->sh_size);
xdr->put32(m, shdr->sh_link);
xdr->put32(m, shdr->sh_info);
xdr->put64(m, shdr->sh_addralign);
xdr->put64(m, shdr->sh_entsize);
} else {
xdr->put32(m, shdr->sh_addr);
xdr->put32(m, shdr->sh_offset);
xdr->put32(m, shdr->sh_size);
xdr->put32(m, shdr->sh_link);
xdr->put32(m, shdr->sh_info);
xdr->put32(m, shdr->sh_addralign);
xdr->put32(m, shdr->sh_entsize);
}
}
static void
phdr_write(struct elf_writer *ew, struct buffer *m, Elf64_Phdr *phdr)
{
if (ew->bit64) {
ew->xdr->put32(m, phdr->p_type);
ew->xdr->put32(m, phdr->p_flags);
ew->xdr->put64(m, phdr->p_offset);
ew->xdr->put64(m, phdr->p_vaddr);
ew->xdr->put64(m, phdr->p_paddr);
ew->xdr->put64(m, phdr->p_filesz);
ew->xdr->put64(m, phdr->p_memsz);
ew->xdr->put64(m, phdr->p_align);
} else {
ew->xdr->put32(m, phdr->p_type);
ew->xdr->put32(m, phdr->p_offset);
ew->xdr->put32(m, phdr->p_vaddr);
ew->xdr->put32(m, phdr->p_paddr);
ew->xdr->put32(m, phdr->p_filesz);
ew->xdr->put32(m, phdr->p_memsz);
ew->xdr->put32(m, phdr->p_flags);
ew->xdr->put32(m, phdr->p_align);
}
}
/*
* Serialize the ELF file to the output buffer. Return < 0 on error,
* 0 on success.
*/
int elf_writer_serialize(struct elf_writer *ew, struct buffer *out)
{
Elf64_Half i;
Elf64_Xword metadata_size;
Elf64_Xword program_size;
Elf64_Off shstroffset;
size_t shstrlen;
struct buffer metadata;
struct buffer phdrs;
struct buffer data;
struct buffer *strtab;
INFO("Writing %zu sections.\n", ew->num_secs);
/* Determine size of sections to be written. */
program_size = 0;
/* Start with 1 byte for first byte of section header string table. */
shstrlen = 1;
for (i = 0; i < ew->num_secs; i++) {
struct elf_writer_section *sec = &ew->sections[i];
if (sec->shdr.sh_flags & SHF_ALLOC)
ew->ehdr.e_phnum++;
program_size += buffer_size(&sec->content);
/* Keep track of the length sections' names. */
if (sec->name != NULL) {
sec->shdr.sh_name = shstrlen;
shstrlen += strlen(sec->name) + 1;
}
}
ew->ehdr.e_shnum = ew->num_secs;
metadata_size = 0;
metadata_size += ew->ehdr.e_ehsize;
metadata_size += ew->ehdr.e_shnum * ew->ehdr.e_shentsize;
metadata_size += ew->ehdr.e_phnum * ew->ehdr.e_phentsize;
shstroffset = metadata_size;
/* Align up section header string size and metadata size to 4KiB */
metadata_size = ALIGN(metadata_size + shstrlen, 4096);
if (buffer_create(out, metadata_size + program_size, "elfout")) {
ERROR("Could not create output buffer for ELF.\n");
return -1;
}
INFO("Created %zu output buffer for ELF file.\n", buffer_size(out));
/*
* Write out ELF header. Section headers come right after ELF header
* followed by the program headers. Buffers need to be created first
* to do the writing.
*/
ew->ehdr.e_shoff = ew->ehdr.e_ehsize;
ew->ehdr.e_phoff = ew->ehdr.e_shoff +
ew->ehdr.e_shnum * ew->ehdr.e_shentsize;
buffer_splice(&metadata, out, 0, metadata_size);
buffer_splice(&phdrs, out, ew->ehdr.e_phoff,
ew->ehdr.e_phnum * ew->ehdr.e_phentsize);
buffer_splice(&data, out, metadata_size, program_size);
/* Set up the section header string table contents. */
strtab = &ew->shstrtab->content;
buffer_splice(strtab, out, shstroffset, shstrlen);
ew->shstrtab->shdr.sh_size = shstrlen;
/* Reset current locations. */
buffer_set_size(&metadata, 0);
buffer_set_size(&data, 0);
buffer_set_size(&phdrs, 0);
buffer_set_size(strtab, 0);
/* ELF Header */
ehdr_write(ew, &metadata);
/* Write out section headers, section strings, section content, and
* program headers. */
ew->xdr->put8(strtab, 0);
for (i = 0; i < ew->num_secs; i++) {
Elf64_Phdr phdr;
struct elf_writer_section *sec = &ew->sections[i];
/* Update section offsets. Be sure to not update SHT_NULL. */
if (sec == ew->shstrtab)
sec->shdr.sh_offset = shstroffset;
else if (i != 0)
sec->shdr.sh_offset = buffer_size(&data) +
metadata_size;
shdr_write(ew, i, &metadata);
/* Add section name to string table. */
if (sec->name != NULL)
bputs(strtab, sec->name, strlen(sec->name) + 1);
if (!(sec->shdr.sh_flags & SHF_ALLOC))
continue;
bputs(&data, buffer_get(&sec->content),
buffer_size(&sec->content));
phdr.p_type = PT_LOAD;
phdr.p_offset = sec->shdr.sh_offset;
phdr.p_vaddr = sec->shdr.sh_addr;
phdr.p_paddr = sec->shdr.sh_addr;
phdr.p_filesz = buffer_size(&sec->content);
phdr.p_memsz = sec->shdr.sh_size;
phdr.p_flags = 0;
if (sec->shdr.sh_flags & SHF_EXECINSTR)
phdr.p_flags |= PF_X | PF_R;
if (sec->shdr.sh_flags & SHF_WRITE)
phdr.p_flags |= PF_W;
phdr.p_align = sec->shdr.sh_addralign;
phdr_write(ew, &phdrs, &phdr);
}
return 0;
}

107
util/cbfstool/elfparsing.h Normal file
View file

@ -0,0 +1,107 @@
/*
* Copyright (C) 2014 Google, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
*/
#ifndef ELFPARSING_H
#define ELFPARSING_H
#include "elf.h"
#include "common.h"
struct parsed_elf {
Elf64_Ehdr ehdr;
Elf64_Phdr *phdr;
Elf64_Shdr *shdr;
/*
* The relocs array contains pointers to arrays of relocation
* structures. Each index into the relocs array corresponds to its
* corresponding section index. i.e. if a section i is of type SHT_REL
* or SHT_RELA then the corresponding index into the relocs array will
* contain the associated relocations. Otherwise thee entry will be
* NULL.
*/
Elf64_Rela **relocs;
/*
* Similarly to the relocs array the strtabs array consists of an
* array of pointers where each entry represents a potential struct
* buffer pointer. Only setions of type SHT_STRTAB will have a non-NULL
* entry.
*/
struct buffer **strtabs;
/* Parsed symbols. */
Elf64_Sym *syms;
};
#define ELF_PARSE_PHDR (1 << 0)
#define ELF_PARSE_SHDR (1 << 1)
#define ELF_PARSE_RELOC (1 << 2)
#define ELF_PARSE_STRTAB (1 << 3)
#define ELF_PARSE_SYMTAB (1 << 4)
#define ELF_PARSE_ALL (-1)
/*
* Parse an ELF file contained within provide struct buffer. The ELF header
* is always parsed while the flags value containing the ELF_PARSE_* values
* determine if other parts of the ELF file will be parsed as well.
* Returns 0 on success, < 0 error.
*/
int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags);
/*
* Clean up memory associated with parsed_elf.
*/
void parsed_elf_destroy(struct parsed_elf *pelf);
int
elf_headers(const struct buffer *pinput,
Elf64_Ehdr *ehdr,
Elf64_Phdr **pphdr,
Elf64_Shdr **pshdr);
/* ELF writing support. */
struct elf_writer;
/*
* Initialize a new ELF writer. Deafult machine type, endianness, etc is
* copied from the passed in Elf64_Ehdr. Returns NULL on failure, valid
* pointer on success.
*/
struct elf_writer *elf_writer_init(const Elf64_Ehdr *ehdr);
/*
* Clean up any internal state represented by ew. Aftewards the elf_writer
* is invalid.
*/
void elf_writer_destroy(struct elf_writer *ew);
/*
* Add a section to the ELF file. Section type, flags, and memsize are
* maintained from the passed in Elf64_Shdr. The buffer represents the
* content of the section while the name is the name of section itself.
* Returns < 0 on error, 0 on success.
*/
int elf_writer_add_section(struct elf_writer *ew, const Elf64_Shdr *shdr,
struct buffer *contents, const char *name);
/*
* Serialize the ELF file to the output buffer. Return < 0 on error,
* 0 on success.
*/
int elf_writer_serialize(struct elf_writer *ew, struct buffer *out);
#endif /* ELFPARSING_H */

View file

@ -23,7 +23,6 @@
#include <stdio.h>
#include "common.h"
#include "elf.h"
#include "cbfs.h"
#include "cbfs_image.h"
#include "fit.h"
@ -188,17 +187,28 @@ static void add_microcodde_entries(struct cbfs_image *image,
}
}
static int fit_header(void *ptr, uint32_t *current_offset, uint32_t *file_length)
{
struct buffer buf;
struct cbfs_file header;
buf.data = ptr;
buf.size = sizeof(header);
cbfs_file_get_header(&buf, &header);
*current_offset = header.offset;
*file_length = header.len;
return 0;
}
static int parse_microcode_blob(struct cbfs_image *image,
struct cbfs_file *mcode_file,
struct microcode_entry *mcus, int *total_mcus)
{
int num_mcus;
int current_offset;
int file_length;
uint32_t current_offset;
uint32_t file_length;
current_offset = (int)((char *)mcode_file - image->buffer.data);
current_offset += ntohl(mcode_file->offset);
file_length = ntohl(mcode_file->len);
fit_header(mcode_file, &current_offset, &file_length);
num_mcus = 0;
while (file_length > sizeof(struct microcode_header))

106
util/cbfstool/rmodtool.c Normal file
View file

@ -0,0 +1,106 @@
/*
* cbfstool, CLI utility for creating rmodules
*
* Copyright (C) 2014 Google, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include "common.h"
#include "rmodule.h"
static const char *optstring = "i:o:vh?";
static struct option long_options[] = {
{"inelf", required_argument, 0, 'i' },
{"outelf", required_argument, 0, 'o' },
{"verbose", no_argument, 0, 'v' },
{"help", no_argument, 0, 'h' },
{NULL, 0, 0, 0 }
};
static void usage(char *name)
{
printf(
"rmodtool: utility for creating rmodules\n\n"
"USAGE: %s [-h] [-v] <-i|--inelf name> <-o|--outelf name>\n",
name
);
}
int main(int argc, char *argv[])
{
int c;
struct buffer elfin;
struct buffer elfout;
const char *input_file = NULL;
const char *output_file = NULL;
if (argc < 3) {
usage(argv[0]);
return 1;
}
while (1) {
int optindex = 0;
c = getopt_long(argc, argv, optstring, long_options, &optindex);
if (c == -1)
break;
switch (c) {
case 'i':
input_file = optarg;
break;
case 'h':
usage(argv[0]);
return 1;
case 'o':
output_file = optarg;
break;
case 'v':
verbose++;
break;
default:
break;
}
}
if (input_file == NULL || output_file == NULL) {
usage(argv[0]);
return 1;
}
if (buffer_from_file(&elfin, input_file)) {
ERROR("Couldn't read in file '%s'.\n", input_file);
return 1;
}
if (rmodule_create(&elfin, &elfout)) {
ERROR("Unable to create rmodule from '%s'.\n", input_file);
return 1;
}
if (buffer_write_file(&elfout, output_file)) {
ERROR("Unable to write rmodule elf '%s'.\n", output_file);
return 1;
}
return 0;
}

631
util/cbfstool/rmodule.c Normal file
View file

@ -0,0 +1,631 @@
/*
;* Copyright (C) 2014 Google, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elfparsing.h"
#include "rmodule.h"
#include "../../src/include/rmodule-defs.h"
struct rmod_context;
struct arch_ops {
int arch;
/* Determine if relocation is a valid type for the architecture. */
int (*valid_type)(struct rmod_context *ctx, Elf64_Rela *rel);
/* Determine if relocation should be emitted. */
int (*should_emit)(struct rmod_context *ctx, Elf64_Rela *rel);
};
struct rmod_context {
/* Ops to process relocations. */
struct arch_ops *ops;
/* endian conversion ops */
struct xdr *xdr;
/* Parsed ELF sturcture. */
struct parsed_elf pelf;
/* Program segment. */
Elf64_Phdr *phdr;
/* Collection of relocation addresses fixup in the module. */
Elf64_Xword nrelocs;
Elf64_Addr *emitted_relocs;
/* The following fields are addresses within the linked program. */
Elf64_Addr link_addr;
Elf64_Addr entry;
Elf64_Addr parameters_begin;
Elf64_Addr parameters_end;
Elf64_Addr bss_begin;
Elf64_Addr bss_end;
Elf64_Xword size;
};
/*
* Architecture specific support operations.
*/
static int valid_reloc_386(struct rmod_context *ctx, Elf64_Rela *rel)
{
int type;
type = ELF64_R_TYPE(rel->r_info);
/* Only these 2 relocations are expected to be found. */
return (type == R_386_32 || type == R_386_PC32);
}
static int should_emit_386(struct rmod_context *ctx, Elf64_Rela *rel)
{
int type;
type = ELF64_R_TYPE(rel->r_info);
/* R_386_32 relocations are absolute. Must emit these. */
return (type == R_386_32);
}
static struct arch_ops reloc_ops[] = {
{
.arch = EM_386,
.valid_type = valid_reloc_386,
.should_emit = should_emit_386,
},
};
/*
* Relocation processing loops.
*/
static int for_each_reloc(struct rmod_context *ctx, int do_emit)
{
Elf64_Half i;
struct parsed_elf *pelf = &ctx->pelf;
for (i = 0; i < pelf->ehdr.e_shnum; i++) {
Elf64_Shdr *shdr;
Elf64_Rela *relocs;
Elf64_Xword nrelocs;
Elf64_Xword j;
relocs = pelf->relocs[i];
/* No relocations in this section. */
if (relocs == NULL)
continue;
shdr = &pelf->shdr[i];
nrelocs = shdr->sh_size / shdr->sh_entsize;
for (j = 0; j < nrelocs; j++) {
Elf64_Rela *r = &relocs[j];
if (!ctx->ops->valid_type(ctx, r)) {
ERROR("Invalid reloc type: %u\n",
(unsigned int)ELF64_R_TYPE(r->r_info));
return -1;
}
if (ctx->ops->should_emit(ctx, r)) {
int n = ctx->nrelocs;
if (do_emit)
ctx->emitted_relocs[n] = r->r_offset;
ctx->nrelocs++;
}
}
}
return 0;
}
static int find_program_segment(struct rmod_context *ctx)
{
int i;
int nsegments;
struct parsed_elf *pelf;
Elf64_Phdr *phdr;
pelf = &ctx->pelf;
/* Silence 'may be used unitilized in this function' warnings. */
phdr = NULL;
/* There should only be a single loadable segment. */
nsegments = 0;
for (i = 0; i < pelf->ehdr.e_phnum; i++) {
if (pelf->phdr[i].p_type != PT_LOAD)
continue;
phdr = &pelf->phdr[i];
nsegments++;
}
if (nsegments != 1) {
ERROR("Unexepcted number of loadable segments: %d.\n",
nsegments);
return -1;
}
INFO("Segment at 0x%0llx, file size 0x%0llx, mem size 0x%0llx.\n",
(long long)phdr->p_vaddr, (long long)phdr->p_filesz,
(long long)phdr->p_memsz);
ctx->phdr = phdr;
return 0;
}
static int
filter_relocation_sections(struct rmod_context *ctx)
{
int i;
const char *shstrtab;
struct parsed_elf *pelf;
const Elf64_Phdr *phdr;
pelf = &ctx->pelf;
phdr = ctx->phdr;
shstrtab = buffer_get(pelf->strtabs[pelf->ehdr.e_shstrndx]);
/*
* Find all relocation sections that contain relocation entries
* for sections that fall within the bounds of the segment. For
* easier processing the pointer to the relocation array for the
* sections that don't fall within the loadable program are NULL'd
* out.
*/
for (i = 0; i < pelf->ehdr.e_shnum; i++) {
Elf64_Shdr *shdr;
Elf64_Word sh_info;
const char *section_name;
shdr = &pelf->shdr[i];
/* Ignore non-relocation sections. */
if (shdr->sh_type != SHT_RELA && shdr->sh_type != SHT_REL)
continue;
/* Obtain section which relocations apply. */
sh_info = shdr->sh_info;
shdr = &pelf->shdr[sh_info];
section_name = &shstrtab[shdr->sh_name];
DEBUG("Relocation section found for '%s' section.\n",
section_name);
/* Do not process relocations for debug sections. */
if (strstr(section_name, ".debug") != NULL) {
pelf->relocs[i] = NULL;
continue;
}
/*
* If relocations apply to a non program section ignore the
* relocations for future processing.
*/
if (shdr->sh_type != SHT_PROGBITS) {
pelf->relocs[i] = NULL;
continue;
}
if (shdr->sh_addr < phdr->p_vaddr ||
((shdr->sh_addr + shdr->sh_size) >
(phdr->p_vaddr + phdr->p_memsz))) {
ERROR("Relocations being applied to section %d not "
"within segment region.\n", sh_info);
return -1;
}
}
return 0;
}
static int vaddr_cmp(const void *a, const void *b)
{
const Elf64_Addr *pa = a;
const Elf64_Addr *pb = b;
if (*pa < *pb)
return -1;
if (*pa > *pb)
return 1;
return 0;
}
static int collect_relocations(struct rmod_context *ctx)
{
int nrelocs;
/*
* The relocs array in the pelf should only contain relocations that
* apply to the program. Count the number relocations. Then collect
* them into the allocated buffer.
*/
if (for_each_reloc(ctx, 0))
return -1;
nrelocs = ctx->nrelocs;
INFO("%d relocations to be emitted.\n", nrelocs);
if (!nrelocs) {
ERROR("No valid relocations in file.\n");
return -1;
}
/* Reset the counter for indexing into the array. */
ctx->nrelocs = 0;
ctx->emitted_relocs = calloc(nrelocs, sizeof(Elf64_Addr));
/* Write out the relocations into the emitted_relocs array. */
if (for_each_reloc(ctx, 1))
return -1;
if (ctx->nrelocs != nrelocs) {
ERROR("Mismatch counted and emitted relocations: %zu vs %zu.\n",
(size_t)nrelocs, (size_t)ctx->nrelocs);
return -1;
}
/* Sort the relocations by their address. */
qsort(ctx->emitted_relocs, nrelocs, sizeof(Elf64_Addr), vaddr_cmp);
return 0;
}
static int
populate_sym(struct rmod_context *ctx, const char *sym_name, Elf64_Addr *addr,
int nsyms, const char *strtab)
{
int i;
Elf64_Sym *syms;
syms = ctx->pelf.syms;
for (i = 0; i < nsyms; i++) {
if (syms[i].st_name == 0)
continue;
if (strcmp(sym_name, &strtab[syms[i].st_name]))
continue;
DEBUG("%s -> 0x%llx\n", sym_name, (long long)syms[i].st_value);
*addr = syms[i].st_value;
return 0;
}
ERROR("symbol '%s' not found.\n", sym_name);
return -1;
}
static int populate_program_info(struct rmod_context *ctx)
{
int i;
const char *strtab;
struct parsed_elf *pelf;
Elf64_Ehdr *ehdr;
int nsyms;
pelf = &ctx->pelf;
ehdr = &pelf->ehdr;
/* Obtain the string table. */
strtab = NULL;
for (i = 0; i < ehdr->e_shnum; i++) {
if (ctx->pelf.strtabs[i] == NULL)
continue;
/* Don't use the section headers' string table. */
if (i == ehdr->e_shstrndx)
continue;
strtab = buffer_get(ctx->pelf.strtabs[i]);
break;
}
if (strtab == NULL) {
ERROR("No string table found.\n");
return -1;
}
/* Determine number of symbols. */
nsyms = 0;
for (i = 0; i < ehdr->e_shnum; i++) {
if (pelf->shdr[i].sh_type != SHT_SYMTAB)
continue;
nsyms = pelf->shdr[i].sh_size / pelf->shdr[i].sh_entsize;
break;
}
if (populate_sym(ctx, "_module_params_begin", &ctx->parameters_begin,
nsyms, strtab))
return -1;
if (populate_sym(ctx, "_module_params_end", &ctx->parameters_end,
nsyms, strtab))
return -1;
if (populate_sym(ctx, "_bss", &ctx->bss_begin, nsyms, strtab))
return -1;
if (populate_sym(ctx, "_ebss", &ctx->bss_end, nsyms, strtab))
return -1;
if (populate_sym(ctx, "__rmodule_entry", &ctx->entry, nsyms, strtab))
return -1;
/* Link address is the virtual address of the program segment. */
ctx->link_addr = ctx->phdr->p_vaddr;
/* The program size is the memsz of the program segment. */
ctx->size = ctx->phdr->p_memsz;
return 0;
}
static int
add_section(struct elf_writer *ew, struct buffer *data, const char *name,
Elf64_Addr addr, Elf64_Word size)
{
Elf64_Shdr shdr;
int ret;
memset(&shdr, 0, sizeof(shdr));
if (data != NULL) {
shdr.sh_type = SHT_PROGBITS;
shdr.sh_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR;
} else {
shdr.sh_type = SHT_NOBITS;
shdr.sh_flags = SHF_ALLOC;
}
shdr.sh_addr = addr;
shdr.sh_offset = addr;
shdr.sh_size = size;
ret = elf_writer_add_section(ew, &shdr, data, name);
if (ret)
ERROR("Could not add '%s' section.\n", name);
return ret;
}
static int
write_elf(const struct rmod_context *ctx, const struct buffer *in,
struct buffer *out)
{
int i;
int ret;
int bit64;
size_t loc;
size_t rmod_data_size;
struct elf_writer *ew;
struct buffer rmod_data;
struct buffer rmod_header;
struct buffer program;
struct buffer relocs;
Elf64_Xword total_size;
Elf64_Addr addr;
Elf64_Ehdr ehdr;
bit64 = ctx->pelf.ehdr.e_ident[EI_CLASS] == ELFCLASS64;
/*
* 3 sections will be added to the ELF file.
* +------------------+
* | rmodule header |
* +------------------+
* | program |
* +------------------+
* | relocations |
* +------------------+
*/
/* Create buffer for header and relocations. */
rmod_data_size = sizeof(struct rmodule_header);
if (bit64)
rmod_data_size += ctx->nrelocs * sizeof(Elf64_Addr);
else
rmod_data_size += ctx->nrelocs * sizeof(Elf32_Addr);
if (buffer_create(&rmod_data, rmod_data_size, "rmod"))
return -1;
buffer_splice(&rmod_header, &rmod_data,
0, sizeof(struct rmodule_header));
buffer_clone(&relocs, &rmod_data);
buffer_seek(&relocs, sizeof(struct rmodule_header));
/* Reset current location. */
buffer_set_size(&rmod_header, 0);
buffer_set_size(&relocs, 0);
/* Program contents. */
buffer_splice(&program, in, ctx->phdr->p_offset, ctx->phdr->p_filesz);
/* Create ELF writer with modified entry point. */
memcpy(&ehdr, &ctx->pelf.ehdr, sizeof(ehdr));
ehdr.e_entry = ctx->entry;
ew = elf_writer_init(&ehdr);
if (ew == NULL) {
ERROR("Failed to create ELF writer.\n");
buffer_delete(&rmod_data);
return -1;
}
/* Write out rmodule_header. */
ctx->xdr->put16(&rmod_header, RMODULE_MAGIC);
ctx->xdr->put8(&rmod_header, RMODULE_VERSION_1);
ctx->xdr->put8(&rmod_header, 0);
/* payload_begin_offset */
loc = sizeof(struct rmodule_header);
ctx->xdr->put32(&rmod_header, loc);
/* payload_end_offset */
loc += ctx->phdr->p_filesz;
ctx->xdr->put32(&rmod_header, loc);
/* relocations_begin_offset */
ctx->xdr->put32(&rmod_header, loc);
/* relocations_end_offset */
if (bit64)
loc += ctx->nrelocs * sizeof(Elf64_Addr);
else
loc += ctx->nrelocs * sizeof(Elf32_Addr);
ctx->xdr->put32(&rmod_header, loc);
/* module_link_start_address */
ctx->xdr->put32(&rmod_header, ctx->link_addr);
/* module_program_size */
ctx->xdr->put32(&rmod_header, ctx->size);
/* module_entry_point */
ctx->xdr->put32(&rmod_header, ctx->entry);
/* parameters_begin */
ctx->xdr->put32(&rmod_header, ctx->parameters_begin);
/* parameters_end */
ctx->xdr->put32(&rmod_header, ctx->parameters_end);
/* bss_begin */
ctx->xdr->put32(&rmod_header, ctx->bss_begin);
/* bss_end */
ctx->xdr->put32(&rmod_header, ctx->bss_end);
/* padding[4] */
ctx->xdr->put32(&rmod_header, 0);
ctx->xdr->put32(&rmod_header, 0);
ctx->xdr->put32(&rmod_header, 0);
ctx->xdr->put32(&rmod_header, 0);
/* Write the relocations. */
for (i = 0; i < ctx->nrelocs; i++) {
if (bit64)
ctx->xdr->put64(&relocs, ctx->emitted_relocs[i]);
else
ctx->xdr->put32(&relocs, ctx->emitted_relocs[i]);
}
total_size = 0;
addr = 0;
/*
* There are 2 cases to deal with. The program has a large NOBITS
* section and the relocations can fit entirely within occupied memory
* region for the program. The other is that the relocations increase
* the memory footprint of the program if it was loaded directly into
* the region it would run. The rmdoule header is a fixed cost that
* is considered a part of the program.
*/
total_size += buffer_size(&rmod_header);
total_size += ctx->phdr->p_memsz;
if (buffer_size(&relocs) + ctx->phdr->p_filesz > total_size) {
total_size -= ctx->phdr->p_memsz;
total_size += buffer_size(&relocs);
total_size += ctx->phdr->p_filesz;
}
ret = add_section(ew, &rmod_header, ".header", addr,
buffer_size(&rmod_header));
if (ret < 0)
goto out;
addr += buffer_size(&rmod_header);
ret = add_section(ew, &program, ".program", addr, ctx->phdr->p_filesz);
if (ret < 0)
goto out;
addr += ctx->phdr->p_filesz;
ret = add_section(ew, &relocs, ".relocs", addr, buffer_size(&relocs));
if (ret < 0)
goto out;
addr += buffer_size(&relocs);
if (total_size != addr) {
ret = add_section(ew, NULL, ".empty", addr, total_size - addr);
if (ret < 0)
goto out;
}
/*
* Ensure last section has a memory usage that meets the required
* total size of the program in memory.
*/
ret = elf_writer_serialize(ew, out);
if (ret < 0)
ERROR("Failed to serialize ELF to buffer.\n");
out:
buffer_delete(&rmod_data);
elf_writer_destroy(ew);
return ret;
}
int rmodule_create(const struct buffer *elfin, struct buffer *elfout)
{
struct rmod_context ctx;
struct parsed_elf *pelf;
int i;
int ret;
ret = -1;
memset(&ctx, 0, sizeof(ctx));
pelf = &ctx.pelf;
if (parse_elf(elfin, pelf, ELF_PARSE_ALL)) {
ERROR("Couldn't parse ELF!\n");
return -1;
}
/* Only allow executables to be turned into rmodules. */
if (pelf->ehdr.e_type != ET_EXEC) {
ERROR("ELF is not an executable: %u.\n", pelf->ehdr.e_type);
goto out;
}
/* Determine if architecture is supported. */
for (i = 0; i < ARRAY_SIZE(reloc_ops); i++) {
if (reloc_ops[i].arch == pelf->ehdr.e_machine) {
ctx.ops = &reloc_ops[i];
break;
}
}
if (ctx.ops == NULL) {
ERROR("ELF is unsupported arch: %u.\n", pelf->ehdr.e_machine);
goto out;
}
/* Set the endian ops. */
if (ctx.pelf.ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
ctx.xdr = &xdr_be;
else
ctx.xdr = &xdr_le;
if (find_program_segment(&ctx))
goto out;
if (filter_relocation_sections(&ctx))
goto out;
if (collect_relocations(&ctx))
goto out;
if (populate_program_info(&ctx))
goto out;
if (write_elf(&ctx, elfin, elfout))
goto out;
ret = 0;
out:
free(ctx.emitted_relocs);
parsed_elf_destroy(pelf);
return ret;
}

View file

@ -1,7 +1,5 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 ChromeOS Authors
* Copyright (C) 2014 Google, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -14,11 +12,19 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
*/
#include <rmodule.h>
#ifndef TOOL_RMODULE_H
#define TOOL_RMODULE_H
extern char _start[];
#include "elf.h"
#include "common.h"
DEFINE_RMODULE_HEADER(ramstage_module, _start, RMODULE_TYPE_STAGE);
/*
* Parse an ELF file within the elfin buffer and fill in the elfout buffer
* with a created rmodule in ELF format. Return 0 on success, < 0 on error.
*/
int rmodule_create(const struct buffer *elfin, struct buffer *elfout);
#endif /* TOOL_RMODULE_H */

View file

@ -25,6 +25,22 @@
#include <stdint.h>
#include "common.h"
size_t bgets(struct buffer *input, void *output, size_t len)
{
len = input->size < len ? input->size : len;
memmove(output, input->data, len);
input->data += len;
input->size -= len;
return len;
}
size_t bputs(struct buffer *b, const void *data, size_t len)
{
memmove(&b->data[b->size], data, len);
b->size += len;
return len;
}
/* The assumption in all this code is that we're given a pointer to enough data.
* Hence, we do not check for underflow.
*/
@ -130,12 +146,12 @@ static void put64le(struct buffer *input, uint64_t val)
}
struct xdr xdr_be = {
get16be, get32be, get64be,
put16be, put32be, put64be
get8, get16be, get32be, get64be,
put8, put16be, put32be, put64be
};
struct xdr xdr_le = {
get16le, get32le, get64le,
put16le, put32le, put64le
get8, get16le, get32le, get64le,
put8, put16le, put32le, put64le
};