cpu/x86/smm: add OPAL S3 CBMEM scratch

Provide an optional, coreboot-managed CBMEM scratch buffer for SMM code.

CBMEM is reserved from the OS via the memory map and persists across S3,
so it is suitable for firmware-owned DMA buffers used during resume.
SMRAM is not device DMA-accessible, so this scratch buffer must live
outside SMRAM.

Pass the base/size to SMM via smm_runtime so SMM code can validate
placement and avoid relying on untrusted pointers.

The CBMEM region size is configurable via SMM_OPAL_S3_SCRATCH_SIZE,
defaulting to 16 KiB as a safe value.

TEST=tested with rest of patch train

Change-Id: I79ae5327f27e574b151b7cf456761fa0d7038f2f
Signed-off-by: Sean Rhodes <sean@starlabs.systems>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/91042
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Rudolph <patrick.rudolph@9elements.com>
This commit is contained in:
Sean Rhodes 2026-02-01 21:11:34 +00:00 committed by Matt DeVillier
commit deb510afeb
5 changed files with 55 additions and 0 deletions

View file

@ -7,6 +7,7 @@
#define CBMEM_ID_ACPI_BERT 0x42455254
#define CBMEM_ID_ACPI_CNVS 0x434e5653
#define CBMEM_ID_ACPI_GNVS 0x474e5653
#define CBMEM_ID_OPAL_S3_SCRATCH 0x3353504f /* 'OPS3' */
#define CBMEM_ID_ACPI_HEST 0x48455354
#define CBMEM_ID_ACPI_UCSI 0x55435349
#define CBMEM_ID_AFTER_CAR 0xc4787a93
@ -100,6 +101,7 @@
{ CBMEM_ID_ACPI_BERT, "ACPI BERT " }, \
{ CBMEM_ID_ACPI_CNVS, "CHROMEOS NVS" }, \
{ CBMEM_ID_ACPI_GNVS, "ACPI GNVS " }, \
{ CBMEM_ID_OPAL_S3_SCRATCH, "OPAL S3 SCR" }, \
{ CBMEM_ID_ACPI_HEST, "ACPI HEST " }, \
{ CBMEM_ID_ACPI_UCSI, "ACPI UCSI " }, \
{ CBMEM_ID_AGESA_RUNTIME, "AGESA RSVD " }, \

View file

@ -196,6 +196,24 @@ config SMM_MODULE_STACK_SIZE
This option determines the size of the stack within the SMM handler
modules.
config SMM_OPAL_S3_SCRATCH_CBMEM
bool
depends on HAVE_ACPI_RESUME
default n
help
Allocate a coreboot-managed CBMEM region that can be used as a
persistent (across S3) scratch buffer by SMM code performing OPAL/NVMe
unlock on resume. The region is in CBMEM and therefore reserved from
the OS via the memory map.
config SMM_OPAL_S3_SCRATCH_SIZE
hex "OPAL S3 scratch size (bytes)"
depends on SMM_OPAL_S3_SCRATCH_CBMEM
default 0x4000
help
Size of the CBMEM scratch buffer provided to the OPAL S3 unlock SMM
handler. This buffer must be DMA-safe and persistent across S3.
endif
config SMM_LAPIC_REMAP_MITIGATION

View file

@ -66,6 +66,14 @@ void smm_get_smmstore_com_buffer(uintptr_t *base, size_t *size)
*size = smm_runtime.smmstore_com_buffer_size;
}
#if CONFIG(SMM_OPAL_S3_SCRATCH_CBMEM)
void smm_get_opal_s3_scratch_buffer(uintptr_t *base, size_t *size)
{
*base = smm_runtime.opal_s3_scratch_base;
*size = smm_runtime.opal_s3_scratch_size;
}
#endif
void smm_get_cbmemc_buffer(void **buffer_out, size_t *size_out)
{
*buffer_out = smm_runtime.cbmemc;

View file

@ -366,6 +366,26 @@ static void setup_smihandler_params(struct smm_runtime *mod_params,
mod_params->smmstore_com_buffer_base = (uintptr_t)ptr;
mod_params->smmstore_com_buffer_size = info.block_size;
}
#if CONFIG(SMM_OPAL_S3_SCRATCH_CBMEM)
/*
* Provide a small, coreboot-managed CBMEM scratch region for SMM code.
* CBMEM is reserved in the memory map, and persists across S3, making
* it suitable for firmware-owned DMA buffers on resume. SMRAM is not
* accessible to devices for DMA, so this scratch buffer must live
* outside SMRAM.
*/
const size_t opal_s3_scratch_size = CONFIG_SMM_OPAL_S3_SCRATCH_SIZE;
void *scratch = cbmem_add(CBMEM_ID_OPAL_S3_SCRATCH, opal_s3_scratch_size);
if (!scratch) {
printk(BIOS_ERR, "SMM: Failed to allocate OPAL S3 scratch\n");
mod_params->opal_s3_scratch_base = 0;
mod_params->opal_s3_scratch_size = 0;
} else {
mod_params->opal_s3_scratch_base = (uintptr_t)scratch;
mod_params->opal_s3_scratch_size = opal_s3_scratch_size;
}
#endif
}
static void print_region(const char *name, const struct region region)

View file

@ -96,6 +96,10 @@ struct smm_runtime {
int smm_log_level;
uintptr_t smmstore_com_buffer_base;
size_t smmstore_com_buffer_size;
#if CONFIG(SMM_OPAL_S3_SCRATCH_CBMEM)
uintptr_t opal_s3_scratch_base;
size_t opal_s3_scratch_size;
#endif
} __packed;
struct smm_module_params {
@ -238,5 +242,8 @@ bool smm_pci_resource_store_fill_resources(struct smm_pci_resource_info *slots,
void smm_pci_resource_store_init(struct smm_runtime *smm_runtime);
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
#endif /* CPU_X86_SMM_H */