| /* |
| * This file is part of the coreboot project. |
| * |
| * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, |
| * Raptor Engineering |
| * Copyright (C) 2012 Google LLC |
| * 2005.6 by yhlu |
| * 2006.3 yhlu add copy data from CAR to ram |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; version 2 of the License. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| #include <string.h> |
| #include <console/console.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 <cpu/amd/msr.h> |
| #include <arch/acpi.h> |
| #include <romstage_handoff.h> |
| |
| #include "cpu/amd/car/disable_cache_as_ram.c" |
| |
| // For set_sysinfo_in_ram() |
| #include <northbridge/amd/amdfam10/raminit.h> |
| |
| #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(int s3resume) |
| { |
| size_t backup_top = backup_size(); |
| print_car_debug("Prepare CAR migration and stack regions..."); |
| |
| if (s3resume) { |
| void *resume_backup_memory = |
| acpi_backup_container(CONFIG_RAMBASE, HIGH_MEMORY_SAVE); |
| 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(int s3resume) |
| { |
| size_t backup_top = backup_size(); |
| print_car_debug("Prepare ramstage memory region..."); |
| |
| if (s3resume) { |
| void *resume_backup_memory = |
| acpi_backup_container(CONFIG_RAMBASE, HIGH_MEMORY_SAVE); |
| if (resume_backup_memory) |
| memcpy_(resume_backup_memory, (void *) CONFIG_RAMBASE, |
| HIGH_MEMORY_SAVE - backup_top); |
| } |
| |
| print_car_debug(" Done\n"); |
| } |
| |
| /* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 |
| * and RevGuide for Fam12h, Pub#44739 Rev 3.10 |
| */ |
| |
| static void vErrata343(void) |
| { |
| msr_t msr; |
| unsigned int uiMask = 0xFFFFFFF7; |
| |
| msr = rdmsr(BU_CFG2_MSR); |
| msr.hi &= uiMask; // IcDisSpecTlbWr (bit 35) = 0 |
| wrmsr(BU_CFG2_MSR, msr); |
| } |
| |
| asmlinkage void *post_cache_as_ram(void) |
| { |
| uint32_t family = amd_fam1x_cpu_family(); |
| int s3resume = 0; |
| |
| /* Verify that the BSP didn't overrun the lower stack |
| * boundary during romstage execution |
| */ |
| volatile uint32_t *lower_stack_boundary; |
| lower_stack_boundary = |
| (void *)((CONFIG_DCACHE_RAM_BASE + CONFIG_DCACHE_RAM_SIZE) |
| - CONFIG_DCACHE_BSP_STACK_SIZE); |
| if ((*lower_stack_boundary) != 0xdeadbeef) |
| printk(BIOS_WARNING, "BSP overran lower stack boundary. Undefined behaviour may result!\n"); |
| |
| s3resume = acpi_is_wakeup_s3(); |
| |
| prepare_romstage_ramstack(s3resume); |
| |
| romstage_handoff_init(s3resume); |
| |
| /* from here don't store more data in CAR */ |
| if (family >= 0x1f && family <= 0x3f) { |
| /* Family 10h and 12h, 11h until shown otherwise */ |
| 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_relocatable_data_start, car_size); |
| print_car_debug(" Done\n"); |
| |
| print_car_debug("Verifying data integrity in RAM..."); |
| if (memcmp_(migrated_car, _car_relocatable_data_start, 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..."); |
| return migrated_car; |
| } |
| |
| asmlinkage void cache_as_ram_new_stack(void) |
| { |
| print_car_debug("Disabling cache as RAM now\n"); |
| disable_cache_as_ram_real(0); // inline |
| |
| disable_cache(); |
| /* Enable cached access to RAM in the range 0M to CACHE_TMP_RAMTOP */ |
| set_var_mtrr(0, 0x00000000, CACHE_TMP_RAMTOP, MTRR_TYPE_WRBACK); |
| enable_cache(); |
| |
| prepare_ramstage_region(acpi_is_wakeup_s3()); |
| |
| 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"); |
| } |