summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Rudolph <patrick.rudolph@9elements.com>2019-09-12 13:21:37 +0200
committerPhilipp Deppenwiese <zaolin.daisuki@gmail.com>2019-09-23 08:46:13 +0000
commit6d787c2590920fc5ea222d692004818bbed6b3e5 (patch)
treecf1add7b3dd4564134f122465e30432aab6eec35
parentafa6a2de4848ad8661b041c3b5e6de8da2ee0abc (diff)
lib/fmap: Cache FMAP in cbmem
For platform independend exposure of FMAP through a kernel module cache the FMAP in CBMEM. In addition add a pointer in coreboot tables pointing to the introduced CBMEM area. To not waste the allocated DRAM, use the cached CBMEM in RAM enabled stages if possible. Tested on qemu using https://github.com/9elements/linux/commits/google_firmware_fmap2 Tested on QEMU and Supermicro X11SSH-TF. Change-Id: I4e01c573c3edfa34dbba5fe7604d4f6e18b584d5 Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/35377 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-by: Julius Werner <jwerner@chromium.org>
-rw-r--r--src/commonlib/include/commonlib/cbmem_id.h4
-rw-r--r--src/commonlib/include/commonlib/coreboot_tables.h1
-rw-r--r--src/lib/coreboot_table.c3
-rw-r--r--src/lib/fmap.c62
4 files changed, 68 insertions, 2 deletions
diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h
index 8d0ca465ae..30bf88ada8 100644
--- a/src/commonlib/include/commonlib/cbmem_id.h
+++ b/src/commonlib/include/commonlib/cbmem_id.h
@@ -76,6 +76,7 @@
#define CBMEM_ID_ROM1 0x524f4d31
#define CBMEM_ID_ROM2 0x524f4d32
#define CBMEM_ID_ROM3 0x524f4d33
+#define CBMEM_ID_FMAP 0x464d4150
#define CBMEM_ID_TO_NAME_TABLE \
{ CBMEM_ID_ACPI, "ACPI " }, \
@@ -134,5 +135,6 @@
{ CBMEM_ID_ROM0, "VGA ROM #0 "}, \
{ CBMEM_ID_ROM1, "VGA ROM #1 "}, \
{ CBMEM_ID_ROM2, "VGA ROM #2 "}, \
- { CBMEM_ID_ROM3, "VGA ROM #3 "},
+ { CBMEM_ID_ROM3, "VGA ROM #3 "}, \
+ { CBMEM_ID_FMAP, "FMAP "},
#endif /* _CBMEM_ID_H_ */
diff --git a/src/commonlib/include/commonlib/coreboot_tables.h b/src/commonlib/include/commonlib/coreboot_tables.h
index 7bded2a3a3..68166701b0 100644
--- a/src/commonlib/include/commonlib/coreboot_tables.h
+++ b/src/commonlib/include/commonlib/coreboot_tables.h
@@ -89,6 +89,7 @@ enum {
LB_TAG_VBOOT_WORKBUF = 0x0034,
LB_TAG_MMC_INFO = 0x0035,
LB_TAG_TCPA_LOG = 0x0036,
+ LB_TAG_FMAP = 0x0037,
LB_TAG_CMOS_OPTION_TABLE = 0x00c8,
LB_TAG_OPTION = 0x00c9,
LB_TAG_OPTION_ENUM = 0x00ca,
diff --git a/src/lib/coreboot_table.c b/src/lib/coreboot_table.c
index 66afcf353b..9c5942fa9d 100644
--- a/src/lib/coreboot_table.c
+++ b/src/lib/coreboot_table.c
@@ -345,7 +345,8 @@ static void add_cbmem_pointers(struct lb_header *header)
{CBMEM_ID_ACPI_GNVS, LB_TAG_ACPI_GNVS},
{CBMEM_ID_VPD, LB_TAG_VPD},
{CBMEM_ID_WIFI_CALIBRATION, LB_TAG_WIFI_CALIBRATION},
- {CBMEM_ID_TCPA_LOG, LB_TAG_TCPA_LOG}
+ {CBMEM_ID_TCPA_LOG, LB_TAG_TCPA_LOG},
+ {CBMEM_ID_FMAP, LB_TAG_FMAP},
};
int i;
diff --git a/src/lib/fmap.c b/src/lib/fmap.c
index 2b4e3bae2c..f0074186da 100644
--- a/src/lib/fmap.c
+++ b/src/lib/fmap.c
@@ -20,6 +20,7 @@
#include <commonlib/fmap_serialized.h>
#include <stddef.h>
#include <string.h>
+#include <cbmem.h>
#include "fmap_config.h"
@@ -28,6 +29,7 @@
*/
static int fmap_print_once CAR_GLOBAL;
+static struct mem_region_device fmap_cache CAR_GLOBAL;
int find_fmap_directory(struct region_device *fmrd)
{
@@ -36,6 +38,16 @@ int find_fmap_directory(struct region_device *fmrd)
size_t fmap_size;
size_t offset = FMAP_OFFSET;
+ if (cbmem_possibly_online() && !ENV_SMM) {
+ /* Try FMAP cache first */
+ const struct mem_region_device *cache;
+
+ cache = car_get_var_ptr(&fmap_cache);
+ if (region_device_sz(&cache->rdev))
+ return rdev_chain(fmrd, &cache->rdev, 0,
+ region_device_sz(&cache->rdev));
+ }
+
boot_device_init();
boot = boot_device_ro();
@@ -195,3 +207,53 @@ ssize_t fmap_overwrite_area(const char *name, const void *buffer, size_t size)
return -1;
return rdev_writeat(&rdev, buffer, 0, size);
}
+
+static void fmap_register_cache(int unused)
+{
+ const struct cbmem_entry *e;
+ struct mem_region_device *mdev;
+
+ mdev = car_get_var_ptr(&fmap_cache);
+
+ /* Find the FMAP cache installed by previous stage */
+ e = cbmem_entry_find(CBMEM_ID_FMAP);
+ /* Don't set fmap_cache so that find_fmap_directory will use regular path */
+ if (!e)
+ return;
+
+ mem_region_device_ro_init(mdev, cbmem_entry_start(e), cbmem_entry_size(e));
+}
+
+/*
+ * The main reason to copy the FMAP into CBMEM is to make it available to the
+ * OS on every architecture. As side effect use the CBMEM copy as cache.
+ */
+static void fmap_setup_cache(int unused)
+{
+ struct region_device fmrd;
+
+ if (find_fmap_directory(&fmrd))
+ return;
+
+ /* Reloads the FMAP even on ACPI S3 resume */
+ const size_t s = region_device_sz(&fmrd);
+ struct fmap *fmap = cbmem_add(CBMEM_ID_FMAP, s);
+ if (!fmap) {
+ printk(BIOS_ERR, "ERROR: Failed to allocate CBMEM\n");
+ return;
+ }
+
+ const ssize_t ret = rdev_readat(&fmrd, fmap, 0, s);
+ if (ret != s) {
+ printk(BIOS_ERR, "ERROR: Failed to read FMAP into CBMEM\n");
+ cbmem_entry_remove(cbmem_entry_find(CBMEM_ID_FMAP));
+ return;
+ }
+
+ /* Finally advertise the cache for the current stage */
+ fmap_register_cache(unused);
+}
+
+ROMSTAGE_CBMEM_INIT_HOOK(fmap_setup_cache)
+RAMSTAGE_CBMEM_INIT_HOOK(fmap_register_cache)
+POSTCAR_CBMEM_INIT_HOOK(fmap_register_cache)