coreboot-kgpe-d16/src/cpu/x86/car.c
Martin Roth 582b2aee0f FSP & CBMEM: Fix broken cbmem CAR transition.
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>
2015-02-06 00:53:13 +01:00

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();
}