diff options
author | Kyösti Mälkki <kyosti.malkki@gmail.com> | 2013-12-29 12:07:54 +0200 |
---|---|---|
committer | Kyösti Mälkki <kyosti.malkki@gmail.com> | 2014-11-14 15:44:56 +0100 |
commit | abc083e06bcb8d20a58d04323d5c6da7313f987d (patch) | |
tree | 60e5d06fa1178a71f21df2779f8ea84bf6be886f /src | |
parent | 3eefeea9d58ab2896aec7ded7aa1a15e8e9fa72c (diff) |
AMD (K8/fam10): Rewrite CAR migration in post_cache_as_ram
Old routine copied all of CAR region as-is right below CONFIG_RAMTOP.
Most of this region was reserved to interleave AP CPU address spaces
and unused on BSP CPU. The only part of CAR region requiring a copy
in RAM is the sysinfo structure.
Improved routine changes this as follows:
A region of size 'backup_size' below CONFIG_RAMTOP is cleared. In
case of S3 resume, OS context from this region is first copied to
high memory (CBMEM_ID_RESUME).
At stack switch, CAR stack is discarded. Top of the stack for BSP
is located at 'CONFIG_RAMTOP - car_size' for the remaining part
of the romstage. This region is part of 'backup_size' and was zeroed
before the switch took place.
Before CAR is torn down the region of CAR_GLOBALS (and CAR_CBMEM),
including the relevant sysinfo data for AP nodes memory training,
is copied at 'CONFIG_RAMTOP - car_size'.
NOTE: While CAR_GLOBAL variables are recovered, there are currently
no means to calculate their offsets in RAM.
NOTE: Boards with multiple CPU packages are likely already broken since
bbc880ee amdk8/amdfam10: Use CAR_GLOBAL for sysinfo
This moved the copy of sysinfo in RAM from above the stack to below
the stack, but code for AP CPU's was not adjusted accordingly.
Change-Id: Ie45b576aec6a2e006bfcb26b52fdb77c24f72e3b
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: http://review.coreboot.org/4583
Tested-by: build bot (Jenkins)
Reviewed-by: Edward O'Callaghan <eocallaghan@alterapraxis.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/cpu/amd/car/cache_as_ram.inc | 5 | ||||
-rw-r--r-- | src/cpu/amd/car/post_cache_as_ram.c | 174 | ||||
-rw-r--r-- | src/include/cpu/amd/car.h | 4 |
3 files changed, 91 insertions, 92 deletions
diff --git a/src/cpu/amd/car/cache_as_ram.inc b/src/cpu/amd/car/cache_as_ram.inc index dd02f6c734..dadf8f7224 100644 --- a/src/cpu/amd/car/cache_as_ram.inc +++ b/src/cpu/amd/car/cache_as_ram.inc @@ -424,10 +424,9 @@ CAR_FAM10_ap_out: cache_as_ram_switch_stack: /* Return address. */ popl %eax - /* Resume memory. */ + /* New stack. */ popl %eax - subl $(( (CONFIG_DCACHE_RAM_BASE + CONFIG_DCACHE_RAM_SIZE)- (CONFIG_RAMTOP) )), %esp - pushl %eax + movl %eax, %esp call cache_as_ram_new_stack all_mtrr_msrs: diff --git a/src/cpu/amd/car/post_cache_as_ram.c b/src/cpu/amd/car/post_cache_as_ram.c index 3a0763aec2..61874a907a 100644 --- a/src/cpu/amd/car/post_cache_as_ram.c +++ b/src/cpu/amd/car/post_cache_as_ram.c @@ -10,58 +10,78 @@ #include "cbmem.h" #include "cpu/amd/car/disable_cache_as_ram.c" -static inline void print_debug_pcar(const char *strval, uint32_t val) +#if CONFIG_RAMTOP <= 0x100000 + #error "You need to set CONFIG_RAMTOP greater than 1M" +#endif + +#define PRINTK_IN_CAR 1 + +#if PRINTK_IN_CAR +#define print_car_debug(x) print_debug(x) +#else +#define print_car_debug(x) +#endif + +extern char _car_data_start[]; +extern char _car_data_end[]; + +static size_t car_data_size(void) { - printk(BIOS_DEBUG, "%s%08x\n", strval, val); + size_t car_size = &_car_data_end[0] - &_car_data_start[0]; + return ALIGN(car_size, 64); } -/* from linux kernel 2.6.32 asm/string_32.h */ - -static void inline __attribute__((always_inline)) memcopy(void *dest, const void *src, unsigned long bytes) +static size_t backup_size(void) { - int d0, d1, d2; - asm volatile("cld ; rep ; movsl\n\t" - "movl %4,%%ecx\n\t" - "andl $3,%%ecx\n\t" - "jz 1f\n\t" - "rep ; movsb\n\t" - "1:" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - : "0" (bytes / 4), "g" (bytes), "1" ((long)dest), "2" ((long)src) - : "memory", "cc"); + size_t car_size = &_car_data_end[0] - &_car_data_start[0]; + return ALIGN(car_size + 1024, 1024); } -#if CONFIG_HAVE_ACPI_RESUME +static void memcpy_(void *d, const void *s, size_t len) +{ +#if PRINTK_IN_CAR + printk(BIOS_SPEW, " Copy [%08x-%08x] to [%08x - %08x] ... ", + (u32) s, (u32) (s + len - 1), (u32) d, (u32) (d + len - 1)); +#endif + memcpy(d, s, len); +} -static inline void *backup_resume(void) { - void *resume_backup_memory; - int suspend = acpi_is_wakeup_early(); +static void memset_(void *d, int val, size_t len) +{ +#if PRINTK_IN_CAR + printk(BIOS_SPEW, " Fill [%08x-%08x] ... ", (u32) d, (u32) (d + len - 1)); +#endif + memset(d, val, len); +} - if (!suspend) - return NULL; +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 (cbmem_recovery(1)) - return NULL; + 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); - resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); + print_car_debug("Done\n"); +} - /* copy 1MB - 64K to high tables ram_base to prevent memory corruption - * through stage 2. We could keep stuff like stack and heap in high tables - * memory completely, but that's a wonderful clean up task for another - * day. - */ +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) { - print_debug_pcar("Will copy coreboot region to: ", (uint32_t) resume_backup_memory); - /* copy only backup only memory used for CAR */ - memcopy(resume_backup_memory+HIGH_MEMORY_SAVE-CONFIG_DCACHE_RAM_SIZE, - (void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE), - CONFIG_DCACHE_RAM_SIZE); //inline + 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); } - return resume_backup_memory; + print_car_debug("Done\n"); } -#endif /* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */ @@ -80,73 +100,53 @@ static void vErrata343(void) void post_cache_as_ram(void) { void *resume_backup_memory = NULL; -#if 1 - { - /* Check value of esp to verify if we have enough room for stack in Cache as RAM */ - unsigned v_esp; - __asm__ volatile ( - "movl %%esp, %0\n\t" - : "=a" (v_esp) - ); - print_debug_pcar("v_esp=", v_esp); - } -#endif - - /* copy data from cache as ram to - ram need to set CONFIG_RAMTOP to 2M and use var mtrr instead. - */ -#if CONFIG_RAMTOP <= 0x100000 - #error "You need to set CONFIG_RAMTOP greater than 1M" -#endif -#if CONFIG_HAVE_ACPI_RESUME - resume_backup_memory = backup_resume(); + int s3resume = acpi_s3_resume_allowed() && acpi_is_wakeup_early(); + if (s3resume) { +#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) + cbmem_recovery(s3resume); + resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); #endif - - print_debug("Copying data from cache to RAM -- switching to use RAM as stack... "); + } + prepare_romstage_ramstack(resume_backup_memory); /* from here don't store more data in CAR */ vErrata343(); - memcopy((void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE), (void *)CONFIG_DCACHE_RAM_BASE, CONFIG_DCACHE_RAM_SIZE); //inline - cache_as_ram_switch_stack(resume_backup_memory); -} + size_t car_size = car_data_size(); + void *migrated_car = (void *)(CONFIG_RAMTOP - car_size); -void -cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused))) -{ - /* We can put data to stack again */ + print_car_debug("Copying data from cache to RAM... "); + memcpy_(migrated_car, &_car_data_start[0], car_size); + print_car_debug("Done\n"); + + /* New stack grows right below migrated_car. */ + print_car_debug("Switching to use RAM as stack... "); + cache_as_ram_switch_stack(migrated_car); - /* only global variable sysinfo in cache need to be offset */ - print_debug("Done\n"); + /* We do not come back. */ +} - print_debug("Disabling cache as ram now \n"); +void cache_as_ram_new_stack (void) +{ + void *resume_backup_memory = NULL; +#if PRINTK_IN_CAR + printk(BIOS_DEBUG, "Top about %08x ... Done\n", (u32) &resume_backup_memory); +#endif + print_car_debug("Disabling cache as ram now\n"); disable_cache_as_ram_bsp(); disable_cache(); set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK); enable_cache(); -#if CONFIG_HAVE_ACPI_RESUME - /* now copy the rest of the area, using the WB method because we already - run normal RAM */ - if (resume_backup_memory) { - memcopy(resume_backup_memory, - (void *)(CONFIG_RAMBASE), - (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE); - } + if (acpi_s3_resume_allowed() && acpi_is_wakeup_early()) { +#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) + resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); #endif - - print_debug("Clearing initial memory region: "); - -#if CONFIG_HAVE_ACPI_RESUME - /* clear only coreboot used region of memory. Note: this may break ECC enabled boards */ - memset((void*) CONFIG_RAMBASE, 0, (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE); -#else - memset((void*)0, 0, ((CONFIG_RAMTOP) - CONFIG_DCACHE_RAM_SIZE)); -#endif - print_debug("Done\n"); + } + prepare_ramstage_region(resume_backup_memory); set_sysinfo_in_ram(1); // So other core0 could start to train mem @@ -154,5 +154,5 @@ cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused))) copy_and_run(); /* We will not return */ - print_debug("should not be here -\n"); + print_car_debug("should not be here -\n"); } diff --git a/src/include/cpu/amd/car.h b/src/include/cpu/amd/car.h index a001c9345f..c00310a61f 100644 --- a/src/include/cpu/amd/car.h +++ b/src/include/cpu/amd/car.h @@ -5,8 +5,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx); void done_cache_as_ram_main(void); void post_cache_as_ram(void); -void cache_as_ram_switch_stack(void *resume_backup_memory); -void cache_as_ram_new_stack(void *resume_backup_memory); +void cache_as_ram_switch_stack(void *stacktop); +void cache_as_ram_new_stack(void); #if CONFIG_CPU_AMD_AGESA void disable_cache_as_ram(void); |