1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <arch/io.h>
4 #include <commonlib/bsd/compiler.h>
5 #include <commonlib/region.h>
6 #include <console/cbmem_console.h>
7 #include <console/console.h>
8 #include <cpu/cpu.h>
9 #include <cpu/x86/smm.h>
10 #include <rmodule.h>
11 #include <types.h>
12 #include <security/intel/stm/SmmStm.h>
13
14 #if CONFIG(SPI_FLASH_SMM)
15 #include <spi-generic.h>
16 #endif
17
18 static int do_driver_init = 1;
19
20 typedef enum { SMI_LOCKED, SMI_UNLOCKED } smi_semaphore;
21
22 /* SMI multiprocessing semaphore */
23 static volatile
24 __attribute__((aligned(4))) smi_semaphore smi_handler_status = SMI_UNLOCKED;
25
26 static const volatile
27 __attribute((aligned(4), __section__(".module_parameters"))) struct smm_runtime smm_runtime;
28
smi_obtain_lock(void)29 static int smi_obtain_lock(void)
30 {
31 u8 ret = SMI_LOCKED;
32
33 asm volatile (
34 "movb %2, %%al\n"
35 "xchgb %%al, %1\n"
36 "movb %%al, %0\n"
37 : "=g" (ret), "=m" (smi_handler_status)
38 : "g" (SMI_LOCKED)
39 : "eax"
40 );
41
42 return (ret == SMI_UNLOCKED);
43 }
44
smi_release_lock(void)45 static void smi_release_lock(void)
46 {
47 asm volatile (
48 "movb %1, %%al\n"
49 "xchgb %%al, %0\n"
50 : "=m" (smi_handler_status)
51 : "g" (SMI_UNLOCKED)
52 : "eax"
53 );
54 }
55
56 #if CONFIG(RUNTIME_CONFIGURABLE_SMM_LOGLEVEL)
get_console_loglevel(void)57 int get_console_loglevel(void)
58 {
59 return smm_runtime.smm_log_level;
60 }
61 #endif
62
smm_get_smmstore_com_buffer(uintptr_t * base,size_t * size)63 void smm_get_smmstore_com_buffer(uintptr_t *base, size_t *size)
64 {
65 *base = smm_runtime.smmstore_com_buffer_base;
66 *size = smm_runtime.smmstore_com_buffer_size;
67 }
68
smm_get_cbmemc_buffer(void ** buffer_out,size_t * size_out)69 void smm_get_cbmemc_buffer(void **buffer_out, size_t *size_out)
70 {
71 *buffer_out = smm_runtime.cbmemc;
72 *size_out = smm_runtime.cbmemc_size;
73 }
74
io_trap_handler(int smif)75 void io_trap_handler(int smif)
76 {
77 /* If a handler function handled a given IO trap, it
78 * shall return a non-zero value
79 */
80 printk(BIOS_DEBUG, "SMI function trap 0x%x: ", smif);
81
82 if (mainboard_io_trap_handler(smif))
83 return;
84
85 printk(BIOS_DEBUG, "Unknown function\n");
86 }
87
88 static u32 pci_orig;
89
90 /**
91 * @brief Backup PCI address to make sure we do not mess up the OS
92 */
smi_backup_pci_address(void)93 static void smi_backup_pci_address(void)
94 {
95 pci_orig = inl(0xcf8);
96 }
97
98 /**
99 * @brief Restore PCI address previously backed up
100 */
smi_restore_pci_address(void)101 static void smi_restore_pci_address(void)
102 {
103 outl(pci_orig, 0xcf8);
104 }
105
106 struct global_nvs *gnvs;
107
smm_get_save_state(int cpu)108 void *smm_get_save_state(int cpu)
109 {
110 if (cpu > smm_runtime.num_cpus)
111 return NULL;
112
113 return (void *)(smm_runtime.save_state_top[cpu] -
114 (smm_runtime.save_state_size - STM_PSD_SIZE));
115 }
116
smm_revision(void)117 uint32_t smm_revision(void)
118 {
119 const uintptr_t save_state = (uintptr_t)(smm_get_save_state(0));
120
121 return *(uint32_t *)(save_state + smm_runtime.save_state_size
122 - SMM_REVISION_OFFSET_FROM_TOP);
123 }
124
smm_region_overlaps_handler(const struct region * r)125 bool smm_region_overlaps_handler(const struct region *r)
126 {
127 const struct region r_smm = {smm_runtime.smbase, smm_runtime.smm_size};
128 const struct region r_aseg = {SMM_BASE, SMM_DEFAULT_SIZE};
129
130 return region_overlap(&r_smm, r) || region_overlap(&r_aseg, r);
131 }
132
smm_handler_start(void * arg)133 asmlinkage void smm_handler_start(void *arg)
134 {
135 const struct smm_module_params *p;
136 int cpu;
137 uintptr_t actual_canary;
138 uintptr_t expected_canary;
139
140 p = arg;
141 cpu = p->cpu;
142 expected_canary = (uintptr_t)p->canary;
143
144 /* Make sure to set the global runtime. It's OK to race as the value
145 * will be the same across CPUs as well as multiple SMIs. */
146 gnvs = (void *)(uintptr_t)smm_runtime.gnvs_ptr;
147
148 if (cpu >= CONFIG_MAX_CPUS) {
149 /* Do not log messages to console here, it is not thread safe */
150 return;
151 }
152
153 /* Are we ok to execute the handler? */
154 if (!smi_obtain_lock()) {
155 /* For security reasons we don't release the other CPUs
156 * until the CPU with the lock is actually done */
157 while (smi_handler_status == SMI_LOCKED) {
158 asm volatile (
159 ".byte 0xf3, 0x90\n" /* PAUSE */
160 );
161 }
162 return;
163 }
164
165 smi_backup_pci_address();
166
167 smm_soc_early_init();
168
169 console_init();
170
171 printk(BIOS_SPEW, "\nSMI# #%d\n", cpu);
172
173 /* Allow drivers to initialize variables in SMM context. */
174 if (do_driver_init) {
175 #if CONFIG(SPI_FLASH_SMM)
176 spi_init();
177 #endif
178 do_driver_init = 0;
179 }
180
181 cpu_smi_handler();
182 northbridge_smi_handler();
183 southbridge_smi_handler();
184
185 smi_restore_pci_address();
186
187 actual_canary = *p->canary;
188
189 if (actual_canary != expected_canary) {
190 printk(BIOS_DEBUG, "canary 0x%lx != 0x%lx\n", actual_canary,
191 expected_canary);
192
193 // Don't die if we can't indicate an error.
194 if (CONFIG(DEBUG_SMI))
195 die("SMM Handler caused a stack overflow\n");
196 }
197
198 smm_soc_exit();
199
200 smi_release_lock();
201
202 /* De-assert SMI# signal to allow another SMI */
203 southbridge_smi_set_eos();
204 }
205
206 #if CONFIG(SMM_PCI_RESOURCE_STORE)
smm_get_pci_resource_store(void)207 const volatile struct smm_pci_resource_info *smm_get_pci_resource_store(void)
208 {
209 return &smm_runtime.pci_resources[0];
210 }
211 #endif
212
213 RMODULE_ENTRY(smm_handler_start);
214
215 /* Provide a default implementation for all weak handlers so that relocation
216 * entries in the modules make sense. Without default implementations the
217 * weak relocations w/o a symbol have a 0 address which is where the modules
218 * are linked at. */
mainboard_io_trap_handler(int smif)219 int __weak mainboard_io_trap_handler(int smif) { return 0; }
cpu_smi_handler(void)220 void __weak cpu_smi_handler(void) {}
northbridge_smi_handler(void)221 void __weak northbridge_smi_handler(void) {}
southbridge_smi_handler(void)222 void __weak southbridge_smi_handler(void) {}
mainboard_smi_gpi(u32 gpi_sts)223 void __weak mainboard_smi_gpi(u32 gpi_sts) {}
mainboard_smi_apmc(u8 data)224 int __weak mainboard_smi_apmc(u8 data) { return 0; }
mainboard_smi_sleep(u8 slp_typ)225 void __weak mainboard_smi_sleep(u8 slp_typ) {}
mainboard_smi_finalize(void)226 void __weak mainboard_smi_finalize(void) {}
227
smm_soc_early_init(void)228 void __weak smm_soc_early_init(void) {}
smm_soc_exit(void)229 void __weak smm_soc_exit(void) {}
230