blob: 49b9ee3fe3aed1f1ce27596ab4147decaa827572 [file] [log] [blame]
/* Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
* Copyright (C) 2012 ChromeOS Authors
* 2005.6 by yhlu
* 2006.3 yhlu add copy data from CAR to ram
*/
#include <string.h>
#include <arch/stages.h>
#include <arch/early_variables.h>
#include <cpu/x86/mtrr.h>
#include <cpu/amd/mtrr.h>
#include <cpu/amd/car.h>
#include <arch/acpi.h>
#include <romstage_handoff.h>
#include "cbmem.h"
#include "cpu/amd/car/disable_cache_as_ram.c"
#if CONFIG_RAMTOP <= 0x100000
#error "You need to set CONFIG_RAMTOP greater than 1M"
#endif
#if IS_ENABLED(CONFIG_DEBUG_CAR)
#define print_car_debug(format, arg...) printk(BIOS_DEBUG, "%s: " format, __func__, ##arg)
#else
#define print_car_debug(format, arg...)
#endif
static size_t backup_size(void)
{
size_t car_size = car_data_size();
return ALIGN(car_size + 1024, 1024);
}
static void memcpy_(void *d, const void *s, size_t len)
{
print_car_debug(" Copy [%08x-%08x] to [%08x - %08x] ... ",
(uint32_t) s, (uint32_t) (s + len - 1), (uint32_t) d, (uint32_t) (d + len - 1));
memcpy(d, s, len);
}
static void memset_(void *d, int val, size_t len)
{
print_car_debug(" Fill [%08x-%08x] ... ", (uint32_t) d, (uint32_t) (d + len - 1));
memset(d, val, len);
}
static int memcmp_(void *d, const void *s, size_t len)
{
print_car_debug(" Compare [%08x-%08x] with [%08x - %08x] ... ",
(uint32_t) s, (uint32_t) (s + len - 1), (uint32_t) d, (uint32_t) (d + len - 1));
return memcmp(d, s, len);
}
static void prepare_romstage_ramstack(void *resume_backup_memory)
{
size_t backup_top = backup_size();
print_car_debug("Prepare CAR migration and stack regions...");
if (resume_backup_memory) {
memcpy_(resume_backup_memory + HIGH_MEMORY_SAVE - backup_top,
(void *)(CONFIG_RAMTOP - backup_top), backup_top);
}
memset_((void *)(CONFIG_RAMTOP - backup_top), 0, backup_top);
print_car_debug("Done\n");
}
static void prepare_ramstage_region(void *resume_backup_memory)
{
size_t backup_top = backup_size();
print_car_debug("Prepare ramstage memory region... ");
if (resume_backup_memory) {
memcpy_(resume_backup_memory, (void *) CONFIG_RAMBASE, HIGH_MEMORY_SAVE - backup_top);
memset_((void*) CONFIG_RAMBASE, 0, HIGH_MEMORY_SAVE - backup_top);
} else {
memset_((void*)0, 0, CONFIG_RAMTOP - backup_top);
}
print_car_debug("Done\n");
}
/* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */
static void vErrata343(void)
{
#ifdef BU_CFG2_MSR
msr_t msr;
unsigned int uiMask = 0xFFFFFFF7;
msr = rdmsr(BU_CFG2_MSR);
msr.hi &= uiMask; // IcDisSpecTlbWr (bit 35) = 0
wrmsr(BU_CFG2_MSR, msr);
#endif
}
void post_cache_as_ram(void)
{
void *resume_backup_memory = NULL;
uint32_t family = amd_fam1x_cpu_family();
struct romstage_handoff *handoff;
handoff = romstage_handoff_find_or_add();
if (handoff != NULL)
handoff->s3_resume = acpi_is_wakeup_s3();
else
printk(BIOS_DEBUG, "Romstage handoff structure not added!\n");
int s3resume = acpi_is_wakeup_s3();
if (s3resume) {
cbmem_recovery(s3resume);
resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
}
prepare_romstage_ramstack(resume_backup_memory);
/* from here don't store more data in CAR */
if (family < 0x6f) {
/* Family 10h or earlier */
vErrata343();
}
size_t car_size = car_data_size();
void *migrated_car = (void *)(CONFIG_RAMTOP - car_size);
print_car_debug("Copying data from cache to RAM... ");
memcpy_(migrated_car, &_car_data_start[0], car_size);
print_car_debug("Done\n");
print_car_debug("Verifying data integrity in RAM... ");
if (memcmp_(migrated_car, &_car_data_start[0], car_size) == 0)
print_car_debug("Done\n");
else
print_car_debug("FAILED\n");
/* New stack grows right below migrated_car. */
print_car_debug("Switching to use RAM as stack... ");
cache_as_ram_switch_stack(migrated_car);
/* We do not come back. */
}
void cache_as_ram_new_stack (void)
{
void *resume_backup_memory = NULL;
print_car_debug("Top about %08x ... Done\n", (uint32_t) &resume_backup_memory);
print_car_debug("Disabling cache as ram now\n");
disable_cache_as_ram_bsp();
disable_cache();
/* Enable cached access to RAM in the range 1M to CONFIG_RAMTOP */
set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
enable_cache();
if (acpi_is_wakeup_s3()) {
resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
print_car_debug("Resume backup memory location: %p\n", resume_backup_memory);
}
prepare_ramstage_region(resume_backup_memory);
set_sysinfo_in_ram(1); // So other core0 could start to train mem
/*copy and execute ramstage */
copy_and_run();
/* We will not return */
print_car_debug("should not be here -\n");
}