2013-09-07 07:41:48 +02:00
|
|
|
/*
|
|
|
|
* This file is part of the coreboot project.
|
|
|
|
*
|
2014-04-22 19:46:06 +02:00
|
|
|
* Copyright (C) 2014 Google Inc.
|
2013-09-07 07:41:48 +02:00
|
|
|
*
|
|
|
|
* 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>
|
2015-09-03 00:34:04 +02:00
|
|
|
#include <bootstate.h>
|
2013-09-07 07:41:48 +02:00
|
|
|
#include <console/console.h>
|
|
|
|
#include <cbmem.h>
|
2016-11-04 16:07:14 +01:00
|
|
|
#include <elog.h>
|
2015-03-29 06:56:22 +02:00
|
|
|
#include <fmap.h>
|
2013-09-07 07:41:48 +02:00
|
|
|
#include <ip_checksum.h>
|
2016-07-25 22:02:36 +02:00
|
|
|
#include <vboot/vboot_common.h>
|
|
|
|
|
2014-04-22 19:46:06 +02:00
|
|
|
#include "mrc_cache.h"
|
2015-09-03 00:34:04 +02:00
|
|
|
#include "nvm.h"
|
2013-09-07 07:41:48 +02:00
|
|
|
|
|
|
|
#define MRC_DATA_ALIGN 0x1000
|
|
|
|
#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24))
|
|
|
|
|
|
|
|
/* The mrc_data_region describes the larger non-volatile area to store
|
|
|
|
* mrc_saved_data objects.*/
|
|
|
|
struct mrc_data_region {
|
|
|
|
void *base;
|
|
|
|
uint32_t size;
|
|
|
|
};
|
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
enum result {
|
|
|
|
WRITE_FAILURE = -1,
|
|
|
|
ERASE_FAILURE = -2,
|
|
|
|
OTHER_FAILURE = -3,
|
|
|
|
UPDATE_SUCCESS = 0,
|
|
|
|
ALREADY_UPTODATE = 1
|
|
|
|
};
|
|
|
|
|
2013-09-07 07:41:48 +02:00
|
|
|
/* common code */
|
2016-11-06 07:57:02 +01:00
|
|
|
static int mrc_cache_get_region(const char *name,
|
|
|
|
struct mrc_data_region *region)
|
2013-09-07 07:41:48 +02:00
|
|
|
{
|
2016-04-12 23:52:29 +02:00
|
|
|
bool located_by_fmap = true;
|
|
|
|
struct region_device rdev;
|
2015-03-29 06:56:22 +02:00
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
region->base = NULL;
|
|
|
|
region->size = 0;
|
|
|
|
|
|
|
|
if (fmap_locate_area_as_rdev(name, &rdev))
|
2016-04-12 23:52:29 +02:00
|
|
|
located_by_fmap = false;
|
|
|
|
|
|
|
|
/* CHROMEOS builds must get their MRC cache from FMAP. */
|
|
|
|
if (IS_ENABLED(CONFIG_CHROMEOS) && !located_by_fmap)
|
|
|
|
return -1;
|
2015-03-29 06:56:22 +02:00
|
|
|
|
2016-04-12 23:52:29 +02:00
|
|
|
if (located_by_fmap) {
|
2015-03-29 06:56:22 +02:00
|
|
|
region->size = region_device_sz(&rdev);
|
|
|
|
region->base = rdev_mmap_full(&rdev);
|
|
|
|
|
|
|
|
if (region->base == NULL)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
region->base = (void *)CONFIG_MRC_SETTINGS_CACHE_BASE;
|
|
|
|
region->size = CONFIG_MRC_SETTINGS_CACHE_SIZE;
|
2013-09-07 07:41:48 +02:00
|
|
|
}
|
2016-04-12 23:52:29 +02:00
|
|
|
|
2013-09-07 07:41:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
/* Protect mrc region with a Protected Range Register */
|
|
|
|
static int __protect_mrc_cache(const struct mrc_data_region *region,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (nvm_is_write_protected() <= 0) {
|
|
|
|
printk(BIOS_INFO, "MRC: NOT enabling PRR for %s.\n", name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nvm_protect(region->base, region->size) < 0) {
|
|
|
|
printk(BIOS_ERR, "MRC: ERROR setting PRR for %s.\n", name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
printk(BIOS_INFO, "MRC: Enabled Protected Range on %s.\n", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int protect_mrc_cache(const char *name)
|
|
|
|
{
|
|
|
|
struct mrc_data_region region;
|
|
|
|
if (mrc_cache_get_region(name, ®ion) < 0) {
|
|
|
|
printk(BIOS_ERR, "MRC: Could not find region %s\n", name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return __protect_mrc_cache(®ion, name);
|
|
|
|
}
|
|
|
|
|
2013-09-07 07:41:48 +02:00
|
|
|
static int mrc_cache_in_region(const struct mrc_data_region *region,
|
|
|
|
const struct mrc_saved_data *cache)
|
|
|
|
{
|
|
|
|
uintptr_t region_end;
|
|
|
|
uintptr_t cache_end;
|
|
|
|
|
|
|
|
if ((uintptr_t)cache < (uintptr_t)region->base)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
region_end = (uintptr_t)region->base;
|
|
|
|
region_end += region->size;
|
|
|
|
|
|
|
|
if ((uintptr_t)cache >= region_end)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((sizeof(*cache) + (uintptr_t)cache) >= region_end)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cache_end = (uintptr_t)cache;
|
|
|
|
cache_end += cache->size + sizeof(*cache);
|
|
|
|
|
|
|
|
if (cache_end > region_end)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mrc_cache_valid(const struct mrc_data_region *region,
|
|
|
|
const struct mrc_saved_data *cache)
|
|
|
|
{
|
|
|
|
uint32_t checksum;
|
|
|
|
|
|
|
|
if (cache->signature != MRC_DATA_SIGNATURE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (cache->size > region->size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
checksum = compute_ip_checksum((void *)&cache->data[0], cache->size);
|
|
|
|
|
|
|
|
if (cache->checksum != checksum)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct mrc_saved_data *
|
|
|
|
next_cache_block(const struct mrc_saved_data *cache)
|
|
|
|
{
|
|
|
|
uintptr_t next = (uintptr_t)cache;
|
|
|
|
|
|
|
|
next += ALIGN(cache->size + sizeof(*cache), MRC_DATA_ALIGN);
|
|
|
|
|
|
|
|
return (const struct mrc_saved_data *)next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Locate the most recently saved MRC data. */
|
|
|
|
static int __mrc_cache_get_current(const struct mrc_data_region *region,
|
2015-12-09 22:04:49 +01:00
|
|
|
const struct mrc_saved_data **cache,
|
|
|
|
uint32_t version)
|
2013-09-07 07:41:48 +02:00
|
|
|
{
|
|
|
|
const struct mrc_saved_data *msd;
|
|
|
|
const struct mrc_saved_data *verified_cache;
|
2014-04-22 19:46:06 +02:00
|
|
|
int slot = 0;
|
2013-09-07 07:41:48 +02:00
|
|
|
|
|
|
|
msd = region->base;
|
|
|
|
|
|
|
|
verified_cache = NULL;
|
|
|
|
|
|
|
|
while (mrc_cache_in_region(region, msd) &&
|
|
|
|
mrc_cache_valid(region, msd)) {
|
|
|
|
verified_cache = msd;
|
|
|
|
msd = next_cache_block(msd);
|
2014-04-22 19:46:06 +02:00
|
|
|
slot++;
|
2013-09-07 07:41:48 +02:00
|
|
|
}
|
|
|
|
|
2016-07-27 17:04:54 +02:00
|
|
|
/*
|
|
|
|
* Update pointer to the most recently saved MRC data before returning
|
|
|
|
* any error. This ensures that the caller can use next available slot
|
|
|
|
* if required.
|
|
|
|
*/
|
|
|
|
*cache = verified_cache;
|
|
|
|
|
2013-09-07 07:41:48 +02:00
|
|
|
if (verified_cache == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2015-12-09 22:04:49 +01:00
|
|
|
if (verified_cache->version != version) {
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_DEBUG, "MRC: cache version mismatch: %x vs %x\n",
|
2015-12-09 22:04:49 +01:00
|
|
|
verified_cache->version, version);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_DEBUG, "MRC: cache slot %d @ %p\n", slot-1, verified_cache);
|
2014-04-22 19:46:06 +02:00
|
|
|
|
2013-09-07 07:41:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
int mrc_cache_get_current_from_region(const struct mrc_saved_data **cache,
|
|
|
|
uint32_t version,
|
|
|
|
const char *region_name)
|
2013-09-07 07:41:48 +02:00
|
|
|
{
|
|
|
|
struct mrc_data_region region;
|
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
if (!region_name) {
|
|
|
|
printk(BIOS_ERR, "MRC: Requires memory retraining.\n");
|
2013-09-07 07:41:48 +02:00
|
|
|
return -1;
|
2016-11-06 07:57:02 +01:00
|
|
|
}
|
2013-09-07 07:41:48 +02:00
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_ERR, "MRC: Using data from %s\n", region_name);
|
|
|
|
|
|
|
|
if (mrc_cache_get_region(region_name, ®ion) < 0) {
|
|
|
|
printk(BIOS_ERR, "MRC: Region %s not found. "
|
|
|
|
"Requires memory retraining.\n", region_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (__mrc_cache_get_current(®ion, cache, version) < 0) {
|
|
|
|
printk(BIOS_ERR, "MRC: Valid slot not found in %s."
|
|
|
|
"Requires memory retraining.\n", region_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mrc_cache_get_current_with_version(const struct mrc_saved_data **cache,
|
|
|
|
uint32_t version)
|
|
|
|
{
|
|
|
|
return mrc_cache_get_current_from_region(cache, version,
|
|
|
|
DEFAULT_MRC_CACHE);
|
2013-09-07 07:41:48 +02:00
|
|
|
}
|
|
|
|
|
2015-12-09 22:04:49 +01:00
|
|
|
int mrc_cache_get_current(const struct mrc_saved_data **cache)
|
|
|
|
{
|
|
|
|
return mrc_cache_get_current_with_version(cache, 0);
|
|
|
|
}
|
2016-11-06 07:57:02 +01:00
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
int mrc_cache_get_vardata(const struct mrc_saved_data **cache, uint32_t version)
|
|
|
|
{
|
|
|
|
struct mrc_data_region region;
|
|
|
|
|
|
|
|
if (mrc_cache_get_region(VARIABLE_MRC_CACHE, ®ion) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return __mrc_cache_get_current(®ion, cache, version);
|
|
|
|
}
|
|
|
|
|
2013-09-07 07:41:48 +02:00
|
|
|
/* Fill in mrc_saved_data structure with payload. */
|
2016-03-04 23:38:19 +01:00
|
|
|
static void mrc_cache_fill(struct mrc_saved_data *cache, const void *data,
|
2015-12-09 22:04:49 +01:00
|
|
|
size_t size, uint32_t version)
|
2013-09-07 07:41:48 +02:00
|
|
|
{
|
|
|
|
cache->signature = MRC_DATA_SIGNATURE;
|
|
|
|
cache->size = size;
|
2015-12-09 22:04:49 +01:00
|
|
|
cache->version = version;
|
2013-09-07 07:41:48 +02:00
|
|
|
memcpy(&cache->data[0], data, size);
|
|
|
|
cache->checksum = compute_ip_checksum((void *)&cache->data[0],
|
|
|
|
cache->size);
|
|
|
|
}
|
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
static int _mrc_stash_data(const void *data, size_t size, uint32_t version,
|
|
|
|
uint32_t cbmem_id)
|
2013-09-07 07:41:48 +02:00
|
|
|
{
|
|
|
|
int cbmem_size;
|
|
|
|
struct mrc_saved_data *cache;
|
|
|
|
|
|
|
|
cbmem_size = sizeof(*cache) + ALIGN(size, 16);
|
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
cache = cbmem_add(cbmem_id, cbmem_size);
|
2013-09-07 07:41:48 +02:00
|
|
|
|
|
|
|
if (cache == NULL) {
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_ERR, "MRC: No space in cbmem for training data.\n");
|
2013-09-07 07:41:48 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-02-05 21:55:26 +01:00
|
|
|
/* Clear alignment padding bytes at end of data. */
|
|
|
|
memset(&cache->data[size], 0, cbmem_size - size - sizeof(*cache));
|
2013-09-07 07:41:48 +02:00
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_DEBUG, "MRC: Relocate data from %p to %p (%zu bytes)\n",
|
2013-09-07 07:41:48 +02:00
|
|
|
data, cache, size);
|
|
|
|
|
2015-12-09 22:04:49 +01:00
|
|
|
mrc_cache_fill(cache, data, size, version);
|
2013-09-07 07:41:48 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
int mrc_cache_stash_data_with_version(const void *data, size_t size,
|
|
|
|
uint32_t version)
|
|
|
|
{
|
|
|
|
return _mrc_stash_data(data, size, version, CBMEM_ID_MRCDATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mrc_cache_stash_vardata(const void *data, size_t size, uint32_t version)
|
|
|
|
{
|
|
|
|
return _mrc_stash_data(data, size, version, CBMEM_ID_VAR_MRCDATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-04 23:38:19 +01:00
|
|
|
int mrc_cache_stash_data(const void *data, size_t size)
|
2015-12-09 22:04:49 +01:00
|
|
|
{
|
|
|
|
return mrc_cache_stash_data_with_version(data, size, 0);
|
|
|
|
}
|
|
|
|
|
2013-09-07 07:41:48 +02:00
|
|
|
static int mrc_slot_valid(const struct mrc_data_region *region,
|
|
|
|
const struct mrc_saved_data *slot,
|
|
|
|
const struct mrc_saved_data *to_save)
|
|
|
|
{
|
|
|
|
uintptr_t region_begin;
|
|
|
|
uintptr_t region_end;
|
|
|
|
uintptr_t slot_end;
|
|
|
|
uintptr_t slot_begin;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
region_begin = (uintptr_t)region->base;
|
|
|
|
region_end = region_begin + region->size;
|
|
|
|
slot_begin = (uintptr_t)slot;
|
|
|
|
size = to_save->size + sizeof(*to_save);
|
|
|
|
slot_end = slot_begin + size;
|
|
|
|
|
2014-02-05 21:55:26 +01:00
|
|
|
if (slot_begin < region_begin || slot_begin >= region_end)
|
2013-09-07 07:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (size > region->size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (slot_end > region_end || slot_end < region_begin)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!nvm_is_erased(slot, size))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct mrc_saved_data *
|
|
|
|
mrc_cache_next_slot(const struct mrc_data_region *region,
|
|
|
|
const struct mrc_saved_data *current_slot)
|
|
|
|
{
|
|
|
|
const struct mrc_saved_data *next_slot;
|
|
|
|
|
|
|
|
if (current_slot == NULL) {
|
|
|
|
next_slot = region->base;
|
|
|
|
} else {
|
|
|
|
next_slot = next_cache_block(current_slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
return next_slot;
|
|
|
|
}
|
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
static void log_event_cache_update(uint8_t slot, enum result res)
|
2016-11-04 16:07:14 +01:00
|
|
|
{
|
|
|
|
const int type = ELOG_TYPE_MEM_CACHE_UPDATE;
|
|
|
|
struct elog_event_mem_cache_update event = {
|
2016-11-08 17:30:06 +01:00
|
|
|
.slot = slot
|
2016-11-04 16:07:14 +01:00
|
|
|
};
|
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
/* Filter through interesting events only */
|
|
|
|
switch (res) {
|
|
|
|
case WRITE_FAILURE: /* fall-through */
|
|
|
|
case ERASE_FAILURE: /* fall-through */
|
|
|
|
case OTHER_FAILURE: /* fall-through */
|
|
|
|
event.status = ELOG_MEM_CACHE_UPDATE_STATUS_FAIL;
|
|
|
|
break;
|
|
|
|
case UPDATE_SUCCESS:
|
|
|
|
event.status = ELOG_MEM_CACHE_UPDATE_STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-04 16:07:14 +01:00
|
|
|
if (elog_add_event_raw(type, &event, sizeof(event)) < 0)
|
|
|
|
printk(BIOS_ERR, "Failed to log mem cache update event.\n");
|
|
|
|
}
|
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
static int update_mrc_cache_type(uint32_t cbmem_id, const char *region_name)
|
2013-09-07 07:41:48 +02:00
|
|
|
{
|
|
|
|
const struct mrc_saved_data *current_boot;
|
|
|
|
const struct mrc_saved_data *current_saved;
|
|
|
|
const struct mrc_saved_data *next_slot;
|
|
|
|
struct mrc_data_region region;
|
2016-11-08 17:30:06 +01:00
|
|
|
int res;
|
2013-09-07 07:41:48 +02:00
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_DEBUG, "MRC: Updating cache data.\n");
|
2013-09-07 07:41:48 +02:00
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_ERR, "MRC: Cache region selected - %s\n", region_name);
|
|
|
|
|
|
|
|
if (mrc_cache_get_region(region_name, ®ion)) {
|
|
|
|
printk(BIOS_ERR, "MRC: Could not obtain cache region.\n");
|
2016-11-08 17:30:06 +01:00
|
|
|
return OTHER_FAILURE;
|
2013-09-07 07:41:48 +02:00
|
|
|
}
|
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
current_boot = cbmem_find(cbmem_id);
|
2016-11-06 07:57:02 +01:00
|
|
|
if (!current_boot) {
|
|
|
|
printk(BIOS_ERR, "MRC: No cache in cbmem.\n");
|
2016-11-08 17:30:06 +01:00
|
|
|
return OTHER_FAILURE;
|
2013-09-07 07:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!mrc_cache_valid(®ion, current_boot)) {
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_ERR, "MRC: Cache data in cbmem invalid.\n");
|
2016-11-08 17:30:06 +01:00
|
|
|
return OTHER_FAILURE;
|
2013-09-07 07:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
current_saved = NULL;
|
|
|
|
|
2015-12-09 22:04:49 +01:00
|
|
|
if (!__mrc_cache_get_current(®ion, ¤t_saved,
|
|
|
|
current_boot->version)) {
|
2013-09-07 07:41:48 +02:00
|
|
|
if (current_saved->size == current_boot->size &&
|
|
|
|
!memcmp(¤t_saved->data[0], ¤t_boot->data[0],
|
|
|
|
current_saved->size)) {
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_DEBUG, "MRC: Cache up to date.\n");
|
2016-11-08 17:30:06 +01:00
|
|
|
return ALREADY_UPTODATE;
|
2013-09-07 07:41:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
next_slot = mrc_cache_next_slot(®ion, current_saved);
|
|
|
|
|
|
|
|
if (!mrc_slot_valid(®ion, next_slot, current_boot)) {
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_DEBUG, "MRC: Slot @ %p is invalid.\n", next_slot);
|
2014-01-13 18:34:51 +01:00
|
|
|
if (!nvm_is_erased(region.base, region.size)) {
|
|
|
|
if (nvm_erase(region.base, region.size) < 0) {
|
2016-11-06 07:57:02 +01:00
|
|
|
printk(BIOS_DEBUG, "MRC: Failure erasing "
|
|
|
|
"region %s.\n", region_name);
|
2016-11-08 17:30:06 +01:00
|
|
|
return ERASE_FAILURE;
|
2014-01-13 18:34:51 +01:00
|
|
|
}
|
2013-09-07 07:41:48 +02:00
|
|
|
}
|
|
|
|
next_slot = region.base;
|
|
|
|
}
|
|
|
|
|
2016-11-08 17:30:06 +01:00
|
|
|
res = nvm_write((void *)next_slot, current_boot, current_boot->size
|
|
|
|
+ sizeof(*current_boot));
|
|
|
|
return res < 0 ? WRITE_FAILURE : UPDATE_SUCCESS;
|
2016-11-06 07:57:02 +01:00
|
|
|
}
|
2016-11-04 16:07:14 +01:00
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
static void protect_mrc_region(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Check if there is a single unified region that encompasses both
|
|
|
|
* RECOVERY_MRC_CACHE and DEFAULT_MRC_CACHE. In that case protect the
|
|
|
|
* entire region using a single PRR.
|
|
|
|
*
|
|
|
|
* If we are not able to protect the entire region, try protecting
|
|
|
|
* individual regions next.
|
|
|
|
*/
|
|
|
|
if (protect_mrc_cache(UNIFIED_MRC_CACHE) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE))
|
|
|
|
protect_mrc_cache(RECOVERY_MRC_CACHE);
|
|
|
|
|
|
|
|
protect_mrc_cache(DEFAULT_MRC_CACHE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_mrc_cache(void *unused)
|
|
|
|
{
|
2016-11-08 17:30:06 +01:00
|
|
|
uint8_t slot;
|
|
|
|
const char *region_name;
|
|
|
|
enum result res;
|
|
|
|
|
|
|
|
/* First update either recovery or default cache */
|
|
|
|
if (vboot_recovery_mode_enabled() &&
|
|
|
|
IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE)) {
|
|
|
|
region_name = RECOVERY_MRC_CACHE;
|
|
|
|
slot = ELOG_MEM_CACHE_UPDATE_SLOT_RECOVERY;
|
|
|
|
} else {
|
|
|
|
region_name = DEFAULT_MRC_CACHE;
|
|
|
|
slot = ELOG_MEM_CACHE_UPDATE_SLOT_NORMAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = update_mrc_cache_type(CBMEM_ID_MRCDATA, region_name);
|
|
|
|
log_event_cache_update(slot, res);
|
|
|
|
|
|
|
|
/* Next update variable cache if in use */
|
|
|
|
if (IS_ENABLED(CONFIG_MRC_SETTINGS_VARIABLE_DATA)) {
|
|
|
|
res = update_mrc_cache_type(CBMEM_ID_VAR_MRCDATA,
|
|
|
|
VARIABLE_MRC_CACHE);
|
|
|
|
log_event_cache_update(ELOG_MEM_CACHE_UPDATE_SLOT_VARIABLE,
|
|
|
|
res);
|
|
|
|
}
|
|
|
|
|
2016-11-06 07:57:02 +01:00
|
|
|
protect_mrc_region();
|
2013-09-07 07:41:48 +02:00
|
|
|
}
|
|
|
|
|
2015-03-16 23:30:09 +01:00
|
|
|
BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, update_mrc_cache, NULL);
|