aboutsummaryrefslogtreecommitdiff
path: root/src/drivers/mrc_cache/mrc_cache.c
diff options
context:
space:
mode:
authorShelley Chen <shchen@google.com>2020-07-23 16:10:52 -0700
committerShelley Chen <shchen@google.com>2020-08-24 23:30:50 +0000
commitad9cd687b83061391d44bfc55a625b5571ff32a9 (patch)
tree4187e82feda28c383ab629c965a74f71cf336c61 /src/drivers/mrc_cache/mrc_cache.c
parent73f8986ad27b528f94e8385cacdbec1a10373148 (diff)
mrc_cache: Add mrc_cache fetch functions to support non-x86 platforms
Create two new functions to fetch mrc_cache data (replacing mrc_cache_get_current): - mrc_cache_load_current: fetches the mrc_cache data and drops it into the given buffer. This is useful for ARM platforms where the mmap operation is very expensive. - mrc_cache_mmap_leak: fetch the mrc_cache data and puts it into a given buffer. This is useful for platforms where the mmap operation is a no-op (like x86 platforms). As the name mentions, we are not freeing the memory that we allocated with the mmap, so it is the caller's responsibility to do so. Additionally, we are replacing mrc_cache_latest with mrc_cache_get_latest_slot_info, which does not check the validity of the data when retrieving the current mrc_cache slot. This allows the caller some flexibility in deciding where they want the mrc_cache data stored (either in an mmaped region or at a given address). BUG=b:150502246 BRANCH=None TEST=Testing on a nami (x86) device: reboot from ec console. Make sure memory training happens. reboot from ec console. Make sure that we don't do training again. Signed-off-by: Shelley Chen <shchen@google.com> Change-Id: I259dd4f550719d821bbafa2d445cbae6ea22e988 Reviewed-on: https://review.coreboot.org/c/coreboot/+/44006 Reviewed-by: Furquan Shaikh <furquan@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/drivers/mrc_cache/mrc_cache.c')
-rw-r--r--src/drivers/mrc_cache/mrc_cache.c106
1 files changed, 78 insertions, 28 deletions
diff --git a/src/drivers/mrc_cache/mrc_cache.c b/src/drivers/mrc_cache/mrc_cache.c
index d567a20f11..1b1ad6332f 100644
--- a/src/drivers/mrc_cache/mrc_cache.c
+++ b/src/drivers/mrc_cache/mrc_cache.c
@@ -204,23 +204,16 @@ static int mrc_header_valid(struct region_device *rdev, struct mrc_metadata *md)
return 0;
}
-static int mrc_data_valid(const struct region_device *rdev,
- const struct mrc_metadata *md)
+static int mrc_data_valid(const struct mrc_metadata *md,
+ void *data, size_t data_size)
{
- void *data;
uint16_t checksum;
- const size_t md_size = sizeof(*md);
- const size_t data_size = md->data_size;
- data = rdev_mmap(rdev, md_size, data_size);
- if (data == NULL) {
- printk(BIOS_ERR, "MRC: mmap failure on data verification.\n");
+ if (md->data_size != data_size)
return -1;
- }
checksum = compute_ip_checksum(data, data_size);
- rdev_munmap(rdev, data);
if (md->data_checksum != checksum) {
printk(BIOS_ERR, "MRC: data checksum mismatch: %x vs %x\n",
md->data_checksum, checksum);
@@ -230,7 +223,7 @@ static int mrc_data_valid(const struct region_device *rdev,
return 0;
}
-static int mrc_cache_latest(const char *name,
+static int mrc_cache_get_latest_slot_info(const char *name,
const struct region_device *backing_rdev,
struct mrc_metadata *md,
struct region_file *cache_file,
@@ -260,25 +253,19 @@ static int mrc_cache_latest(const char *name,
return fail_bad_data ? -1 : 0;
}
- /* Validate Data */
- if (mrc_data_valid(rdev, md) < 0) {
- printk(BIOS_ERR, "MRC: invalid data in '%s'\n", name);
- return fail_bad_data ? -1 : 0;
- }
-
return 0;
}
-int mrc_cache_get_current(int type, uint32_t version,
- struct region_device *rdev)
+static int mrc_cache_find_current(int type, uint32_t version,
+ struct region_device *rdev,
+ struct mrc_metadata *md)
{
const struct cache_region *cr;
struct region region;
struct region_device read_rdev;
struct region_file cache_file;
- struct mrc_metadata md;
size_t data_size;
- const size_t md_size = sizeof(md);
+ const size_t md_size = sizeof(*md);
const bool fail_bad_data = true;
cr = lookup_region(&region, type);
@@ -289,21 +276,75 @@ int mrc_cache_get_current(int type, uint32_t version,
if (boot_device_ro_subregion(&region, &read_rdev) < 0)
return -1;
- if (mrc_cache_latest(cr->name, &read_rdev, &md, &cache_file, rdev,
- fail_bad_data) < 0)
+ if (mrc_cache_get_latest_slot_info(cr->name,
+ &read_rdev,
+ md,
+ &cache_file,
+ rdev,
+ fail_bad_data) < 0)
return -1;
- if (version != md.version) {
+ if (version != md->version) {
printk(BIOS_INFO, "MRC: version mismatch: %x vs %x\n",
- md.version, version);
+ md->version, version);
return -1;
}
/* Re-size rdev to only contain the data. i.e. remove metadata. */
- data_size = md.data_size;
+ data_size = md->data_size;
return rdev_chain(rdev, rdev, md_size, data_size);
}
+int mrc_cache_load_current(int type, uint32_t version, void *buffer,
+ size_t buffer_size)
+{
+ struct region_device rdev;
+ struct mrc_metadata md;
+ size_t data_size;
+
+ if (mrc_cache_find_current(type, version, &rdev, &md) < 0)
+ return -1;
+
+ data_size = region_device_sz(&rdev);
+ if (buffer_size < data_size)
+ return -1;
+
+ if (rdev_readat(&rdev, buffer, 0, data_size) != data_size)
+ return -1;
+
+ if (mrc_data_valid(&md, buffer, data_size) < 0)
+ return -1;
+
+ return 0;
+}
+
+void *mrc_cache_current_mmap_leak(int type, uint32_t version,
+ size_t *data_size)
+{
+ struct region_device rdev;
+ void *data;
+ size_t region_device_size;
+ struct mrc_metadata md;
+
+ if (mrc_cache_find_current(type, version, &rdev, &md) < 0)
+ return NULL;
+
+ region_device_size = region_device_sz(&rdev);
+ if (data_size)
+ *data_size = region_device_size;
+ data = rdev_mmap_full(&rdev);
+
+ if (data == NULL) {
+ printk(BIOS_INFO, "MRC: mmap failure.\n");
+ return NULL;
+ }
+
+ if (mrc_data_valid(&md, data, region_device_size) < 0)
+ return NULL;
+
+ return data;
+}
+
static bool mrc_cache_needs_update(const struct region_device *rdev,
const struct cbmem_entry *to_be_updated)
{
@@ -392,8 +433,17 @@ static void update_mrc_cache_by_type(int type)
if (backing_rdev == NULL)
return;
- if (mrc_cache_latest(cr->name, backing_rdev, &md, &cache_file,
- &latest_rdev, fail_bad_data) < 0)
+ /* Note that mrc_cache_get_latest_slot_info doesn't check the
+ * validity of the current slot. If the slot is invalid,
+ * we'll overwrite it anyway when we update the mrc_cache.
+ */
+ if (mrc_cache_get_latest_slot_info(cr->name,
+ backing_rdev,
+ &md,
+ &cache_file,
+ &latest_rdev,
+ fail_bad_data) < 0)
+
return;
if (!mrc_cache_needs_update(&latest_rdev, to_be_updated)) {