aboutsummaryrefslogtreecommitdiff
path: root/src/drivers/smmstore/ramstage.c
diff options
context:
space:
mode:
authorPatrick Rudolph <patrick.rudolph@9elements.com>2020-04-17 16:16:49 +0200
committerMichał Żygowski <michal.zygowski@3mdeb.com>2020-10-22 12:29:47 +0000
commitbc744f5893fc4d53275ed26dd8d968011c6a09c1 (patch)
treefb283c9d57431020405a5404db04b425428f7709 /src/drivers/smmstore/ramstage.c
parenta693fa06cd32da8239f820d833bb7a1bf55bf351 (diff)
drivers/smmstore: Implement SMMSTORE version 2
SMMSTORE version 2 is a complete redesign of the current driver. It is not backwards-compatible with version 1, and only one version can be used at a time. Key features: * Uses a fixed communication buffer instead of writing to arbitrary memory addresses provided by untrusted ring0 code. * Gives the caller full control over the used data format. * Splits the store into smaller chunks to allow fault tolerant updates. * Doesn't provide feedback about the actual read/written bytes, just returns error or success in registers. * Returns an error if the requested operation would overflow the communication buffer. Separate the SMMSTORE into 64 KiB blocks that can individually be read/written/erased. To be used by payloads that implement a FaultTolerant Variable store like TianoCore. The implementation has been tested against EDK2 master. An example EDK2 implementation can be found here: https://github.com/9elements/edk2-1/commit/eb1127744a3a5d5c8ac4e8eb76f07e79c736dbe2 Change-Id: I25e49d184135710f3e6dd1ad3bed95de950fe057 Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Signed-off-by: Christian Walter <christian.walter@9elements.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/40520 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Michał Żygowski <michal.zygowski@3mdeb.com> Reviewed-by: Matt DeVillier <matt.devillier@gmail.com>
Diffstat (limited to 'src/drivers/smmstore/ramstage.c')
-rw-r--r--src/drivers/smmstore/ramstage.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/drivers/smmstore/ramstage.c b/src/drivers/smmstore/ramstage.c
new file mode 100644
index 0000000000..ef80e221bc
--- /dev/null
+++ b/src/drivers/smmstore/ramstage.c
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <bootstate.h>
+#include <cpu/x86/smm.h>
+#include <commonlib/helpers.h>
+#include <commonlib/region.h>
+#include <console/console.h>
+#include <smmstore.h>
+#include <types.h>
+#include <cbmem.h>
+
+static struct smmstore_params_info info;
+
+void lb_smmstorev2(struct lb_header *header)
+{
+ struct lb_record *rec;
+ struct lb_smmstorev2 *store;
+ const struct cbmem_entry *e;
+
+ e = cbmem_entry_find(CBMEM_ID_SMM_COMBUFFER);
+ if (!e)
+ return;
+
+ rec = lb_new_record(header);
+ store = (struct lb_smmstorev2 *)rec;
+
+ store->tag = LB_TAG_SMMSTOREV2;
+ store->size = sizeof(*store);
+ store->com_buffer = (uintptr_t)cbmem_entry_start(e);
+ store->com_buffer_size = cbmem_entry_size(e);
+ store->mmap_addr = info.mmap_addr;
+ store->num_blocks = info.num_blocks;
+ store->block_size = info.block_size;
+ store->apm_cmd = APM_CNT_SMMSTORE;
+}
+
+static void init_store(void *unused)
+{
+ struct smmstore_params_init args;
+ uint32_t eax = ~0;
+ uint32_t ebx;
+
+ if (smmstore_get_info(&info) < 0) {
+ printk(BIOS_INFO, "SMMSTORE: Failed to get meta data\n");
+ return;
+ }
+
+ void *ptr = cbmem_add(CBMEM_ID_SMM_COMBUFFER, info.block_size);
+ if (!ptr) {
+ printk(BIOS_ERR, "SMMSTORE: Failed to add com buffer\n");
+ return;
+ }
+
+ args.com_buffer = (uintptr_t)ptr;
+ args.com_buffer_size = info.block_size;
+ ebx = (uintptr_t)&args;
+
+ printk(BIOS_INFO, "SMMSTORE: Setting up SMI handler\n");
+
+ /* Issue SMI using APM to update the com buffer and to lock the SMMSTORE */
+ __asm__ __volatile__ (
+ "outb %%al, %%dx"
+ : "=a" (eax)
+ : "a" ((SMMSTORE_CMD_INIT << 8) | APM_CNT_SMMSTORE),
+ "b" (ebx),
+ "d" (APM_CNT)
+ : "memory");
+
+ if (eax != SMMSTORE_RET_SUCCESS) {
+ printk(BIOS_ERR, "SMMSTORE: Failed to install com buffer\n");
+ return;
+ }
+}
+
+/* The SMI APM handler is installed at DEV_INIT phase */
+BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, init_store, NULL);