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>
This commit is contained in:
Aaron Durbin 2013-12-12 10:29:48 -08:00 committed by Kyösti Mälkki
parent ce727e18f0
commit 63fcb4a1f8
1 changed files with 101 additions and 8 deletions

View File

@ -17,19 +17,113 @@
* 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 <string.h>
#include <arch/acpi.h>
#include <cbmem.h> #include <cbmem.h>
#include <console/console.h> #include <console/console.h>
#include <cpu/x86/tsc.h> #include <cpu/x86/tsc.h>
#include <rmodule.h> #include <rmodule.h>
#include <ramstage_cache.h>
#include <baytrail/ramstage.h> #include <baytrail/ramstage.h>
#include <baytrail/efi_wrapper.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) static void ABI_X86 send_to_console(unsigned char b)
{ {
console_tx_byte(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) void baytrail_run_reference_code(void)
{ {
int ret; int ret;
@ -38,18 +132,17 @@ void baytrail_run_reference_code(void)
.version = EFI_WRAPPER_VER, .version = EFI_WRAPPER_VER,
.console_out = send_to_console, .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) { if (is_s3_resume()) {
printk(BIOS_DEBUG, "Error loading reference code.\n"); entry = load_refcode_from_cache();
return; } else {
entry = load_refcode_from_cbfs();
} }
if (entry == NULL)
return;
wrp.tsc_ticks_per_microsecond = tsc_freq_mhz(); wrp.tsc_ticks_per_microsecond = tsc_freq_mhz();
entry = refcode.entry;
/* Call into reference code. */ /* Call into reference code. */
ret = entry(&wrp); ret = entry(&wrp);