summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorArthur Heymans <arthur@aheymans.xyz>2020-08-09 21:33:19 +0200
committerPatrick Georgi <pgeorgi@google.com>2020-11-09 10:20:07 +0000
commit3967cf931b02414d4b420dcb43b4aeb5ce7d2430 (patch)
treedda5095618a5e9e2b1df562c6bcb0e343518d770 /src/cpu
parent7ac4722a35714bb02286a0ae0b47abaf1a35219d (diff)
cpu/x86/smm: Add a common save state handling
Currently coreboot has limited use for the SMM save state. Typically the only thing needed is to get or set a few registers and to know which CPU triggered the SMI (typically via an IO write). Abstracting away different SMM save states would allow to put some SMM functionality like the SMMSTORE entry in common places. To save place platforms can select different SMM save sate ops that should be implemented. For instance AMD platforms don't need Intel SMM save state handling. Some platforms can encounter CPUs with different save states, which the code then handles at runtime by comparing the SMM save state revision which is located at the same offset for all SMM save state types. Change-Id: I4a31d05c09065543424a9010ac434dde0dfb5836 Signed-off-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-on: https://review.coreboot.org/c/coreboot/+/44323 Reviewed-by: Angel Pons <th3fanbus@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/x86/smm/Makefile.inc2
-rw-r--r--src/cpu/x86/smm/save_state.c77
2 files changed, 79 insertions, 0 deletions
diff --git a/src/cpu/x86/smm/Makefile.inc b/src/cpu/x86/smm/Makefile.inc
index c2f49cf94d..eb386a69e5 100644
--- a/src/cpu/x86/smm/Makefile.inc
+++ b/src/cpu/x86/smm/Makefile.inc
@@ -32,6 +32,8 @@ ifeq ($(CONFIG_HAVE_SMI_HANDLER),y)
ramstage-srcs += $(obj)/cpu/x86/smm/smm.manual
endif
+smm-y += save_state.c
+
ifeq ($(CONFIG_SMM_TSEG),y)
ramstage-y += tseg_region.c
diff --git a/src/cpu/x86/smm/save_state.c b/src/cpu/x86/smm/save_state.c
new file mode 100644
index 0000000000..bb08f86414
--- /dev/null
+++ b/src/cpu/x86/smm/save_state.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <cpu/x86/smm.h>
+#include <cpu/x86/save_state.h>
+
+/* These are weakly linked such that platforms can link only the save state
+ ops they actually require. */
+const struct smm_save_state_ops *legacy_ops __weak = NULL;
+const struct smm_save_state_ops *em64t100_ops __weak = NULL;
+const struct smm_save_state_ops *em64t101_ops __weak = NULL;
+const struct smm_save_state_ops *amd64_ops __weak = NULL;
+
+static const struct smm_save_state_ops *save_state;
+
+/* Returns -1 on failure, 0 on success */
+static int init_save_state(void)
+{
+ const uint32_t revision = smm_revision();
+ int i;
+ static bool initialized = false;
+ const struct smm_save_state_ops *save_state_ops[] = {
+ legacy_ops,
+ em64t100_ops,
+ em64t101_ops,
+ amd64_ops,
+ };
+
+ if (initialized)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(save_state_ops); i++) {
+ const struct smm_save_state_ops *ops = save_state_ops[i];
+ const uint32_t *rev;
+
+ if (ops == NULL)
+ continue;
+
+ for (rev = ops->revision_table; *rev != SMM_REV_INVALID; rev++)
+ if (*rev == revision) {
+ save_state = ops;
+ initialized = true;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int get_apmc_node(u8 cmd)
+{
+ if (init_save_state())
+ return -1;
+
+ return save_state->apmc_node(cmd);
+}
+
+int get_save_state_reg(const enum cpu_reg reg, const int node, void *out, const uint8_t length)
+{
+ if (init_save_state())
+ return -1;
+
+ if (node > CONFIG_MAX_CPUS)
+ return -1;
+
+ return save_state->get_reg(reg, node, out, length);
+}
+
+int set_save_state_reg(const enum cpu_reg reg, const int node, void *in, const uint8_t length)
+{
+ if (init_save_state())
+ return -1;
+
+ if (node > CONFIG_MAX_CPUS)
+ return -1;
+
+ return save_state->set_reg(reg, node, in, length);
+}