Arthur Heymans has uploaded this change for review.

View Change

[RFC]cpu/x86/smm: Add a unified way of handling save_states

This adds common code to handle SMM save states based on the SMM
revision.

example:
SMM code needing access to eax from save state would do the following

struct smm_save_state_ops ops = get_save_state_ops();
uint64_t rax;
int node;

for (node = 0; node < CONFIG_MAX_CPUS; node++) {
if (ops.get_reg(node, RAX, &rax))
error...
rax &= MAX_UINT32;
do_stuff...
}

UNTESTED.

Change-Id: Ide7ccc44dbcc864e70463ef318dc1858b51183dc
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
---
M src/cpu/x86/smm/Makefile.inc
A src/cpu/x86/smm/smm_save_state.c
M src/include/cpu/x86/smm.h
3 files changed, 311 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/61/36661/1
diff --git a/src/cpu/x86/smm/Makefile.inc b/src/cpu/x86/smm/Makefile.inc
index 11a4e67..6c74c88 100644
--- a/src/cpu/x86/smm/Makefile.inc
+++ b/src/cpu/x86/smm/Makefile.inc
@@ -47,6 +47,7 @@
smmstub-y += smm_stub.S

smm-y += smm_module_handler.c
+smm-y += smm_save_state.c

ramstage-srcs += $(obj)/cpu/x86/smm/smmstub.manual

diff --git a/src/cpu/x86/smm/smm_save_state.c b/src/cpu/x86/smm/smm_save_state.c
new file mode 100644
index 0000000..8a7f347
--- /dev/null
+++ b/src/cpu/x86/smm/smm_save_state.c
@@ -0,0 +1,283 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include <string.h>
+#include <cpu/amd/amd64_save_state.h>
+#include <cpu/intel/em64t100_save_state.h>
+#include <cpu/intel/em64t101_save_state.h>
+#include <cpu/x86/legacy_save_state.h>
+
+static const struct smm_runtime *smm_runtime;
+static const struct smm_save_state_ops *ops;
+
+static void *smm_get_save_state_top(int cpu)
+{
+ char *base;
+
+ /* This function assumes all save states start at top of default
+ * SMRAM size space and are staggered down by save state size. */
+ base = (void *)smm_runtime->smbase;
+ base += SMM_DEFAULT_SIZE;
+ base -= cpu * smm_runtime->save_state_size;
+
+ return base;
+}
+
+static uint32_t smm_get_revision(uint32_t base)
+{
+ uint8_t *top = (uint8_t *)smm_get_save_state_top(0);
+ /* SMM revision offset from top */
+ return *(uint32_t *)(top - (0x8000 - 0x7efc));
+}
+
+const struct smm_save_state_ops *get_save_state_ops(void)
+{
+ return ops;
+}
+
+/* We only have 32bit registers so we'll fake 64bit registers with 0
+ in the upper part. */
+static void *legacy_get_reg_ptr(unsigned int cpu, enum smm_reg reg)
+{
+ uint8_t *base;
+ legacy_smm_state_save_area_t *state;
+ if (cpu > CONFIG_MAX_CPUS)
+ return NULL;
+ base = smm_get_save_state_top(cpu);
+ base -= sizeof(legacy_smm_state_save_area_t);
+ state = (legacy_smm_state_save_area_t *)(base);
+ switch (reg) {
+ case RAX:
+ return &state->eax;
+ case RBX:
+ return &state->ebx;
+ case RCX:
+ return &state->ecx;
+ case RDX:
+ return &state->edx;
+ default:
+ break;
+ }
+ printk(BIOS_DEBUG, "SMM get_reg: Unknown reg requested\n");
+ return NULL;
+}
+
+static void *em64t100_get_reg_ptr(unsigned int cpu, enum smm_reg reg)
+{
+ uint8_t *base;
+ em64t100_smm_state_save_area_t *state;
+ if (cpu > CONFIG_MAX_CPUS)
+ return NULL;;
+ base = smm_get_save_state_top(cpu);
+ base -= sizeof(em64t100_smm_state_save_area_t);
+ state = (em64t100_smm_state_save_area_t *)(base);
+ switch (reg) {
+ case RAX:
+ return &state->rax;
+ case RBX:
+ return &state->rbx;
+ case RCX:
+ return &state->rcx;
+ case RDX:
+ return &state->rdx;
+ case IO_MISC_INFO:
+ return &state->io_misc_info;
+ default:
+ break;
+ }
+ printk(BIOS_DEBUG, "SMM get_reg: Unknown reg requested\n");
+ return NULL;
+}
+
+static void *em64t101_get_reg_ptr(unsigned int cpu, enum smm_reg reg)
+{
+ uint8_t *base;
+ em64t101_smm_state_save_area_t *state;
+ if (cpu > CONFIG_MAX_CPUS)
+ return NULL;
+ base = smm_get_save_state_top(cpu);
+ base -= sizeof(em64t101_smm_state_save_area_t);
+ state = (em64t101_smm_state_save_area_t *)(base);
+ switch (reg) {
+ case RAX:
+ return &state->rax;
+ case RBX:
+ return &state->rbx;
+ case RCX:
+ return &state->rcx;
+ case RDX:
+ return &state->rdx;
+ case IO_MISC_INFO:
+ return &state->io_misc_info;
+ default:
+ break;
+ }
+ printk(BIOS_DEBUG, "SMM get_reg: Unknown reg requested\n");
+ return NULL;
+}
+
+static void *amd64_get_reg_ptr(unsigned int cpu, enum smm_reg reg)
+{
+ uint8_t *base;
+ amd64_smm_state_save_area_t *state;
+ if (cpu > CONFIG_MAX_CPUS)
+ return NULL;
+ base = smm_get_save_state_top(cpu);
+ base -= sizeof(amd64_smm_state_save_area_t);
+ state = (amd64_smm_state_save_area_t *)(base);
+ switch (reg) {
+ case RAX:
+ return &state->rax;
+ case RBX:
+ return &state->rbx;
+ case RCX:
+ return &state->rcx;
+ case RDX:
+ return &state->rdx;
+ case SMM_IO_TRAP_OFFSET:
+ return &state->smm_io_trap_offset;
+ default:
+ break;
+ }
+ printk(BIOS_DEBUG, "SMM get_reg: Unknown reg requested\n");
+ return NULL;
+}
+
+static int ss_get_helper(unsigned int cpu, enum smm_reg reg, void *val, size_t val_size,
+ void *(*get_reg_ptr_fn)(unsigned int, enum smm_reg))
+{
+ void *ss_entry = get_reg_ptr_fn(cpu, reg);
+ if (!ss_entry)
+ return -1;
+ memcpy(val, ss_entry, val_size);
+ return 0;
+}
+
+static int ss_set_helper(unsigned int cpu, enum smm_reg reg, void *val, size_t val_size,
+ void *(*get_reg_ptr_fn)(unsigned int, enum smm_reg))
+{
+ void *ss_entry = get_reg_ptr_fn(cpu, reg);
+ if (!ss_entry)
+ return -1;
+ memcpy(ss_entry, val, val_size);
+ return 0;
+}
+
+static int legacy_get_reg(unsigned int cpu, enum smm_reg reg, uint64_t *val)
+{
+ return ss_get_helper(cpu, reg, val, sizeof(uint32_t), legacy_get_reg_ptr);
+}
+
+static int legacy_set_reg(unsigned int cpu, enum smm_reg reg, uint64_t val)
+{
+ return ss_set_helper(cpu, reg, &val, sizeof(uint32_t), legacy_get_reg_ptr);
+}
+
+static int em64t100_get_io_misc_info(unsigned int cpu, uint32_t *misc_info)
+{
+ return ss_get_helper(cpu, IO_MISC_INFO, misc_info, sizeof(*misc_info), em64t100_get_reg_ptr);
+}
+
+static int em64t100_get_reg(unsigned int cpu, enum smm_reg reg, uint64_t *val)
+{
+ return ss_get_helper(cpu, reg, val, sizeof(*val), em64t100_get_reg_ptr);
+}
+
+static int em64t100_set_reg(unsigned int cpu, enum smm_reg reg, uint64_t val)
+{
+ return ss_set_helper(cpu, reg, &val, sizeof(val), em64t100_get_reg_ptr);
+}
+
+static int em64t101_get_io_misc_info(unsigned int cpu, uint32_t *misc_info)
+{
+ return ss_get_helper(cpu, IO_MISC_INFO, misc_info, sizeof(*misc_info), em64t101_get_reg_ptr);
+}
+
+static int em64t101_get_reg(unsigned int cpu, enum smm_reg reg, uint64_t *val)
+{
+ return ss_get_helper(cpu, reg, val, sizeof(*val), em64t101_get_reg_ptr);
+}
+
+static int em64t101_set_reg(unsigned int cpu, enum smm_reg reg, uint64_t val)
+{
+ return ss_set_helper(cpu, reg, &val, sizeof(val), em64t101_get_reg_ptr);
+}
+
+static int amd64_get_io_trap(unsigned int cpu, uint32_t *io_trap)
+{
+ return ss_get_helper(cpu, SMM_IO_TRAP_OFFSET, io_trap, sizeof(*io_trap), amd64_get_reg_ptr);
+}
+
+static int amd64_get_reg(unsigned int cpu, enum smm_reg reg, uint64_t *val)
+{
+ return ss_get_helper(cpu, reg, val, sizeof(*val), amd64_get_reg_ptr);
+}
+
+static int amd64_set_reg(unsigned int cpu, enum smm_reg reg, uint64_t val)
+{
+ return ss_set_helper(cpu, reg, &val, sizeof(val), amd64_get_reg_ptr);
+}
+
+static const struct smm_save_state_ops legacy_save_state_ops = {
+ .get_reg = legacy_get_reg,
+ .set_reg = legacy_set_reg,
+};
+
+static const struct smm_save_state_ops em64t100_save_state_ops = {
+ .get_io_misc_info = em64t100_get_io_misc_info,
+ .get_reg = em64t100_get_reg,
+ .set_reg = em64t100_set_reg,
+};
+
+static const struct smm_save_state_ops em64t101_save_state_ops = {
+ .get_io_misc_info = em64t101_get_io_misc_info,
+ .get_reg = em64t101_get_reg,
+ .set_reg = em64t101_set_reg,
+};
+
+static const struct smm_save_state_ops amd64_save_state_ops = {
+ .get_io_trap = amd64_get_io_trap,
+ .get_reg = amd64_get_reg,
+ .set_reg = amd64_set_reg,
+};
+
+int smm_save_state_ops_init(const struct smm_runtime *runtime)
+{
+ uint32_t smm_revision = smm_get_revision(runtime->smbase);
+ smm_runtime = runtime;
+
+ switch (smm_revision) {
+ case 0x00030002:
+ case 0x00030007:
+ ops = &legacy_save_state_ops;
+ return 0;
+ break;
+ case 0x00030100:
+ ops = &em64t100_save_state_ops;
+ return 0;
+ break;
+ case 0x00030101: /* SandyBridge, IvyBridge, and Haswell */
+ ops = &em64t101_save_state_ops;
+ return 0;
+ case 0x00020064:
+ case 0x00030064:
+ ops = &amd64_save_state_ops;
+ return 0;
+ default:
+ printk(BIOS_DEBUG, "smm_revision: 0x%08x\n", smm_revision);
+ printk(BIOS_DEBUG, "SMI# not supported on your CPU\n");
+ return 1;
+ }
+}
+
diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h
index d8b9efe..b389e77 100644
--- a/src/include/cpu/x86/smm.h
+++ b/src/include/cpu/x86/smm.h
@@ -95,6 +95,33 @@
/* Retrieve SMM save state for a given CPU. WARNING: This does not take into
* account CPUs which are configured to not save their state to RAM. */
void *smm_get_save_state(int cpu);
+
+enum smm_reg {
+ RAX,
+ RBX,
+ RCX,
+ RDX,
+ IO_MISC_INFO,
+ SMM_IO_TRAP_OFFSET,
+};
+
+/* SMM save state ops.
+ WARNING1: This does not take into account CPUs which are configured to not
+ save their state to RAM. Returns -1 on failure, 0 on succes. */
+struct smm_save_state_ops {
+ /* Intel 64: misc info */
+ int (*get_io_misc_info)(unsigned int cpu, uint32_t *misc_info);
+ /* AMD64: smm_io_trap */
+ int (*get_io_trap)(unsigned int cpu, uint32_t *misc_info);
+ /* return value of the requested register from
+ * SMM Save State Area.
+ */
+ int (*get_reg)(unsigned int cpu, enum smm_reg reg, uint64_t *val);
+ int (*set_reg)(unsigned int cpu, enum smm_reg reg, uint64_t val);
+};
+
+const struct smm_save_state_ops *get_save_state_ops(void);
+int smm_save_state_ops_init(const struct smm_runtime *runtime);
#endif /* __SMM__ */

/* SMM Module Loading API */

To view, visit change 36661. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ide7ccc44dbcc864e70463ef318dc1858b51183dc
Gerrit-Change-Number: 36661
Gerrit-PatchSet: 1
Gerrit-Owner: Arthur Heymans <arthur@aheymans.xyz>
Gerrit-MessageType: newchange