diff options
-rw-r--r-- | src/cpu/x86/Kconfig | 13 | ||||
-rw-r--r-- | src/cpu/x86/smm/Makefile.inc | 3 | ||||
-rw-r--r-- | src/cpu/x86/smm/pci_resource_store.c | 73 | ||||
-rw-r--r-- | src/cpu/x86/smm/smm_module_handler.c | 7 | ||||
-rw-r--r-- | src/cpu/x86/smm/smm_module_loader.c | 3 | ||||
-rw-r--r-- | src/include/cpu/x86/smm.h | 26 | ||||
-rw-r--r-- | src/include/device/pci_def.h | 4 |
7 files changed, 129 insertions, 0 deletions
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig index edba27bd40..d95e6cc4c3 100644 --- a/src/cpu/x86/Kconfig +++ b/src/cpu/x86/Kconfig @@ -168,6 +168,19 @@ config SMM_LAPIC_REMAP_MITIGATION || NORTHBRIDGE_INTEL_E7505 || NORTHBRIDGE_INTEL_IRONLAKE default n +config SMM_PCI_RESOURCE_STORE + bool + default n + help + This option enables support for storing PCI resources in SMRAM so + SMM can tell if they've been altered. + +config SMM_PCI_RESOURCE_STORE_NUM_SLOTS + int + default 8 + help + Number of slots available to store PCI BARs in SMRAM + config X86_AMD_FIXED_MTRRS bool default n diff --git a/src/cpu/x86/smm/Makefile.inc b/src/cpu/x86/smm/Makefile.inc index 327b6c6720..dbe9c75262 100644 --- a/src/cpu/x86/smm/Makefile.inc +++ b/src/cpu/x86/smm/Makefile.inc @@ -1,6 +1,9 @@ ## SPDX-License-Identifier: GPL-2.0-only ramstage-y += smm_module_loader.c +ramstage-$(CONFIG_SMM_PCI_RESOURCE_STORE) += pci_resource_store.c + +smm-$(CONFIG_SMM_PCI_RESOURCE_STORE) += pci_resource_store.c ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32),y) $(eval $(call create_class_compiler,smm,x86_32)) diff --git a/src/cpu/x86/smm/pci_resource_store.c b/src/cpu/x86/smm/pci_resource_store.c new file mode 100644 index 0000000000..56bb766cc3 --- /dev/null +++ b/src/cpu/x86/smm/pci_resource_store.c @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <cpu/x86/smm.h> +#include <device/device.h> +#include <device/pci_def.h> +#include <device/pci_ops.h> + +void smm_pci_get_stored_resources(const volatile struct smm_pci_resource_info **out_slots, + size_t *out_size) +{ + *out_slots = smm_get_pci_resource_store(); + *out_size = CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS; +} + +bool smm_pci_resource_store_fill_resources(struct smm_pci_resource_info *slots, size_t num_slots, + const struct device **devices, size_t num_devices) +{ + size_t i_slot = 0; + + for (size_t i_dev = 0; i_dev < num_devices; i_dev++) { + if (i_slot >= num_slots) { + printk(BIOS_ERR, "Failed to store all PCI resources, number of devices exceeds %zd slots\n", + num_slots); + return false; + } + + if (!is_pci(devices[i_dev])) { + printk(BIOS_WARNING, "Skipping storing PCI resources for device at index %zd, not a PCI device\n", + i_dev); + continue; + } + + pci_devfn_t pci_addr = PCI_BDF(devices[i_dev]); + slots[i_slot].pci_addr = pci_addr; + slots[i_slot].class_device = PCI_CLASS_GET_DEVICE(devices[i_dev]->class); + slots[i_slot].class_prog = PCI_CLASS_GET_PROG(devices[i_dev]->class); + + /* Use the resource list to get our BARs. */ + if (!devices[i_dev]->resource_list) + continue; + + size_t i_res = 0; + for (const struct resource *res = devices[i_dev]->resource_list; res != NULL; + res = res->next) { + slots[i_slot].resources[i_res] = *res; + slots[i_slot].resources[i_res].next = NULL; + + if (i_res > 0) + slots[i_slot].resources[i_res - 1].next = (struct resource *)&slots[i_slot].resources[i_res]; + + if (++i_res >= SMM_PCI_RESOURCE_STORE_NUM_RESOURCES) { + if (res->next) + printk(BIOS_WARNING, "Number of PCI resources exceeds supported storage count\n"); + break; + } + } + + i_slot++; + } + + return true; +} + +void __weak smm_mainboard_pci_resource_store_init(struct smm_pci_resource_info *slots, + size_t size) +{ +} + +void smm_pci_resource_store_init(struct smm_runtime *smm_runtime) +{ + smm_mainboard_pci_resource_store_init(&smm_runtime->pci_resources[0], + CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS); +} diff --git a/src/cpu/x86/smm/smm_module_handler.c b/src/cpu/x86/smm/smm_module_handler.c index 1b3c93b780..3415b02842 100644 --- a/src/cpu/x86/smm/smm_module_handler.c +++ b/src/cpu/x86/smm/smm_module_handler.c @@ -195,6 +195,13 @@ asmlinkage void smm_handler_start(void *arg) southbridge_smi_set_eos(); } +#if CONFIG(SMM_PCI_RESOURCE_STORE) +const volatile struct smm_pci_resource_info *smm_get_pci_resource_store(void) +{ + return &smm_runtime.pci_resources[0]; +} +#endif + RMODULE_ENTRY(smm_handler_start); /* Provide a default implementation for all weak handlers so that relocation diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c index 1b04e8894d..6452707f75 100644 --- a/src/cpu/x86/smm/smm_module_loader.c +++ b/src/cpu/x86/smm/smm_module_loader.c @@ -343,6 +343,9 @@ static void setup_smihandler_params(struct smm_runtime *mod_params, mod_params->smm_log_level = mainboard_set_smm_log_level(); else mod_params->smm_log_level = 0; + + if (CONFIG(SMM_PCI_RESOURCE_STORE)) + smm_pci_resource_store_init(mod_params); } static void print_region(const char *name, const struct region region) diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index 4ab9f213f4..d28197232a 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -5,6 +5,8 @@ #include <arch/cpu.h> #include <commonlib/region.h> +#include <device/pci_type.h> +#include <device/resource.h> #include <types.h> #define SMM_DEFAULT_BASE 0x30000 @@ -29,6 +31,8 @@ #define APM_CNT_ELOG_GSMI 0xef #define APM_STS 0xb3 +#define SMM_PCI_RESOURCE_STORE_NUM_RESOURCES 6 + /* Send cmd to APM_CNT with HAVE_SMI_HANDLER checking. */ int apm_control(u8 cmd); u8 apm_get_apmc(void); @@ -58,6 +62,13 @@ void smm_soc_exit(void); extern unsigned char _binary_smm_start[]; extern unsigned char _binary_smm_end[]; +struct smm_pci_resource_info { + pci_devfn_t pci_addr; + uint16_t class_device; + uint8_t class_prog; + struct resource resources[SMM_PCI_RESOURCE_STORE_NUM_RESOURCES]; +}; + struct smm_runtime { u32 smbase; u32 smm_size; @@ -66,6 +77,9 @@ struct smm_runtime { u32 gnvs_ptr; u32 cbmemc_size; void *cbmemc; +#if CONFIG(SMM_PCI_RESOURCE_STORE) + struct smm_pci_resource_info pci_resources[CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS]; +#endif uintptr_t save_state_top[CONFIG_MAX_CPUS]; int smm_log_level; } __packed; @@ -198,4 +212,16 @@ uint32_t smm_revision(void); On AMD systems it is sometimes configurable. */ uint16_t pm_acpi_smi_cmd_port(void); +const volatile struct smm_pci_resource_info *smm_get_pci_resource_store(void); + +void smm_pci_get_stored_resources(const volatile struct smm_pci_resource_info **out_slots, + size_t *out_size); +/* Weak handler function to store PCI BARs. */ +void smm_mainboard_pci_resource_store_init(struct smm_pci_resource_info *slots, size_t size); +/* Helper function to fill BARs from an array of device pointers. */ +bool smm_pci_resource_store_fill_resources(struct smm_pci_resource_info *slots, size_t num_slots, + const struct device **devices, size_t num_devices); + +void smm_pci_resource_store_init(struct smm_runtime *smm_runtime); + #endif /* CPU_X86_SMM_H */ diff --git a/src/include/device/pci_def.h b/src/include/device/pci_def.h index 69ff79d91a..aa53909d1e 100644 --- a/src/include/device/pci_def.h +++ b/src/include/device/pci_def.h @@ -590,4 +590,8 @@ #define PCI_DEV2DEVFN(sdev) (((sdev)>>12) & 0xff) #define PCI_DEV2SEGBUS(sdev) (((sdev)>>20) & 0xfff) +/* Fields from within the device's class value. */ +#define PCI_CLASS_GET_DEVICE(c) (c >> 8) +#define PCI_CLASS_GET_PROG(c) (c & 0xff) + #endif /* PCI_DEF_H */ |