xref: /aosp_15_r20/external/coreboot/src/cpu/x86/smm/smm_module_handler.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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