582b2aee0f
1) Save the pointer to the FSP HOB list to low memory at address 0x614. This is the same location as CBMEM_RESUME_BACKUP - the two aren't used in the same platform, so overlapping should be OK. I didn't see any documentation that actually said that this location was free to use, and didn't need to be restored after use in S3 resume, but it looks like the DOS boot vector gets loaded juat above this location, so it SHOULD be ok. The alternative is to copy the memory out and store it in cbmem until we're ready to restore it. 2) When a request for the pointer to a CAR variable comes in, pass back the location inside the FSP hob structure. 3) Skip the memcopy of the CAR Data. The CAR variables do not get transitioned back into cbmem, but used out of the HOB structure. 4) Remove the BROKEN_CAR_MIGRATE Kconfig option from the FSP platform. Change-Id: Iaf566dce1b41a3bcb17e4134877f68262b5e113f Signed-off-by: Martin Roth <gaumless@gmail.com> Reviewed-on: http://review.coreboot.org/8196 Reviewed-by: Aaron Durbin <adurbin@google.com> Tested-by: build bot (Jenkins) Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
157 lines
4.2 KiB
C
157 lines
4.2 KiB
C
/*
|
|
* This file is part of the coreboot project.
|
|
*
|
|
* Copyright (C) 2013 Google, Inc.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stddef.h>
|
|
#include <console/console.h>
|
|
#include <cbmem.h>
|
|
#include <arch/early_variables.h>
|
|
|
|
#if IS_ENABLED(CONFIG_PLATFORM_USES_FSP)
|
|
#include <drivers/intel/fsp/fsp_util.h>
|
|
#endif
|
|
typedef void (* const car_migration_func_t)(void);
|
|
|
|
extern car_migration_func_t _car_migrate_start;
|
|
|
|
extern char _car_data_start[];
|
|
extern char _car_data_end[];
|
|
|
|
/*
|
|
* The car_migrated global variable determines if the cache-as-ram space has
|
|
* been migrated to real RAM. It does this by assuming the following things:
|
|
* 1. cache-as-ram space is zero'd out once it is set up.
|
|
* 2. Either the cache-as-ram space is memory-backed after getting torn down
|
|
* or the space returns 0xff's for each byte read.
|
|
* Based on these 2 attributes there is the ability to tell when the
|
|
* cache-as-ram region has been migrated.
|
|
*/
|
|
static int car_migrated CAR_GLOBAL;
|
|
|
|
/** @brief returns pointer to a CAR variable, before or after migration.
|
|
*
|
|
* @param var pointer to the CAR variable
|
|
*/
|
|
void *car_get_var_ptr(void *var)
|
|
{
|
|
char *migrated_base = NULL;
|
|
int offset;
|
|
void * _car_start = &_car_data_start;
|
|
void * _car_end = &_car_data_end;
|
|
|
|
/* If the cache-as-ram has not been migrated return the pointer
|
|
* passed in. */
|
|
if (!car_migrated)
|
|
return var;
|
|
|
|
if (var < _car_start || var >= _car_end) {
|
|
printk(BIOS_ERR,
|
|
"Requesting CAR variable outside of CAR region: %p\n",
|
|
var);
|
|
return var;
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_PLATFORM_USES_FSP)
|
|
migrated_base=(char *)find_saved_temp_mem(
|
|
*(void **)CBMEM_FSP_HOB_PTR);
|
|
#else
|
|
migrated_base = cbmem_find(CBMEM_ID_CAR_GLOBALS);
|
|
#endif
|
|
|
|
if (migrated_base == NULL)
|
|
die( "CAR: Could not find migration base!\n");
|
|
|
|
offset = (char *)var - (char *)_car_start;
|
|
|
|
return &migrated_base[offset];
|
|
}
|
|
|
|
/*
|
|
* Update a CAR_GLOBAL variable var, originally pointing to CAR region,
|
|
* with the address in migrated CAR region in DRAM.
|
|
*/
|
|
void *car_sync_var_ptr(void *var)
|
|
{
|
|
void ** mig_var = car_get_var_ptr(var);
|
|
void * _car_start = &_car_data_start;
|
|
void * _car_end = &_car_data_end;
|
|
|
|
/* Not moved or migrated yet. */
|
|
if (mig_var == var)
|
|
return mig_var;
|
|
|
|
/* It's already pointing outside car.global_data. */
|
|
if (*mig_var < _car_start || *mig_var > _car_end)
|
|
return mig_var;
|
|
|
|
#if !IS_ENABLED(CONFIG_PLATFORM_USES_FSP)
|
|
/* Keep console buffer in CAR until cbmemc_reinit() moves it. */
|
|
if (*mig_var == _car_end)
|
|
return mig_var;
|
|
#endif
|
|
|
|
/* Move the pointer by the same amount the variable storing it was
|
|
* moved by.
|
|
*/
|
|
*mig_var += (char *)mig_var - (char *)var;
|
|
|
|
return mig_var;
|
|
}
|
|
|
|
static void do_car_migrate_variables(void)
|
|
{
|
|
void *migrated_base;
|
|
size_t car_data_size = &_car_data_end[0] - &_car_data_start[0];
|
|
|
|
/* Check if already migrated. */
|
|
if (car_migrated)
|
|
return;
|
|
|
|
migrated_base = cbmem_add(CBMEM_ID_CAR_GLOBALS, car_data_size);
|
|
|
|
if (migrated_base == NULL) {
|
|
printk(BIOS_ERR, "Could not migrate CAR data!\n");
|
|
return;
|
|
}
|
|
|
|
memcpy(migrated_base, &_car_data_start[0], car_data_size);
|
|
|
|
/* Mark that the data has been moved. */
|
|
car_migrated = ~0;
|
|
}
|
|
|
|
static void do_car_migrate_hooks(void)
|
|
{
|
|
car_migration_func_t *migrate_func;
|
|
/* Call all the migration functions. */
|
|
migrate_func = &_car_migrate_start;
|
|
while (*migrate_func != NULL) {
|
|
(*migrate_func)();
|
|
migrate_func++;
|
|
}
|
|
}
|
|
|
|
void car_migrate_variables(void)
|
|
{
|
|
if (!IS_ENABLED(CONFIG_BROKEN_CAR_MIGRATE) && !IS_ENABLED(PLATFORM_USES_FSP))
|
|
do_car_migrate_variables();
|
|
|
|
if (!IS_ENABLED(CONFIG_BROKEN_CAR_MIGRATE))
|
|
do_car_migrate_hooks();
|
|
}
|