aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/x86
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/x86')
-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);
+}