xref: /aosp_15_r20/external/coreboot/src/include/cpu/x86/smm.h (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #ifndef CPU_X86_SMM_H
4 #define CPU_X86_SMM_H
5 
6 #include <arch/cpu.h>
7 #include <commonlib/region.h>
8 #include <device/pci_type.h>
9 #include <device/resource.h>
10 #include <types.h>
11 
12 #define SMM_DEFAULT_BASE 0x30000
13 #define SMM_DEFAULT_SIZE 0x10000
14 
15 /* used only by C programs so far */
16 #define SMM_BASE 0xa0000
17 
18 #define SMM_ENTRY_OFFSET 0x8000
19 #define SMM_SAVE_STATE_BEGIN(x) (SMM_ENTRY_OFFSET + (x))
20 
21 #define APM_CNT		0xb2
22 #define APM_CNT_NOOP_SMI	0x00
23 #define APM_CNT_ACPI_DISABLE	0x1e
24 #define APM_CNT_ACPI_ENABLE	0xe1
25 #define APM_CNT_ROUTE_ALL_XHCI	0xca
26 #define APM_CNT_FINALIZE	0xcb
27 #define APM_CNT_LEGACY		0xcc
28 #define APM_CNT_MBI_UPDATE	0xeb
29 #define APM_CNT_SMMINFO		0xec
30 #define APM_CNT_SMMSTORE	0xed
31 #define APM_CNT_ELOG_GSMI	0xef
32 #define APM_STS		0xb3
33 
34 #define SMM_PCI_RESOURCE_STORE_NUM_RESOURCES 6
35 
36 /*
37  * SMI Transfer Monitor (STM) descriptor reserved in SMM save state.
38  */
39 #if CONFIG(STM)
40 #define STM_PSD_SIZE ALIGN_UP(sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR), 0x100)
41 #else
42 #define STM_PSD_SIZE 0
43 #endif
44 
45 /* Send cmd to APM_CNT with HAVE_SMI_HANDLER checking. */
46 enum cb_err apm_control(u8 cmd);
47 u8 apm_get_apmc(void);
48 
49 void io_trap_handler(int smif);
50 int mainboard_io_trap_handler(int smif);
51 
52 void southbridge_smi_set_eos(void);
53 
54 void global_smi_enable(void);
55 void global_smi_enable_no_pwrbtn(void);
56 
57 void cpu_smi_handler(void);
58 void northbridge_smi_handler(void);
59 void southbridge_smi_handler(void);
60 
61 void mainboard_smi_gpi(u32 gpi_sts);
62 int  mainboard_smi_apmc(u8 data);
63 void mainboard_smi_sleep(u8 slp_typ);
64 void mainboard_smi_finalize(void);
65 int mainboard_set_smm_log_level(void);
66 
67 void smm_soc_early_init(void);
68 void smm_soc_exit(void);
69 
70 /* This is the SMM handler. */
71 extern unsigned char _binary_smm_start[];
72 extern unsigned char _binary_smm_end[];
73 
74 struct smm_pci_resource_info {
75 	pci_devfn_t pci_addr;
76 	uint16_t vendor_id;
77 	uint16_t device_id;
78 	uint16_t class_device;
79 	uint8_t class_prog;
80 	struct resource resources[SMM_PCI_RESOURCE_STORE_NUM_RESOURCES];
81 };
82 
83 struct smm_runtime {
84 	u32 smbase;
85 	u32 smm_size;
86 	u32 save_state_size;
87 	u32 num_cpus;
88 	u32 gnvs_ptr;
89 	u32 cbmemc_size;
90 	void *cbmemc;
91 #if CONFIG(SMM_PCI_RESOURCE_STORE)
92 	struct smm_pci_resource_info pci_resources[CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS];
93 #endif
94 	uintptr_t save_state_top[CONFIG_MAX_CPUS];
95 	int smm_log_level;
96 	uintptr_t smmstore_com_buffer_base;
97 	size_t smmstore_com_buffer_size;
98 } __packed;
99 
100 struct smm_module_params {
101 	size_t cpu;
102 	/* A canary value that has been placed at the end of the stack.
103 	 * If (uintptr_t)canary != *canary then a stack overflow has occurred.
104 	 */
105 	const uintptr_t *canary;
106 };
107 
108 /* These parameters are used by the SMM stub code. A pointer to the params
109  * is also passed to the C-base handler. */
110 struct smm_stub_params {
111 	u32 stack_size;
112 	u32 stack_top;
113 	u32 c_handler;
114 	u32 cr3;
115 	/* The apic_id_to_cpu provides a mapping from APIC id to CPU number.
116 	 * The CPU number is indicated by the index into the array by matching
117 	 * the default APIC id and value at the index. The stub loader
118 	 * initializes this array with a 1:1 mapping. If the APIC ids are not
119 	 * contiguous like the 1:1 mapping it is up to the caller of the stub
120 	 * loader to adjust this mapping. */
121 	u16 apic_id_to_cpu[CONFIG_MAX_CPUS];
122 } __packed;
123 
124 /* smm_handler_t is called with arg of smm_module_params pointer. */
125 typedef asmlinkage void (*smm_handler_t)(void *);
126 
127 /* SMM Runtime helpers. */
128 #if ENV_SMM
129 extern struct global_nvs *gnvs;
130 #endif
131 
132 /* Entry point for SMM modules. */
133 asmlinkage void smm_handler_start(void *params);
134 
135 /* Retrieve SMM save state for a given CPU. WARNING: This does not take into
136  * account CPUs which are configured to not save their state to RAM. */
137 void *smm_get_save_state(int cpu);
138 
139 /* Returns true if the region overlaps with the SMM */
140 bool smm_region_overlaps_handler(const struct region *r);
141 
142 /* Returns true if the memory pointed to overlaps with SMM reserved memory. */
smm_points_to_smram(const void * ptr,const size_t len)143 static inline bool smm_points_to_smram(const void *ptr, const size_t len)
144 {
145 	const struct region r = {(uintptr_t)ptr, len};
146 
147 	return smm_region_overlaps_handler(&r);
148 }
149 
150 /* SMM Module Loading API */
151 
152 /* The smm_loader_params structure provides direction to the SMM loader:
153  * - num_cpus - number of concurrent cpus in handler needing stack
154  *                           optional for setting up relocation handler.
155  * - cpu_save_state_size - the SMM save state size per cpu
156  * - num_concurrent_save_states - number of concurrent cpus needing save state
157  *                                space
158  * - handler - optional handler to call. Only used during SMM relocation setup.
159  * - runtime - this field is a result only. The SMM runtime location is filled
160  *             into this field so the code doing the loading can manipulate the
161  *             runtime's assumptions. e.g. updating the APIC id to CPU map to
162  *             handle sparse APIC id space.
163  */
164 struct smm_loader_params {
165 	size_t num_cpus;
166 
167 	size_t cpu_save_state_size;
168 	size_t num_concurrent_save_states;
169 
170 	smm_handler_t handler;
171 	uint32_t cr3;
172 };
173 
174 /* All of these return 0 on success, < 0 on failure. */
175 int smm_setup_stack(const uintptr_t perm_smbase, const size_t perm_smram_size,
176 		    const unsigned int total_cpus, const size_t stack_size);
177 int smm_setup_relocation_handler(struct smm_loader_params *params);
178 int smm_load_module(uintptr_t smram_base, size_t smram_size, struct smm_loader_params *params);
179 
180 u32 smm_get_cpu_smbase(unsigned int cpu_num);
181 
182 /* Backup and restore default SMM region. */
183 void *backup_default_smm_area(void);
184 void restore_default_smm_area(void *smm_save_area);
185 
186 /*
187  * Fills in the arguments for the entire SMM region covered by chipset
188  * protections. e.g. TSEG.
189  */
190 void smm_region(uintptr_t *start, size_t *size);
191 
aseg_region(uintptr_t * start,size_t * size)192 static inline void aseg_region(uintptr_t *start, size_t *size)
193 {
194 	*start = SMM_BASE;
195 	*size = SMM_DEFAULT_SIZE; /* SMM_CODE_SEGMENT_SIZE ? */
196 }
197 
198 enum {
199 	/* SMM handler area. */
200 	SMM_SUBREGION_HANDLER,
201 	/* SMM cache region. */
202 	SMM_SUBREGION_CACHE,
203 	/* Chipset specific area. */
204 	SMM_SUBREGION_CHIPSET,
205 	/* Total sub regions supported. */
206 	SMM_SUBREGION_NUM,
207 };
208 
209 /* Fills in the start and size for the requested SMM subregion. Returns
210  * 0 on success, < 0 on failure. */
211 int smm_subregion(int sub, uintptr_t *start, size_t *size);
212 
213 /* Print the SMM memory layout on console. */
214 void smm_list_regions(void);
215 
216 #define SMM_REVISION_OFFSET_FROM_TOP (0x8000 - 0x7efc)
217 /* Return the SMM save state revision. The revision can be fetched from the smm savestate
218    which is always at the same offset downward from the top of the save state. */
219 uint32_t smm_revision(void);
220 /* Returns the PM ACPI SMI port. On Intel systems this typically not configurable (APM_CNT, 0xb2).
221    On AMD systems it is sometimes configurable. */
222 uint16_t pm_acpi_smi_cmd_port(void);
223 
224 const volatile struct smm_pci_resource_info *smm_get_pci_resource_store(void);
225 
226 void smm_pci_get_stored_resources(const volatile struct smm_pci_resource_info **out_slots,
227 				  size_t *out_size);
228 /* Weak handler function to store PCI BARs. */
229 void smm_mainboard_pci_resource_store_init(struct smm_pci_resource_info *slots, size_t size);
230 /* Helper function to fill BARs from an array of device pointers. */
231 bool smm_pci_resource_store_fill_resources(struct smm_pci_resource_info *slots, size_t num_slots,
232 					   const struct device **devices, size_t num_devices);
233 
234 void smm_pci_resource_store_init(struct smm_runtime *smm_runtime);
235 
236 void smm_get_smmstore_com_buffer(uintptr_t *base, size_t *size);
237 
238 #endif /* CPU_X86_SMM_H */
239