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:
parent
39a740d488
commit
5d262f8dd4
41 changed files with 1865 additions and 438 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -58,6 +58,7 @@ tarballs/
|
|||
util/*/.dependencies
|
||||
util/*/.test
|
||||
util/cbfstool/cbfstool
|
||||
util/cbfstool/rmodtool
|
||||
util/cbmem/.dependencies
|
||||
util/cbmem/cbmem
|
||||
util/dumpmmcr/dumpmmcr
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ thread_stacks:
|
|||
.section ".textfirst", "ax", @progbits
|
||||
.code32
|
||||
.globl _start
|
||||
.globl __rmodule_entry
|
||||
__rmodule_entry:
|
||||
_start:
|
||||
cli
|
||||
lgdt %cs:gdtaddr
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
#include <rmodule.h>
|
||||
|
||||
|
||||
extern void *ap_start;
|
||||
|
||||
DEFINE_RMODULE_HEADER(sipi_vector_header, ap_start, RMODULE_TYPE_SIPI_VECTOR);
|
||||
|
|
@ -58,6 +58,8 @@ apic_to_cpu_num:
|
|||
.text
|
||||
.code16
|
||||
.global ap_start
|
||||
.global __rmodule_entry
|
||||
__rmodule_entry:
|
||||
ap_start:
|
||||
cli
|
||||
xorl %eax, %eax
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
#include <rmodule.h>
|
||||
|
||||
|
||||
extern void *ap_start;
|
||||
|
||||
DEFINE_RMODULE_HEADER(sipi_vector_header, ap_start, RMODULE_TYPE_SIPI_VECTOR);
|
||||
|
|
@ -58,6 +58,8 @@ ap_count:
|
|||
.text
|
||||
.code16
|
||||
.global ap_start
|
||||
.global __rmodule_entry
|
||||
__rmodule_entry:
|
||||
ap_start:
|
||||
cli
|
||||
xorl %eax, %eax
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
63
src/include/rmodule-defs.h
Normal file
63
src/include/rmodule-defs.h
Normal 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 */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "elf.h"
|
||||
#include "elfparsing.h"
|
||||
#include "common.h"
|
||||
#include "cbfs.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
107
util/cbfstool/elfparsing.h
Normal 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 */
|
||||
|
|
@ -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, ¤t_offset, &file_length);
|
||||
|
||||
num_mcus = 0;
|
||||
while (file_length > sizeof(struct microcode_header))
|
||||
|
|
|
|||
106
util/cbfstool/rmodtool.c
Normal file
106
util/cbfstool/rmodtool.c
Normal 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
631
util/cbfstool/rmodule.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue