From ce1db1f54a1f65834dbbf42d90681718b069f573 Mon Sep 17 00:00:00 2001 From: Sean Rhodes Date: Fri, 13 Feb 2026 20:58:00 +0000 Subject: [PATCH] cpu/x86/smm: reserve SMRAM for OPAL S3 state Reserve a small persistent SMRAM subregion for OPAL S3 unlock state, so the payload-provided OPAL secret can survive SMM handler reload on S3 resume. Expose the region base/size to SMM via smm_runtime and provide an accessor for SMM code. Clear the region on cold boot/reboot, but preserve it when waking from S3. TEST=tested with rest of patch train Change-Id: Ib1e92edb31c845367afe6185e5fa18ab1bc71108 Signed-off-by: Sean Rhodes Reviewed-on: https://review.coreboot.org/c/coreboot/+/91414 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons --- src/cpu/x86/Kconfig | 15 +++++++++++++++ src/cpu/x86/smm/smm_module_handler.c | 8 ++++++++ src/cpu/x86/smm/smm_module_loader.c | 18 ++++++++++++++++++ src/cpu/x86/smm/tseg_region.c | 13 ++++++++++++- src/include/cpu/x86/smm.h | 9 +++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig index c049d4b124..5f6bf7bd18 100644 --- a/src/cpu/x86/Kconfig +++ b/src/cpu/x86/Kconfig @@ -196,6 +196,21 @@ config SMM_MODULE_STACK_SIZE This option determines the size of the stack within the SMM handler modules. +config SMM_OPAL_S3_STATE_SMRAM + bool + help + Reserve a small persistent region in SMRAM for OPAL S3 state so the + OPAL secret survives SMM handler reload on S3 resume. + +config SMM_OPAL_S3_STATE_SMRAM_SIZE + hex + default 0x1000 if SMM_OPAL_S3_STATE_SMRAM + default 0x0 + help + Size in bytes of the persistent SMRAM region reserved for OPAL S3 + secret/state. Must be large enough to store the OPAL S3 state + structure and should be kept minimal to reduce SMRAM pressure. + config SMM_OPAL_S3_SCRATCH_CBMEM bool depends on HAVE_ACPI_RESUME diff --git a/src/cpu/x86/smm/smm_module_handler.c b/src/cpu/x86/smm/smm_module_handler.c index 3f14d970d8..36b68f6ba5 100644 --- a/src/cpu/x86/smm/smm_module_handler.c +++ b/src/cpu/x86/smm/smm_module_handler.c @@ -74,6 +74,14 @@ void smm_get_opal_s3_scratch_buffer(uintptr_t *base, size_t *size) } #endif +#if CONFIG(SMM_OPAL_S3_STATE_SMRAM) +void smm_get_opal_s3_state_buffer(uintptr_t *base, size_t *size) +{ + *base = smm_runtime.opal_s3_state_base; + *size = smm_runtime.opal_s3_state_size; +} +#endif + void smm_get_cbmemc_buffer(void **buffer_out, size_t *size_out) { *buffer_out = smm_runtime.cbmemc; diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c index 4946fe5a0f..8476245b3c 100644 --- a/src/cpu/x86/smm/smm_module_loader.c +++ b/src/cpu/x86/smm/smm_module_loader.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include #include #include #include @@ -386,6 +387,23 @@ static void setup_smihandler_params(struct smm_runtime *mod_params, mod_params->opal_s3_scratch_size = opal_s3_scratch_size; } #endif + +#if CONFIG(SMM_OPAL_S3_STATE_SMRAM) + uintptr_t state_base = 0; + size_t state_size = 0; + if (smm_subregion(SMM_SUBREGION_OPAL_S3_STATE, &state_base, &state_size)) { + printk(BIOS_ERR, "SMM: Failed to locate OPAL S3 state SMRAM region\n"); + mod_params->opal_s3_state_base = 0; + mod_params->opal_s3_state_size = 0; + } else { + mod_params->opal_s3_state_base = state_base; + mod_params->opal_s3_state_size = state_size; + + /* Clear any stale state on cold boot/reboot, but preserve it on S3 resume. */ + if (!acpi_is_wakeup_s3()) + memset((void *)state_base, 0, state_size); + } +#endif } static void print_region(const char *name, const struct region region) diff --git a/src/cpu/x86/smm/tseg_region.c b/src/cpu/x86/smm/tseg_region.c index 90e61dc426..d02f9d8e08 100644 --- a/src/cpu/x86/smm/tseg_region.c +++ b/src/cpu/x86/smm/tseg_region.c @@ -15,6 +15,8 @@ * +-------------------------+ * | External Stage Cache | SMM_RESERVED_SIZE * +-------------------------+ + * | OPAL S3 State (opt) | SMM_OPAL_S3_STATE_SMRAM_SIZE + * +-------------------------+ * | code and data | * | (TSEG) | * +-------------------------+ TSEG @@ -25,6 +27,7 @@ int smm_subregion(int sub, uintptr_t *start, size_t *size) size_t sub_size; const size_t ied_size = CONFIG_IED_REGION_SIZE; const size_t cache_size = CONFIG_SMM_RESERVED_SIZE; + const size_t opal_state_size = CONFIG_SMM_OPAL_S3_STATE_SMRAM_SIZE; if (CONFIG(SMM_TSEG)) smm_region(&sub_base, &sub_size); @@ -34,13 +37,21 @@ int smm_subregion(int sub, uintptr_t *start, size_t *size) return -1; ASSERT(IS_ALIGNED(sub_base, sub_size)); - ASSERT(sub_size > (cache_size + ied_size)); + ASSERT(sub_size > (cache_size + ied_size + opal_state_size)); switch (sub) { case SMM_SUBREGION_HANDLER: /* Handler starts at the base of TSEG. */ sub_size -= ied_size; sub_size -= cache_size; + sub_size -= opal_state_size; + break; + case SMM_SUBREGION_OPAL_S3_STATE: + if (!opal_state_size) + return -1; + /* Persistent OPAL S3 state lives below the external stage cache. */ + sub_base += sub_size - (ied_size + cache_size + opal_state_size); + sub_size = opal_state_size; break; case SMM_SUBREGION_CACHE: /* External cache is in the middle of TSEG. */ diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index 913bd37205..26fc1d4abb 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -100,6 +100,10 @@ struct smm_runtime { uintptr_t opal_s3_scratch_base; size_t opal_s3_scratch_size; #endif +#if CONFIG(SMM_OPAL_S3_STATE_SMRAM) + uintptr_t opal_s3_state_base; + size_t opal_s3_state_size; +#endif } __packed; struct smm_module_params { @@ -206,6 +210,8 @@ static inline void aseg_region(uintptr_t *start, size_t *size) enum { /* SMM handler area. */ SMM_SUBREGION_HANDLER, + /* Persistent OPAL S3 state area. */ + SMM_SUBREGION_OPAL_S3_STATE, /* SMM cache region. */ SMM_SUBREGION_CACHE, /* Chipset specific area. */ @@ -245,5 +251,8 @@ void smm_get_smmstore_com_buffer(uintptr_t *base, size_t *size); #if CONFIG(SMM_OPAL_S3_SCRATCH_CBMEM) void smm_get_opal_s3_scratch_buffer(uintptr_t *base, size_t *size); #endif +#if CONFIG(SMM_OPAL_S3_STATE_SMRAM) +void smm_get_opal_s3_state_buffer(uintptr_t *base, size_t *size); +#endif #endif /* CPU_X86_SMM_H */