Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/36661 )
Change subject: [RFC]cpu/x86/smm: Add a unified way of handling save_states ......................................................................
[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 */