Arthur Heymans has uploaded this change for review.

View Change

[WIP] SMM save states

Change-Id: I4a31d05c09065543424a9010ac434dde0dfb5836
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
---
M src/cpu/intel/smm/Makefile.inc
A src/cpu/intel/smm/em64t101_save_state.c
M src/cpu/x86/smm/Makefile.inc
A src/cpu/x86/smm/save_state.c
M src/cpu/x86/smm/smm.ld
A src/include/cpu/x86/save_state.h
M src/lib/program.ld
M src/southbridge/intel/i82801ix/smihandler.c
8 files changed, 210 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/23/44323/1
diff --git a/src/cpu/intel/smm/Makefile.inc b/src/cpu/intel/smm/Makefile.inc
index a49b796..df73ae7 100644
--- a/src/cpu/intel/smm/Makefile.inc
+++ b/src/cpu/intel/smm/Makefile.inc
@@ -1 +1,2 @@
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smm_reloc.c
+smm-y += em64t101_save_state.c
diff --git a/src/cpu/intel/smm/em64t101_save_state.c b/src/cpu/intel/smm/em64t101_save_state.c
new file mode 100644
index 0000000..404906b
--- /dev/null
+++ b/src/cpu/intel/smm/em64t101_save_state.c
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <string.h>
+#include <cpu/x86/save_state.h>
+#include <cpu/intel/em64t101_save_state.h>
+
+static void *em64t101_get_reg_base(const enum cpu_reg reg, const int node)
+{
+ const em64t101_smm_state_save_area_t *save_state = (const em64t101_smm_state_save_area_t *)smm_get_save_state(node);
+
+ switch (reg) {
+ case RAX:
+ return (void *)&save_state->rax;
+ case RBX:
+ return (void *)&save_state->rbx;
+ case RCX:
+ return (void *)&save_state->rcx;
+ case RDX:
+ return (void *)&save_state->rdx;
+ }
+
+ return NULL;
+}
+
+enum get_set {
+ GET,
+ SET
+};
+
+static int em64t101_get_set(const enum get_set op_type, const enum cpu_reg reg,
+ const int node, void *in_out, const uint8_t length)
+{
+
+ void *reg_base = em64t101_get_reg_base(reg, node);
+
+ if (!reg_base)
+ return -1;
+
+ switch (length) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ switch (op_type) {
+ case GET:
+ memcpy(in_out, reg_base, length);
+ return 0;
+ case SET:
+ memcpy(reg_base, in_out, length);
+ }
+ }
+
+ return -1;
+}
+
+static int em64t101_get_reg(const enum cpu_reg reg, const int node, void *out, const uint8_t length)
+{
+ return em64t101_get_set(GET, reg, node, out, length);
+}
+
+static int em64t101_set_reg(const enum cpu_reg reg, const int node, void *in, const uint8_t length)
+{
+ return em64t101_get_set(SET, reg, node, in, length);
+}
+
+static int em64t101_apmc_node(u8 cmd)
+{
+ em64t101_smm_state_save_area_t *state;
+ int node;
+
+ for (node = 0; node < CONFIG_MAX_CPUS; node++) {
+ state = smm_get_save_state(node);
+
+ /* Check for Synchronous IO (bit0 == 1) */
+ if (!(state->io_misc_info & (1 << 0)))
+ continue;
+
+ /* Make sure it was a write (bit4 == 0) */
+ if (state->io_misc_info & (1 << 4))
+ continue;
+
+ /* Check for APMC IO port */
+ if (((state->io_misc_info >> 16) & 0xff) != APM_CNT)
+ continue;
+
+ /* Check AX against the requested command */
+ if ((state->rax & 0xff) != cmd)
+ continue;
+
+ return node;
+ }
+
+ return -1;
+}
+
+static const uint32_t revisions[] = {
+ 0x00030101,
+ SMM_REV_INVALID,
+};
+
+static const struct smm_save_state_ops ops __smm_save_state_ops = {
+ .revision_table = revisions,
+ .get_reg = em64t101_get_reg,
+ .set_reg = em64t101_set_reg,
+ .apmc_node = em64t101_apmc_node,
+};
diff --git a/src/cpu/x86/smm/Makefile.inc b/src/cpu/x86/smm/Makefile.inc
index bbd96c6..2b3e073 100644
--- a/src/cpu/x86/smm/Makefile.inc
+++ b/src/cpu/x86/smm/Makefile.inc
@@ -28,6 +28,8 @@
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 0000000..7c757e3
--- /dev/null
+++ b/src/cpu/x86/smm/save_state.c
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <cpu/x86/smm.h>
+#include <cpu/x86/save_state.h>
+
+static 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();
+ struct smm_save_state_ops *ops;
+ static bool initialized = false;
+
+ if (initialized)
+ return 0;
+
+ for (ops = _smm_save_state_ops; ops < _esmm_save_state_ops; ops++) {
+ const uint32_t *rev;
+ 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;
+
+ return save_state->get_reg(reg, node, out, length);
+}
diff --git a/src/cpu/x86/smm/smm.ld b/src/cpu/x86/smm/smm.ld
index 2f46975..39afee4 100644
--- a/src/cpu/x86/smm/smm.ld
+++ b/src/cpu/x86/smm/smm.ld
@@ -25,6 +25,11 @@

/* C read-only data of the SMM handler */
. = ALIGN(16);
+
+ _smm_save_state_ops = .;
+ KEEP(*(.rodata.smm_ops));
+ _esmm_save_state_ops = .;
+
*(.rodata)
*(.rodata.*)

diff --git a/src/include/cpu/x86/save_state.h b/src/include/cpu/x86/save_state.h
new file mode 100644
index 0000000..b97890b
--- /dev/null
+++ b/src/include/cpu/x86/save_state.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __CPU_X86_SAVE_STATE_H__
+#define __CPU_X86_SAVE_STATE_H__
+
+#include <stdint.h>
+
+#if ENV_SMM
+#define __smm_save_state_ops __attribute__((used, __section__(".rodata.smm_ops")))
+#else
+#define __smm_save_state_ops __attribute__((unused))
+#endif
+
+enum cpu_reg {
+ RAX,
+ RBX,
+ RCX,
+ RDX
+};
+
+#define SMM_REV_INVALID 0xffffffff
+
+struct smm_save_state_ops {
+ const uint32_t *revision_table;
+ /* Accessors for CPU registers in the SMM save state
+ Returns -1 on failure, 0 on success */
+ int (*get_reg)(const enum cpu_reg reg, const int node, void *out, const uint8_t length);
+ int(*set_reg)(const enum cpu_reg reg, const int node, void *in, const uint8_t length);
+ /* Returns -1 on failure, the node on which the 'cmd' was send on success */
+ int(*apmc_node)(u8 cmd);
+};
+
+/** start of compile time generated pci driver array */
+extern struct smm_save_state_ops _smm_save_state_ops[];
+/** end of compile time generated pci driver array */
+extern struct smm_save_state_ops _esmm_save_state_ops[];
+
+int get_apmc_node(u8 cmd);
+int get_save_state_reg(const enum cpu_reg reg, const int node, void *out, const uint8_t length);
+
+#endif /* __CPU_X86_SAVE_STATE_H__ */
diff --git a/src/lib/program.ld b/src/lib/program.ld
index 88a3126..1894ae0 100644
--- a/src/lib/program.ld
+++ b/src/lib/program.ld
@@ -44,6 +44,13 @@
_ecpu_drivers = .;
#endif

+#if ENV_SMM || ENV_RMODULE
+ . = ALIGN(ARCH_POINTER_ALIGN_SIZE);
+ _smm_save_state_ops = .;
+ KEEP(*(.rodata.smm_ops));
+ _esmm_save_state_ops = .;
+#endif
+
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
*(.rodata);
*(.rodata.*);
diff --git a/src/southbridge/intel/i82801ix/smihandler.c b/src/southbridge/intel/i82801ix/smihandler.c
index 699f51f..9b37f05 100644
--- a/src/southbridge/intel/i82801ix/smihandler.c
+++ b/src/southbridge/intel/i82801ix/smihandler.c
@@ -3,6 +3,7 @@
#include <types.h>
#include <console/console.h>
#include <cpu/x86/smm.h>
+#include <cpu/x86/save_state.h>
#include <device/pci_def.h>
#include <southbridge/intel/common/pmutil.h>
#include "i82801ix.h"
@@ -31,6 +32,8 @@
return 1; /* IO trap handled */
}

+ get_apmc_node(5);
+
/* Not handled */
return 0;
}

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

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I4a31d05c09065543424a9010ac434dde0dfb5836
Gerrit-Change-Number: 44323
Gerrit-PatchSet: 1
Gerrit-Owner: Arthur Heymans <arthur@aheymans.xyz>
Gerrit-Reviewer: Julius Werner <jwerner@chromium.org>
Gerrit-Reviewer: Martin Roth <martinroth@google.com>
Gerrit-Reviewer: Patrick Georgi <pgeorgi@google.com>
Gerrit-Reviewer: Patrick Rudolph <siro@das-labor.org>
Gerrit-MessageType: newchange