[coreboot] New patch to review for coreboot: b19bd0e ramstage: cache relocated ramstage in RAM

Stefan Reinauer (stefan.reinauer@coreboot.org) gerrit at coreboot.org
Tue Mar 19 01:59:06 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/2800

-gerrit

commit b19bd0e080f7a487af5c5b26b979ccfda634b182
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Tue Feb 12 00:50:47 2013 -0600

    ramstage: cache relocated ramstage in RAM
    
    Accessing the flash part where the ramstage resides can be slow
    when loading it. In order to save time in the S3 resume path a copy
    of the relocated ramstage is saved just below the location the ramstage
    was loaded. Then on S3 resume the cached version of the relocated
    ramstage is copied back to the loaded address.
    
    This is achieved by saving the ramstage entry point in the
    romstage_handoff structure as reserving double the amount of memory
    required for ramstage. This approach saves the engineering time to make
    the ramstage reentrant.
    
    The fast path in this change will only be taken when the chipset's
    romstage code properly initializes the s3_resume field in the
    romstage_handoff structure. If that is never set up properly then the
    fast path will never be taken.
    
    e820 entries from Linux:
    BIOS-e820: [mem 0x000000007bf21000-0x000000007bfbafff] reserved
    BIOS-e820: [mem 0x000000007bfbb000-0x000000007bffffff] type 16
    
    The type 16 is the cbmem table and the reserved section contains the two
    copies of the ramstage; one has been executed already and one is
    the cached relocated program.
    
    With this change the S3 resume path on the basking ridge CRB shows
    to be ~200ms to hand off to the kernel:
    
    13 entries total:
    
       1:95,965
       2:97,191 (1,225)
       3:131,755 (34,564)
       4:132,890 (1,135)
       8:135,165 (2,274)
       9:135,840 (675)
      10:135,973 (132)
      30:136,016 (43)
      40:136,581 (564)
      50:138,280 (1,699)
      60:138,381 (100)
      70:204,538 (66,157)
      98:204,615 (77)
    
    Change-Id: I9c7a6d173afc758eef560e09d2aef5f90a25187a
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
 src/include/romstage_handoff.h | 10 +++++++-
 src/lib/cbfs.c                 | 58 ++++++++++++++++++++++++++++++++++--------
 2 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/src/include/romstage_handoff.h b/src/include/romstage_handoff.h
index c20b261..4150e8e 100644
--- a/src/include/romstage_handoff.h
+++ b/src/include/romstage_handoff.h
@@ -31,8 +31,16 @@ struct romstage_handoff {
 	/* This indicates to the ramstage to reserve a chunk of memory. */
 	uint32_t reserve_base;
 	uint32_t reserve_size;
-	/* Inidicate if the current boot is an S3 resume. */
+	/* Inidicate if the current boot is an S3 resume. If
+	 * CONFIG_RELOCTABLE_RAMSTAGE is enabled the chipset code is
+	 * responsible for initializing this variable. Otherwise, ramstage
+	 * will be re-loaded from cbfs (which can be slower since it lives
+	 * in flash). */
 	uint32_t s3_resume;
+	/* The ramstage_entry_point is cached in the stag loading path. This
+	 * cached value can only be utilized when the chipset code properly
+	 * fills in the s3_resume field above. */
+	uint32_t ramstage_entry_point;
 };
 
 #if defined(__PRE_RAM__)
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index c8bfb0c..6e89a39 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -120,10 +120,11 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
 #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. */
+ * for the romstage, the rmodule loader is used. The ramstage is placed just
+ * below the cbmem location. */
 
-void * cbfs_load_stage(struct cbfs_media *media, const char *name)
+static void *load_stage_from_cbfs(struct cbfs_media *media, const char *name,
+                                  struct romstage_handoff *handoff)
 {
 	struct cbfs_stage *stage;
 	struct rmodule ramstage;
@@ -131,7 +132,7 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name)
 	void *ramstage_base;
 	void *decompression_loc;
 	void *ramstage_loc;
-	struct romstage_handoff *handoff;
+	void *entry_point;
 
 	stage = (struct cbfs_stage *)
 		cbfs_get_file_content(media, name, CBFS_TYPE_STAGE);
@@ -143,9 +144,10 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name)
 	if (cbmem_base == NULL)
 		return (void *) -1;
 
-	ramstage_base = rmodule_find_region_below(cbmem_base, stage->memlen,
-	                                          &ramstage_loc,
-	                                          &decompression_loc);
+	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);
@@ -161,15 +163,49 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name)
 	if (rmodule_load_no_clear_bss(ramstage_loc, &ramstage))
 		return (void *) -1;
 
-	handoff = romstage_handoff_find_or_add();
+	entry_point = rmodule_entry(&ramstage);
+
 	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");
+		/* Save an entire copy in RAM of the relocated ramstage for
+		 * the S3 resume path. The size of the saved relocated ramstage
+		 * is larger than necessary. It could be optimized by saving
+		 * just the text/data segment of the ramstage. The rmodule
+		 * API would need to be modified to expose these details. For
+		 * the time being, just save the entire used region. */
+		memcpy((void *)(handoff->reserve_base - handoff->reserve_size),
+		       (void *)handoff->reserve_base, handoff->reserve_size);
+		/* Update the size and base of the reserve region. */
+		handoff->reserve_base -= handoff->reserve_size;
+		handoff->reserve_size += handoff->reserve_size;
+		/* Save the entry point in the handoff area. */
+		handoff->ramstage_entry_point = (uint32_t)entry_point;
+	}
+
+	return entry_point;
+}
+
+void * cbfs_load_stage(struct cbfs_media *media, const char *name)
+{
+	struct romstage_handoff *handoff;
+
+	handoff = romstage_handoff_find_or_add();
+
+	if (handoff == NULL) {
+		LOG("Couldn't find or allocate romstage handoff.\n");
+		return load_stage_from_cbfs(media, name, handoff);
+	} else if (!handoff->s3_resume)
+		return load_stage_from_cbfs(media, name, handoff);
+
+	/* S3 resume path. Copy from the saved relocated program buffer to
+	 * the running location. load_stage_from_cbfs() keeps a copy of the
+	 * relocated program just below the relocated program. */
+	memcpy((void *)(handoff->reserve_base + (handoff->reserve_size / 2)),
+	       (void *)handoff->reserve_base, handoff->reserve_size / 2);
 
-	return rmodule_entry(&ramstage);
+	return (void *)handoff->ramstage_entry_point;
 }
 
 #else



More information about the coreboot mailing list