1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <commonlib/region.h>
5 #include <console/cbmem_console.h>
6 #include <console/console.h>
8 #include <cpu/x86/smm.h>
11 #include <security/intel/stm/SmmStm.h>
13 #if CONFIG(SPI_FLASH_SMM)
14 #include <spi-generic.h>
17 static int do_driver_init
= 1;
19 typedef enum { SMI_LOCKED
, SMI_UNLOCKED
} smi_semaphore
;
21 /* SMI multiprocessing semaphore */
23 __attribute__((aligned(4))) smi_semaphore smi_handler_status
= SMI_UNLOCKED
;
26 __attribute((aligned(4), __section__(".module_parameters"))) struct smm_runtime smm_runtime
;
28 static int smi_obtain_lock(void)
36 : "=g" (ret
), "=m" (smi_handler_status
)
41 return (ret
== SMI_UNLOCKED
);
44 static void smi_release_lock(void)
49 : "=m" (smi_handler_status
)
55 #if CONFIG(RUNTIME_CONFIGURABLE_SMM_LOGLEVEL)
56 int get_console_loglevel(void)
58 return smm_runtime
.smm_log_level
;
62 void smm_get_smmstore_com_buffer(uintptr_t *base
, size_t *size
)
64 *base
= smm_runtime
.smmstore_com_buffer_base
;
65 *size
= smm_runtime
.smmstore_com_buffer_size
;
68 void smm_get_cbmemc_buffer(void **buffer_out
, size_t *size_out
)
70 *buffer_out
= smm_runtime
.cbmemc
;
71 *size_out
= smm_runtime
.cbmemc_size
;
74 void io_trap_handler(int smif
)
76 /* If a handler function handled a given IO trap, it
77 * shall return a non-zero value
79 printk(BIOS_DEBUG
, "SMI function trap 0x%x: ", smif
);
81 if (mainboard_io_trap_handler(smif
))
84 printk(BIOS_DEBUG
, "Unknown function\n");
90 * @brief Backup PCI address to make sure we do not mess up the OS
92 static void smi_backup_pci_address(void)
94 pci_orig
= inl(0xcf8);
98 * @brief Restore PCI address previously backed up
100 static void smi_restore_pci_address(void)
102 outl(pci_orig
, 0xcf8);
105 struct global_nvs
*gnvs
;
107 void *smm_get_save_state(int cpu
)
109 if (cpu
> smm_runtime
.num_cpus
)
112 return (void *)(smm_runtime
.save_state_top
[cpu
] -
113 (smm_runtime
.save_state_size
- STM_PSD_SIZE
));
116 uint32_t smm_revision(void)
118 const uintptr_t save_state
= (uintptr_t)(smm_get_save_state(0));
120 return *(uint32_t *)(save_state
+ smm_runtime
.save_state_size
121 - SMM_REVISION_OFFSET_FROM_TOP
);
124 bool smm_region_overlaps_handler(const struct region
*r
)
126 const struct region r_smm
= region_create(smm_runtime
.smbase
, smm_runtime
.smm_size
);
127 const struct region r_aseg
= region_create(SMM_BASE
, SMM_DEFAULT_SIZE
);
129 return region_overlap(&r_smm
, r
) || region_overlap(&r_aseg
, r
);
132 asmlinkage
void smm_handler_start(void *arg
)
134 const struct smm_module_params
*p
;
136 uintptr_t actual_canary
;
137 uintptr_t expected_canary
;
141 expected_canary
= (uintptr_t)p
->canary
;
143 /* Make sure to set the global runtime. It's OK to race as the value
144 * will be the same across CPUs as well as multiple SMIs. */
145 gnvs
= (void *)(uintptr_t)smm_runtime
.gnvs_ptr
;
147 if (cpu
>= CONFIG_MAX_CPUS
) {
148 /* Do not log messages to console here, it is not thread safe */
152 /* Are we ok to execute the handler? */
153 if (!smi_obtain_lock()) {
154 /* For security reasons we don't release the other CPUs
155 * until the CPU with the lock is actually done */
156 while (smi_handler_status
== SMI_LOCKED
) {
158 ".byte 0xf3, 0x90\n" /* PAUSE */
164 smi_backup_pci_address();
166 smm_soc_early_init();
170 printk(BIOS_SPEW
, "\nSMI# #%d\n", cpu
);
172 /* Allow drivers to initialize variables in SMM context. */
173 if (do_driver_init
) {
174 #if CONFIG(SPI_FLASH_SMM)
181 northbridge_smi_handler();
182 southbridge_smi_handler();
184 smi_restore_pci_address();
186 actual_canary
= *p
->canary
;
188 if (actual_canary
!= expected_canary
) {
189 printk(BIOS_DEBUG
, "canary 0x%lx != 0x%lx\n", actual_canary
,
192 // Don't die if we can't indicate an error.
193 if (CONFIG(DEBUG_SMI
))
194 die("SMM Handler caused a stack overflow\n");
201 /* De-assert SMI# signal to allow another SMI */
202 southbridge_smi_set_eos();
205 #if CONFIG(SMM_PCI_RESOURCE_STORE)
206 const volatile struct smm_pci_resource_info
*smm_get_pci_resource_store(void)
208 return &smm_runtime
.pci_resources
[0];
212 RMODULE_ENTRY(smm_handler_start
);
214 /* Provide a default implementation for all weak handlers so that relocation
215 * entries in the modules make sense. Without default implementations the
216 * weak relocations w/o a symbol have a 0 address which is where the modules
218 int __weak
mainboard_io_trap_handler(int smif
) { return 0; }
219 void __weak
cpu_smi_handler(void) {}
220 void __weak
northbridge_smi_handler(void) {}
221 void __weak
southbridge_smi_handler(void) {}
222 void __weak
mainboard_smi_gpi(u32 gpi_sts
) {}
223 int __weak
mainboard_smi_apmc(u8 data
) { return 0; }
224 void __weak
mainboard_smi_sleep(u8 slp_typ
) {}
225 void __weak
mainboard_smi_finalize(void) {}
227 void __weak
smm_soc_early_init(void) {}
228 void __weak
smm_soc_exit(void) {}