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>
This commit is contained in:
Arthur Heymans 2020-08-09 21:33:19 +02:00 committed by Patrick Georgi
parent 7ac4722a35
commit 3967cf931b
3 changed files with 113 additions and 0 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __CPU_X86_SAVE_STATE_H__
#define __CPU_X86_SAVE_STATE_H__
#include <stdint.h>
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);
};
/* Return -1 on failure, otherwise returns which CPU node issued an APMC IO write */
int get_apmc_node(u8 cmd);
/* Return -1 on failure, 0 on succes.
Accessors for the SMM save state CPU registers RAX, RBX, RCX and RDX */
int get_save_state_reg(const enum cpu_reg reg, const int node, void *out, const uint8_t length);
int set_save_state_reg(const enum cpu_reg reg, const int node, void *in, const uint8_t length);
#endif /* __CPU_X86_SAVE_STATE_H__ */