[coreboot] New patch to review for coreboot: c95991a coreboot: introduce CONFIG_RELOCATABLE_RAMSTAGE

Stefan Reinauer (stefan.reinauer@coreboot.org) gerrit at coreboot.org
Tue Mar 19 01:58:56 CET 2013


Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2792

-gerrit

commit c95991ad763ea16884eac6cd4e2819ef5f82e91b
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Fri Feb 8 17:28:04 2013 -0600

    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 at chromium.org>
---
 src/Kconfig                                | 18 +++++++++
 src/arch/x86/Makefile.inc                  |  8 ++++
 src/arch/x86/boot/Makefile.inc             |  1 +
 src/arch/x86/boot/acpi.c                   |  4 ++
 src/arch/x86/boot/boot.c                   | 29 ++++++++++++++
 src/arch/x86/boot/ramstage_module_header.c | 24 ++++++++++++
 src/arch/x86/boot/tables.c                 |  3 ++
 src/include/cbmem.h                        |  5 +++
 src/lib/Makefile.inc                       |  1 +
 src/lib/cbfs.c                             | 61 ++++++++++++++++++++++++++++++
 src/lib/selfboot.c                         | 16 ++++++++
 11 files changed, 170 insertions(+)

diff --git a/src/Kconfig b/src/Kconfig
index f6a83e8..7a8985c 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -307,7 +307,14 @@ config HAVE_INIT_TIMER
 
 config HIGH_SCRATCH_MEMORY_SIZE
 	hex
+	default 0x5000 if RELOCATABLE_RAMSTAGE
 	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
 	bool
@@ -374,6 +381,17 @@ config RELOCATABLE_MODULES
 	 building relocatable modules in the ram stage. Those modules can be
 	 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
 	bool
 	help
diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc
index cc7bfc2..ee956a4 100644
--- a/src/arch/x86/Makefile.inc
+++ b/src/arch/x86/Makefile.inc
@@ -157,6 +157,12 @@ $(objcbfs)/%.elf: $(objcbfs)/%.debug
 ################################################################################
 # 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
 	@printf "    CC         $(subst $(obj)/,,$(@))\n"
 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 $<
 endif
 
+endif
+
 $(objgenerated)/coreboot_ram.o: $$(ramstage-objs) $(LIBGCC_FILE_NAME)
 	@printf "    CC         $(subst $(obj)/,,$(@))\n"
 ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
diff --git a/src/arch/x86/boot/Makefile.inc b/src/arch/x86/boot/Makefile.inc
index 3f11c01..9c18043 100644
--- a/src/arch/x86/boot/Makefile.inc
+++ b/src/arch/x86/boot/Makefile.inc
@@ -9,6 +9,7 @@ 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
diff --git a/src/arch/x86/boot/acpi.c b/src/arch/x86/boot/acpi.c
index 327d175..b04cbe5 100644
--- a/src/arch/x86/boot/acpi.c
+++ b/src/arch/x86/boot/acpi.c
@@ -759,6 +759,9 @@ extern unsigned int __wakeup_size;
 
 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);
 
 	if (!acpi_backup_memory) {
@@ -766,6 +769,7 @@ void acpi_jump_to_wakeup(void *vector)
 		       "No S3 resume.\n");
 		return;
 	}
+#endif
 
 #if CONFIG_SMP
 	// FIXME: This should go into the ACPI backup memory, too. No pork saussages.
diff --git a/src/arch/x86/boot/boot.c b/src/arch/x86/boot/boot.c
index d9cb02e..4892c5e 100644
--- a/src/arch/x86/boot/boot.c
+++ b/src/arch/x86/boot/boot.c
@@ -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)
 {
 	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 /* CONFIG_RELOCATABLE_RAMSTAGE */
 
 
diff --git a/src/arch/x86/boot/ramstage_module_header.c b/src/arch/x86/boot/ramstage_module_header.c
new file mode 100644
index 0000000..b958c16
--- /dev/null
+++ b/src/arch/x86/boot/ramstage_module_header.c
@@ -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);
diff --git a/src/arch/x86/boot/tables.c b/src/arch/x86/boot/tables.c
index 7f28861..294a10c 100644
--- a/src/arch/x86/boot/tables.c
+++ b/src/arch/x86/boot/tables.c
@@ -232,11 +232,14 @@ struct lb_memory *write_tables(void)
 	post_code(0x9e);
 
 #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
 	 * 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.
 	 */
 	cbmem_add(CBMEM_ID_RESUME, HIGH_MEMORY_SAVE);
+#endif
 #if CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY14 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY15_TN
 	cbmem_add(CBMEM_ID_RESUME_SCRATCH, CONFIG_HIGH_SCRATCH_MEMORY_SIZE);
 #endif
diff --git a/src/include/cbmem.h b/src/include/cbmem.h
index 0aa9b30..d0f0c9a 100644
--- a/src/include/cbmem.h
+++ b/src/include/cbmem.h
@@ -28,7 +28,12 @@
 #endif
 
 #if CONFIG_HAVE_ACPI_RESUME
+#if CONFIG_RELOCATABLE_RAMSTAGE
+#define HIGH_MEMORY_SAVE	0
+#else
 #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)
 
 /* Delegation of resume backup memory so we don't have to
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc
index 160fce6..fe04e43 100644
--- a/src/lib/Makefile.inc
+++ b/src/lib/Makefile.inc
@@ -109,6 +109,7 @@ $(obj)/lib/uart8250.smm.o : $(OPTION_TABLE_H)
 
 ifeq ($(CONFIG_RELOCATABLE_MODULES),y)
 ramstage-y += rmodule.c
+romstage-$(CONFIG_RELOCATABLE_RAMSTAGE) += rmodule.c
 
 RMODULE_LDSCRIPT := $(src)/lib/rmodule.ld
 RMODULE_LDFLAGS  := -nostartfiles -shared -z defs -nostdlib -Bsymbolic -T $(RMODULE_LDSCRIPT)
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index abb95ab..7d81038 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -36,6 +36,7 @@
 
 #include <cbfs.h>
 #include <string.h>
+#include <cbmem.h>
 
 #ifdef LIBPAYLOAD
 # include <stdio.h>
@@ -114,6 +115,65 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
 	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_no_clear_bss(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)
 {
 	struct cbfs_stage *stage = (struct cbfs_stage *)
@@ -145,6 +205,7 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name)
 
 	return (void *) entry;
 }
+#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
 
 int cbfs_execute_stage(struct cbfs_media *media, const char *name)
 {
diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index f32bb81..f933142 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -78,6 +78,16 @@ struct segment {
 
 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)
 {
 	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_size = req_size;
 }
+#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
 
 static int valid_area(struct lb_memory *mem, unsigned long buffer,
 	unsigned long start, unsigned long len)
@@ -394,8 +405,13 @@ static int load_self_segments(
 	for(ptr = head->next; ptr != head; ptr = ptr->next) {
 		if (!overlaps_coreboot(ptr))
 			continue;
+#if CONFIG_RELOCATABLE_RAMSTAGE
+		/* payloads are required to not overlap ramstage. */
+		return 0;
+#else
 		if (ptr->s_dstaddr + ptr->s_memsz > bounce_high)
 			bounce_high = ptr->s_dstaddr + ptr->s_memsz;
+#endif
 	}
 	get_bounce_buffer(mem, bounce_high - lb_start);
 	if (!bounce_buffer) {



More information about the coreboot mailing list