coreboot: introduce CONFIG_RELOCATABLE_RAMSTAGE
This patch adds an option to build the ramstage as a reloctable binary. It uses the rmodule library for the relocation. The main changes consist of the following: 1. The ramstage is loaded just under the cmbem space. 2. Payloads cannot be loaded over where ramstage is loaded. If a payload is attempted to load where the relocatable ramstage resides the load is aborted. 3. The memory occupied by the ramstage is reserved from the OS's usage using the romstage_handoff structure stored in cbmem. This region is communicated to ramstage by an CBMEM_ID_ROMSTAGE_INFO entry in cbmem. 4. There is no need to reserve cbmem space for the OS controlled memory for the resume path because the ramsage region has been reserved in #3. 5. Since no memory needs to be preserved in the wake path, the loading and begin of execution of a elf payload is straight forward. Change-Id: Ia66cf1be65c29fa25ca7bd9ea6c8f11d7eee05f5 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/2792 Reviewed-by: Ronald G. Minnich <rminnich@gmail.com> Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@google.com>
This commit is contained in:
parent
43e4a80a92
commit
8e4a355773
18
src/Kconfig
18
src/Kconfig
|
@ -307,7 +307,14 @@ config HAVE_INIT_TIMER
|
||||||
|
|
||||||
config HIGH_SCRATCH_MEMORY_SIZE
|
config HIGH_SCRATCH_MEMORY_SIZE
|
||||||
hex
|
hex
|
||||||
|
default 0x5000 if RELOCATABLE_RAMSTAGE
|
||||||
default 0x0
|
default 0x0
|
||||||
|
help
|
||||||
|
The amount of extra memory to reserve from the OS. If
|
||||||
|
RELOCATABLE_RAMSTAGE is enabled a size of 20KiB is reserved. This is
|
||||||
|
for the use of a stack in romstage after memory has been initialized.
|
||||||
|
The stack size required in romstage can be large when needing to
|
||||||
|
decompress the ramstage.
|
||||||
|
|
||||||
config USE_OPTION_TABLE
|
config USE_OPTION_TABLE
|
||||||
bool
|
bool
|
||||||
|
@ -374,6 +381,17 @@ config RELOCATABLE_MODULES
|
||||||
building relocatable modules in the ram stage. Those modules can be
|
building relocatable modules in the ram stage. Those modules can be
|
||||||
loaded anywhere and all the relocations are handled automatically.
|
loaded anywhere and all the relocations are handled automatically.
|
||||||
|
|
||||||
|
config RELOCATABLE_RAMSTAGE
|
||||||
|
depends on RELOCATABLE_MODULES
|
||||||
|
bool "Build the ramstage to be relocatable in 32-bit address space."
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
The reloctable ramstage support allows for the ramstage to be built
|
||||||
|
as a relocatable module. The stage loader can identify a place
|
||||||
|
out of the OS way so that copying memory is unnecessary during an S3
|
||||||
|
wake. When selecting this option the romstage is responsible for
|
||||||
|
determing a stack location to use for loading the ramstage.
|
||||||
|
|
||||||
config HAVE_ACPI_TABLES
|
config HAVE_ACPI_TABLES
|
||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
|
|
|
@ -157,6 +157,12 @@ $(objcbfs)/%.elf: $(objcbfs)/%.debug
|
||||||
################################################################################
|
################################################################################
|
||||||
# Build the coreboot_ram (stage 2)
|
# Build the coreboot_ram (stage 2)
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_RELOCATABLE_RAMSTAGE),y)
|
||||||
|
|
||||||
|
$(eval $(call rmodule_link,$(objcbfs)/coreboot_ram.debug, $(obj)/arch/x86/boot/ramstage_module_header.ramstage.o $(objgenerated)/coreboot_ram.o, $(CONFIG_HEAP_SIZE)))
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
$(objcbfs)/coreboot_ram.debug: $(objgenerated)/coreboot_ram.o $(src)/arch/x86/coreboot_ram.ld
|
$(objcbfs)/coreboot_ram.debug: $(objgenerated)/coreboot_ram.o $(src)/arch/x86/coreboot_ram.ld
|
||||||
@printf " CC $(subst $(obj)/,,$(@))\n"
|
@printf " CC $(subst $(obj)/,,$(@))\n"
|
||||||
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
|
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
|
||||||
|
@ -165,6 +171,8 @@ else
|
||||||
$(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(src)/arch/x86/coreboot_ram.ld $<
|
$(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(src)/arch/x86/coreboot_ram.ld $<
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
$(objgenerated)/coreboot_ram.o: $$(ramstage-objs) $(LIBGCC_FILE_NAME)
|
$(objgenerated)/coreboot_ram.o: $$(ramstage-objs) $(LIBGCC_FILE_NAME)
|
||||||
@printf " CC $(subst $(obj)/,,$(@))\n"
|
@printf " CC $(subst $(obj)/,,$(@))\n"
|
||||||
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
|
ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
|
||||||
|
|
|
@ -9,6 +9,7 @@ ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c
|
||||||
ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios.c
|
ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios.c
|
||||||
ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpigen.c
|
ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpigen.c
|
||||||
ramstage-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.S
|
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/coreboot_table.ramstage.o : $(OPTION_TABLE_H)
|
||||||
$(obj)/arch/x86/boot/smbios.ramstage.o: $(obj)/build.h
|
$(obj)/arch/x86/boot/smbios.ramstage.o: $(obj)/build.h
|
||||||
|
|
|
@ -759,6 +759,9 @@ extern unsigned int __wakeup_size;
|
||||||
|
|
||||||
void acpi_jump_to_wakeup(void *vector)
|
void acpi_jump_to_wakeup(void *vector)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_RELOCATABLE_RAMSTAGE
|
||||||
|
u32 acpi_backup_memory = 0;
|
||||||
|
#else
|
||||||
u32 acpi_backup_memory = (u32)cbmem_find(CBMEM_ID_RESUME);
|
u32 acpi_backup_memory = (u32)cbmem_find(CBMEM_ID_RESUME);
|
||||||
|
|
||||||
if (!acpi_backup_memory) {
|
if (!acpi_backup_memory) {
|
||||||
|
@ -766,6 +769,7 @@ void acpi_jump_to_wakeup(void *vector)
|
||||||
"No S3 resume.\n");
|
"No S3 resume.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIG_SMP
|
#if CONFIG_SMP
|
||||||
// FIXME: This should go into the ACPI backup memory, too. No pork saussages.
|
// FIXME: This should go into the ACPI backup memory, too. No pork saussages.
|
||||||
|
|
|
@ -68,6 +68,34 @@ int elf_check_arch(Elf_ehdr *ehdr)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_RELOCATABLE_RAMSTAGE
|
||||||
|
/* When the ramstage is relocatable the elf loading ensures an elf image cannot
|
||||||
|
* be loaded over the ramstage code. */
|
||||||
|
void jmp_to_elf_entry(void *entry, unsigned long unused1, unsigned long unused2)
|
||||||
|
{
|
||||||
|
elf_boot_notes.hdr.b_checksum =
|
||||||
|
compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes));
|
||||||
|
|
||||||
|
/* Jump to kernel */
|
||||||
|
__asm__ __volatile__(
|
||||||
|
" cld \n\t"
|
||||||
|
/* Now jump to the loaded image */
|
||||||
|
" call *%0\n\t"
|
||||||
|
|
||||||
|
/* The loaded image returned? */
|
||||||
|
" cli \n\t"
|
||||||
|
" cld \n\t"
|
||||||
|
|
||||||
|
::
|
||||||
|
"r" (entry),
|
||||||
|
#if CONFIG_MULTIBOOT
|
||||||
|
"b"(mbi), "a" (MB_MAGIC2)
|
||||||
|
#else
|
||||||
|
"b"(&elf_boot_notes), "a" (0x0E1FB007)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#else
|
||||||
void jmp_to_elf_entry(void *entry, unsigned long buffer, unsigned long size)
|
void jmp_to_elf_entry(void *entry, unsigned long buffer, unsigned long size)
|
||||||
{
|
{
|
||||||
extern unsigned char _ram_seg, _eram_seg;
|
extern unsigned char _ram_seg, _eram_seg;
|
||||||
|
@ -182,5 +210,6 @@ void jmp_to_elf_entry(void *entry, unsigned long buffer, unsigned long size)
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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 _start[];
|
||||||
|
|
||||||
|
DEFINE_RMODULE_HEADER(ramstage_module, _start, RMODULE_TYPE_STAGE);
|
|
@ -232,11 +232,14 @@ struct lb_memory *write_tables(void)
|
||||||
post_code(0x9e);
|
post_code(0x9e);
|
||||||
|
|
||||||
#if CONFIG_HAVE_ACPI_RESUME
|
#if CONFIG_HAVE_ACPI_RESUME
|
||||||
|
/* Only add CBMEM_ID_RESUME when the ramstage isn't relocatable. */
|
||||||
|
#if !CONFIG_RELOCATABLE_RAMSTAGE
|
||||||
/* Let's prepare the ACPI S3 Resume area now already, so we can rely on
|
/* Let's prepare the ACPI S3 Resume area now already, so we can rely on
|
||||||
* it begin there during reboot time. We don't need the pointer, nor
|
* it begin there during reboot time. We don't need the pointer, nor
|
||||||
* the result right now. If it fails, ACPI resume will be disabled.
|
* the result right now. If it fails, ACPI resume will be disabled.
|
||||||
*/
|
*/
|
||||||
cbmem_add(CBMEM_ID_RESUME, HIGH_MEMORY_SAVE);
|
cbmem_add(CBMEM_ID_RESUME, HIGH_MEMORY_SAVE);
|
||||||
|
#endif
|
||||||
#if CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY14 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY15_TN
|
#if CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY14 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY15_TN
|
||||||
cbmem_add(CBMEM_ID_RESUME_SCRATCH, CONFIG_HIGH_SCRATCH_MEMORY_SIZE);
|
cbmem_add(CBMEM_ID_RESUME_SCRATCH, CONFIG_HIGH_SCRATCH_MEMORY_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,7 +28,12 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_HAVE_ACPI_RESUME
|
#if CONFIG_HAVE_ACPI_RESUME
|
||||||
|
#if CONFIG_RELOCATABLE_RAMSTAGE
|
||||||
|
#define HIGH_MEMORY_SAVE 0
|
||||||
|
#else
|
||||||
#define HIGH_MEMORY_SAVE (CONFIG_RAMTOP - CONFIG_RAMBASE)
|
#define HIGH_MEMORY_SAVE (CONFIG_RAMTOP - CONFIG_RAMBASE)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define HIGH_MEMORY_SIZE (HIGH_MEMORY_SAVE + CONFIG_HIGH_SCRATCH_MEMORY_SIZE + HIGH_MEMORY_DEF_SIZE)
|
#define HIGH_MEMORY_SIZE (HIGH_MEMORY_SAVE + CONFIG_HIGH_SCRATCH_MEMORY_SIZE + HIGH_MEMORY_DEF_SIZE)
|
||||||
|
|
||||||
/* Delegation of resume backup memory so we don't have to
|
/* Delegation of resume backup memory so we don't have to
|
||||||
|
|
|
@ -110,6 +110,7 @@ $(obj)/lib/uart8250.smm.o : $(OPTION_TABLE_H)
|
||||||
|
|
||||||
ifeq ($(CONFIG_RELOCATABLE_MODULES),y)
|
ifeq ($(CONFIG_RELOCATABLE_MODULES),y)
|
||||||
ramstage-y += rmodule.c
|
ramstage-y += rmodule.c
|
||||||
|
romstage-$(CONFIG_RELOCATABLE_RAMSTAGE) += rmodule.c
|
||||||
|
|
||||||
RMODULE_LDSCRIPT := $(src)/lib/rmodule.ld
|
RMODULE_LDSCRIPT := $(src)/lib/rmodule.ld
|
||||||
RMODULE_LDFLAGS := -nostartfiles -shared -z defs -nostdlib -Bsymbolic -T $(RMODULE_LDSCRIPT)
|
RMODULE_LDFLAGS := -nostartfiles -shared -z defs -nostdlib -Bsymbolic -T $(RMODULE_LDSCRIPT)
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
#include <cbfs.h>
|
#include <cbfs.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <cbmem.h>
|
||||||
|
|
||||||
#ifdef LIBPAYLOAD
|
#ifdef LIBPAYLOAD
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
|
@ -114,6 +115,65 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_RELOCATABLE_RAMSTAGE && defined(__PRE_RAM__)
|
||||||
|
|
||||||
|
#include <rmodule.h>
|
||||||
|
#include <romstage_handoff.h>
|
||||||
|
/* When CONFIG_RELOCATABLE_RAMSTAGE is enabled and this file is being compiled
|
||||||
|
* for the romstage the rmodule loader is used. The ramstage is placed just
|
||||||
|
* below the cbemem location. */
|
||||||
|
|
||||||
|
void * cbfs_load_stage(struct cbfs_media *media, const char *name)
|
||||||
|
{
|
||||||
|
struct cbfs_stage *stage;
|
||||||
|
struct rmodule ramstage;
|
||||||
|
void *cbmem_base;
|
||||||
|
void *ramstage_base;
|
||||||
|
void *decompression_loc;
|
||||||
|
void *ramstage_loc;
|
||||||
|
struct romstage_handoff *handoff;
|
||||||
|
|
||||||
|
stage = (struct cbfs_stage *)
|
||||||
|
cbfs_get_file_content(media, name, CBFS_TYPE_STAGE);
|
||||||
|
|
||||||
|
if (stage == NULL)
|
||||||
|
return (void *) -1;
|
||||||
|
|
||||||
|
cbmem_base = get_cbmem_toc();
|
||||||
|
if (cbmem_base == NULL)
|
||||||
|
return (void *) -1;
|
||||||
|
|
||||||
|
ramstage_base = rmodule_find_region_below(cbmem_base, stage->memlen,
|
||||||
|
&ramstage_loc,
|
||||||
|
&decompression_loc);
|
||||||
|
|
||||||
|
LOG("Decompressing stage %s @ 0x%p (%d bytes)\n",
|
||||||
|
name, decompression_loc, stage->memlen);
|
||||||
|
|
||||||
|
if (cbfs_decompress(stage->compression, &stage[1],
|
||||||
|
decompression_loc, stage->len))
|
||||||
|
return (void *) -1;
|
||||||
|
|
||||||
|
if (rmodule_parse(decompression_loc, &ramstage))
|
||||||
|
return (void *) -1;
|
||||||
|
|
||||||
|
/* The ramstage is responsible for clearing its own bss. */
|
||||||
|
if (rmodule_load(ramstage_loc, &ramstage))
|
||||||
|
return (void *) -1;
|
||||||
|
|
||||||
|
handoff = cbmem_add(CBMEM_ID_ROMSTAGE_INFO, sizeof(*handoff));
|
||||||
|
if (handoff) {
|
||||||
|
handoff->reserve_base = (uint32_t)ramstage_base;
|
||||||
|
handoff->reserve_size = (uint32_t)cbmem_base -
|
||||||
|
(uint32_t)ramstage_base;
|
||||||
|
} else
|
||||||
|
LOG("Couldn't allocate romstage handoff.\n");
|
||||||
|
|
||||||
|
return rmodule_entry(&ramstage);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
void * cbfs_load_stage(struct cbfs_media *media, const char *name)
|
void * cbfs_load_stage(struct cbfs_media *media, const char *name)
|
||||||
{
|
{
|
||||||
struct cbfs_stage *stage = (struct cbfs_stage *)
|
struct cbfs_stage *stage = (struct cbfs_stage *)
|
||||||
|
@ -146,6 +206,7 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name)
|
||||||
|
|
||||||
return (void *) entry;
|
return (void *) entry;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
|
||||||
|
|
||||||
int cbfs_execute_stage(struct cbfs_media *media, const char *name)
|
int cbfs_execute_stage(struct cbfs_media *media, const char *name)
|
||||||
{
|
{
|
||||||
|
|
|
@ -78,6 +78,16 @@ struct segment {
|
||||||
|
|
||||||
static unsigned long bounce_size, bounce_buffer;
|
static unsigned long bounce_size, bounce_buffer;
|
||||||
|
|
||||||
|
#if CONFIG_RELOCATABLE_RAMSTAGE
|
||||||
|
static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size)
|
||||||
|
{
|
||||||
|
/* When the ramstage is relocatable there is no need for a bounce
|
||||||
|
* buffer. All payloads should not overlap the ramstage.
|
||||||
|
*/
|
||||||
|
bounce_buffer = ~0UL;
|
||||||
|
bounce_size = 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size)
|
static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size)
|
||||||
{
|
{
|
||||||
unsigned long lb_size;
|
unsigned long lb_size;
|
||||||
|
@ -114,6 +124,7 @@ static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size)
|
||||||
bounce_buffer = buffer;
|
bounce_buffer = buffer;
|
||||||
bounce_size = req_size;
|
bounce_size = req_size;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
|
||||||
|
|
||||||
static int valid_area(struct lb_memory *mem, unsigned long buffer,
|
static int valid_area(struct lb_memory *mem, unsigned long buffer,
|
||||||
unsigned long start, unsigned long len)
|
unsigned long start, unsigned long len)
|
||||||
|
@ -394,8 +405,13 @@ static int load_self_segments(
|
||||||
for(ptr = head->next; ptr != head; ptr = ptr->next) {
|
for(ptr = head->next; ptr != head; ptr = ptr->next) {
|
||||||
if (!overlaps_coreboot(ptr))
|
if (!overlaps_coreboot(ptr))
|
||||||
continue;
|
continue;
|
||||||
|
#if CONFIG_RELOCATABLE_RAMSTAGE
|
||||||
|
/* payloads are required to not overlap ramstage. */
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
if (ptr->s_dstaddr + ptr->s_memsz > bounce_high)
|
if (ptr->s_dstaddr + ptr->s_memsz > bounce_high)
|
||||||
bounce_high = ptr->s_dstaddr + ptr->s_memsz;
|
bounce_high = ptr->s_dstaddr + ptr->s_memsz;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
get_bounce_buffer(mem, bounce_high - lb_start);
|
get_bounce_buffer(mem, bounce_high - lb_start);
|
||||||
if (!bounce_buffer) {
|
if (!bounce_buffer) {
|
||||||
|
|
Loading…
Reference in New Issue