baytrail: cache reference code for S3 resume
In order to use the same reference code on S3 resume
that was booted the program needs to be cached. Piggy
back on the ramstage cache to save the loaded reference
code program.
BUG=chrome-os-partner:22867
BRANCH=None
TEST=Built and booted. S3 resumed. Noted locations of reference
code caching and load addresses in console.
Change-Id: I90ceaf5697e8c269c3244370519d4d8a8ee2eb4a
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/179777
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: http://review.coreboot.org/5013
Tested-by: build bot (Jenkins)
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
diff --git a/src/soc/intel/baytrail/refcode.c b/src/soc/intel/baytrail/refcode.c
index 9b5aa67..f746358 100644
--- a/src/soc/intel/baytrail/refcode.c
+++ b/src/soc/intel/baytrail/refcode.c
@@ -17,19 +17,113 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <string.h>
+#include <arch/acpi.h>
#include <cbmem.h>
#include <console/console.h>
#include <cpu/x86/tsc.h>
#include <rmodule.h>
+#include <ramstage_cache.h>
#include <baytrail/ramstage.h>
#include <baytrail/efi_wrapper.h>
+static inline int is_s3_resume(void)
+{
+#if CONFIG_HAVE_ACPI_RESUME
+ return acpi_slp_type == 3;
+#else
+ return 0;
+#endif
+}
+
+static inline struct ramstage_cache *next_cache(struct ramstage_cache *c)
+{
+ return (struct ramstage_cache *)&c->program[c->size];
+}
+
static void ABI_X86 send_to_console(unsigned char b)
{
console_tx_byte(b);
}
+static efi_wrapper_entry_t load_refcode_from_cache(void)
+{
+ struct ramstage_cache *c;
+ long cache_size;
+
+ printk(BIOS_DEBUG, "refcode loading from cache.\n");
+
+ c = ramstage_cache_location(&cache_size);
+
+ if (!ramstage_cache_is_valid(c)) {
+ printk(BIOS_DEBUG, "Invalid ramstage cache descriptor.\n");
+ return NULL;
+ }
+
+ c = next_cache(c);
+ if (!ramstage_cache_is_valid(c)) {
+ printk(BIOS_DEBUG, "Invalid refcode cache descriptor.\n");
+ return NULL;
+ }
+
+ printk(BIOS_DEBUG, "Loading cached reference code from 0x%08x(%x)\n",
+ c->load_address, c->size);
+ memcpy((void *)c->load_address, &c->program[0], c->size);
+
+ return (efi_wrapper_entry_t)c->entry_point;
+}
+
+static void cache_refcode(const struct rmod_stage_load *rsl)
+{
+ struct ramstage_cache *c;
+ long cache_size;
+
+ c = ramstage_cache_location(&cache_size);
+
+ if (!ramstage_cache_is_valid(c)) {
+ printk(BIOS_DEBUG, "No place to cache reference code.\n");
+ return;
+ }
+
+ /* Determine how much remaining cache available. */
+ cache_size -= c->size + sizeof(*c);
+
+ if (cache_size < (sizeof(*c) + cbmem_entry_size(rsl->cbmem_entry))) {
+ printk(BIOS_DEBUG, "Not enough cache space for ref code.\n");
+ return;
+ }
+
+ c = next_cache(c);
+ c->magic = RAMSTAGE_CACHE_MAGIC;
+ c->entry_point = (uint32_t)rsl->entry;
+ c->load_address = (uint32_t)cbmem_entry_start(rsl->cbmem_entry);
+ c->size = cbmem_entry_size(rsl->cbmem_entry);;
+
+ printk(BIOS_DEBUG, "Caching refcode at 0x%p(%x)\n",
+ &c->program[0], c->size);
+ memcpy(&c->program[0], (void *)c->load_address, c->size);
+}
+
+static efi_wrapper_entry_t load_refcode_from_cbfs(void)
+{
+ struct rmod_stage_load refcode = {
+ .cbmem_id = CBMEM_ID_REFCODE,
+ .name = CONFIG_CBFS_PREFIX "/refcode",
+ };
+
+ printk(BIOS_DEBUG, "refcode loading from cbfs.\n");
+
+ if (rmodule_stage_load_from_cbfs(&refcode) || refcode.entry == NULL) {
+ printk(BIOS_DEBUG, "Error loading reference code.\n");
+ return NULL;
+ }
+
+ cache_refcode(&refcode);
+
+ return refcode.entry;
+}
+
void baytrail_run_reference_code(void)
{
int ret;
@@ -38,18 +132,17 @@
.version = EFI_WRAPPER_VER,
.console_out = send_to_console,
};
- struct rmod_stage_load refcode = {
- .cbmem_id = CBMEM_ID_REFCODE,
- .name = CONFIG_CBFS_PREFIX "/refcode",
- };
- if (rmodule_stage_load_from_cbfs(&refcode) || refcode.entry == NULL) {
- printk(BIOS_DEBUG, "Error loading reference code.\n");
- return;
+ if (is_s3_resume()) {
+ entry = load_refcode_from_cache();
+ } else {
+ entry = load_refcode_from_cbfs();
}
+ if (entry == NULL)
+ return;
+
wrp.tsc_ticks_per_microsecond = tsc_freq_mhz();
- entry = refcode.entry;
/* Call into reference code. */
ret = entry(&wrp);