summaryrefslogtreecommitdiffstats
path: root/src/drivers/mrc_cache/mrc_cache.c
diff options
context:
space:
mode:
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 d567a20f11c8..1b1ad6332ff3 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)) {