blob: 44a1086e4f528c883d71ec52d63fd657d464f6a9 [file] [log] [blame]
Angel Pons32859fc2020-04-02 23:48:27 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauerdebb11f2008-10-29 04:46:52 +00002
Sven Schnelle180f81e2011-06-28 08:06:18 +02003#ifndef CPU_X86_SMM_H
4#define CPU_X86_SMM_H
5
Edward O'Callaghanc4561e22014-06-26 15:02:40 +10006#include <arch/cpu.h>
Patrick Rudolph41fec862020-05-06 10:55:12 +02007#include <commonlib/region.h>
Robert Ziebaac8c3782022-09-07 16:25:15 -06008#include <device/pci_type.h>
9#include <device/resource.h>
Edward O'Callaghanc4561e22014-06-26 15:02:40 +100010#include <types.h>
11
Aaron Durbin1fef1f52012-12-19 17:15:43 -060012#define SMM_DEFAULT_BASE 0x30000
13#define SMM_DEFAULT_SIZE 0x10000
14
Rudolf Marekb5b3b3b2011-07-02 16:36:17 +020015/* used only by C programs so far */
16#define SMM_BASE 0xa0000
17
Aaron Durbin62f100b2012-11-07 12:27:29 -060018#define SMM_ENTRY_OFFSET 0x8000
19#define SMM_SAVE_STATE_BEGIN(x) (SMM_ENTRY_OFFSET + (x))
20
Sven Schnellef4dc1a72011-06-05 11:33:41 +020021#define APM_CNT 0xb2
Kyösti Mälkkid1518312020-06-18 13:51:31 +030022#define APM_CNT_NOOP_SMI 0x00
Sven Schnellef4dc1a72011-06-05 11:33:41 +020023#define APM_CNT_ACPI_DISABLE 0x1e
24#define APM_CNT_ACPI_ENABLE 0xe1
Kyösti Mälkkib486f292020-06-18 14:05:35 +030025#define APM_CNT_ROUTE_ALL_XHCI 0xca
Duncan Laurie911cedf2013-07-30 16:05:55 -070026#define APM_CNT_FINALIZE 0xcb
Marc Jones9afc5c02014-09-24 10:53:48 -060027#define APM_CNT_LEGACY 0xcc
Kyösti Mälkkib8cf0392020-06-17 01:00:10 +030028#define APM_CNT_MBI_UPDATE 0xeb
Marshall Dawsond2d93822020-03-16 20:05:05 -060029#define APM_CNT_SMMINFO 0xec
Patrick Georgi9fca2972018-12-03 16:13:17 +010030#define APM_CNT_SMMSTORE 0xed
Patrick Georgid61839c2018-12-03 16:10:33 +010031#define APM_CNT_ELOG_GSMI 0xef
Sven Schnellef4dc1a72011-06-05 11:33:41 +020032#define APM_STS 0xb3
Stefan Reinauer3b387452009-03-06 19:52:36 +000033
Robert Ziebaac8c3782022-09-07 16:25:15 -060034#define SMM_PCI_RESOURCE_STORE_NUM_RESOURCES 6
35
Eugene D. Myersd205cf72023-11-02 13:34:56 -070036/*
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
Kyösti Mälkkib6585482020-06-01 15:11:14 +030045/* Send cmd to APM_CNT with HAVE_SMI_HANDLER checking. */
Felix Held21710ea2024-01-05 19:16:48 +010046enum cb_err apm_control(u8 cmd);
Kyösti Mälkki9a1620f2021-01-08 13:27:33 +020047u8 apm_get_apmc(void);
Kyösti Mälkkib6585482020-06-01 15:11:14 +030048
Stefan Reinauerbe7f7982009-03-13 15:42:27 +000049void io_trap_handler(int smif);
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +020050int mainboard_io_trap_handler(int smif);
Stefan Reinauer3b387452009-03-06 19:52:36 +000051
Stefan Reinauer348a1ba2010-03-17 01:51:11 +000052void southbridge_smi_set_eos(void);
53
Kyösti Mälkki21ba5ee2020-06-10 10:52:24 +030054void global_smi_enable(void);
55void global_smi_enable_no_pwrbtn(void);
56
Aaron Durbin50a34642013-01-03 17:38:47 -060057void cpu_smi_handler(void);
58void northbridge_smi_handler(void);
59void southbridge_smi_handler(void);
Kyösti Mälkkie31ec292019-08-10 17:27:01 +030060
Duncan Laurie0edc2242013-04-29 15:04:30 -070061void mainboard_smi_gpi(u32 gpi_sts);
Aaron Durbin50a34642013-01-03 17:38:47 -060062int mainboard_smi_apmc(u8 data);
63void mainboard_smi_sleep(u8 slp_typ);
Aseda Aboagye63356052021-06-17 12:10:33 -070064void mainboard_smi_finalize(void);
Johnny Lin107e7aa2021-01-14 17:49:08 +080065int mainboard_set_smm_log_level(void);
Stefan Reinauerbf34e942012-04-27 00:44:04 +020066
Raul E Rangele6cd6ca2022-02-25 12:40:32 -070067void smm_soc_early_init(void);
68void smm_soc_exit(void);
69
Kyösti Mälkki9d8adc02016-12-04 22:17:37 +020070/* This is the SMM handler. */
71extern unsigned char _binary_smm_start[];
72extern unsigned char _binary_smm_end[];
73
Robert Ziebaac8c3782022-09-07 16:25:15 -060074struct smm_pci_resource_info {
75 pci_devfn_t pci_addr;
Patrick Rudolph61ec6e92024-01-25 14:52:01 +010076 uint16_t vendor_id;
77 uint16_t device_id;
Robert Ziebaac8c3782022-09-07 16:25:15 -060078 uint16_t class_device;
79 uint8_t class_prog;
80 struct resource resources[SMM_PCI_RESOURCE_STORE_NUM_RESOURCES];
81};
82
Aaron Durbin50a34642013-01-03 17:38:47 -060083struct smm_runtime {
84 u32 smbase;
Arthur Heymansa3eb3df2019-11-27 16:21:46 +010085 u32 smm_size;
Aaron Durbin50a34642013-01-03 17:38:47 -060086 u32 save_state_size;
Eugene Myersae438be2020-01-21 17:01:47 -050087 u32 num_cpus;
Kyösti Mälkkie769bce2020-06-16 21:37:05 +030088 u32 gnvs_ptr;
Raul E Rangelc5160982022-02-24 16:02:49 -070089 u32 cbmemc_size;
90 void *cbmemc;
Robert Ziebaac8c3782022-09-07 16:25:15 -060091#if CONFIG(SMM_PCI_RESOURCE_STORE)
92 struct smm_pci_resource_info pci_resources[CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS];
93#endif
Arthur Heymans64d9e852021-02-15 18:55:40 +010094 uintptr_t save_state_top[CONFIG_MAX_CPUS];
Johnny Lin107e7aa2021-01-14 17:49:08 +080095 int smm_log_level;
Arthur Heymansd57d5e32023-12-27 20:54:19 +010096 uintptr_t smmstore_com_buffer_base;
97 size_t smmstore_com_buffer_size;
Stefan Reinauer6a001132017-07-13 02:20:27 +020098} __packed;
Aaron Durbin50a34642013-01-03 17:38:47 -060099
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500100struct smm_module_params {
Patrick Rudolph24bb8032019-12-01 07:04:04 +0100101 size_t cpu;
Raul E Rangeleb5d76a2018-06-25 14:22:27 -0600102 /* 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;
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500106};
107
Arthur Heymans5dfb3312021-02-15 13:08:43 +0100108/* These parameters are used by the SMM stub code. A pointer to the params
109 * is also passed to the C-base handler. */
110struct smm_stub_params {
111 u32 stack_size;
112 u32 stack_top;
113 u32 c_handler;
Arthur Heymans3cfcffe2024-02-02 17:37:42 +0100114 u32 cr3;
Arthur Heymansed4be452021-02-15 13:20:35 +0100115 /* 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. */
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700121 u16 apic_id_to_cpu[CONFIG_MAX_CPUS];
Arthur Heymans5dfb3312021-02-15 13:08:43 +0100122} __packed;
123
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500124/* smm_handler_t is called with arg of smm_module_params pointer. */
Lee Leahy746d4af2017-03-07 15:31:49 -0800125typedef asmlinkage void (*smm_handler_t)(void *);
Aaron Durbin50a34642013-01-03 17:38:47 -0600126
Aaron Durbin50a34642013-01-03 17:38:47 -0600127/* SMM Runtime helpers. */
Kyösti Mälkki239abaf2020-06-28 12:12:01 +0300128#if ENV_SMM
129extern struct global_nvs *gnvs;
130#endif
Aaron Durbin50a34642013-01-03 17:38:47 -0600131
132/* Entry point for SMM modules. */
Lee Leahy22c28e02017-03-07 15:47:44 -0800133asmlinkage void smm_handler_start(void *params);
Aaron Durbin50a34642013-01-03 17:38:47 -0600134
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. */
137void *smm_get_save_state(int cpu);
138
Patrick Rudolph41fec862020-05-06 10:55:12 +0200139/* Returns true if the region overlaps with the SMM */
140bool smm_region_overlaps_handler(const struct region *r);
141
142/* Returns true if the memory pointed to overlaps with SMM reserved memory. */
143static 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
Aaron Durbin50a34642013-01-03 17:38:47 -0600150/* SMM Module Loading API */
151
Martin Roth0cb07e32013-07-09 21:46:01 -0600152/* The smm_loader_params structure provides direction to the SMM loader:
Arthur Heymans2412c812021-10-28 15:19:39 +0200153 * - num_cpus - number of concurrent cpus in handler needing stack
Aaron Durbin50a34642013-01-03 17:38:47 -0600154 * optional for setting up relocation handler.
Arthur Heymans1684b0a2022-04-07 21:50:16 +0200155 * - cpu_save_state_size - the SMM save state size per cpu
Aaron Durbin50a34642013-01-03 17:38:47 -0600156 * - 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.
Aaron Durbin50a34642013-01-03 17:38:47 -0600159 * - 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
Elyes HAOUASccf78f02016-08-21 10:49:19 +0200161 * runtime's assumptions. e.g. updating the APIC id to CPU map to
162 * handle sparse APIC id space.
Aaron Durbin50a34642013-01-03 17:38:47 -0600163 */
164struct smm_loader_params {
Arthur Heymans2412c812021-10-28 15:19:39 +0200165 size_t num_cpus;
Aaron Durbin50a34642013-01-03 17:38:47 -0600166
Arthur Heymans1684b0a2022-04-07 21:50:16 +0200167 size_t cpu_save_state_size;
Aaron Durbin25a885b2017-06-16 11:45:32 -0500168 size_t num_concurrent_save_states;
Aaron Durbin50a34642013-01-03 17:38:47 -0600169
170 smm_handler_t handler;
Arthur Heymans3cfcffe2024-02-02 17:37:42 +0100171 uint32_t cr3;
Aaron Durbin50a34642013-01-03 17:38:47 -0600172};
173
Arthur Heymans96451a72021-10-28 15:14:18 +0200174/* All of these return 0 on success, < 0 on failure. */
175int 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);
177int smm_setup_relocation_handler(struct smm_loader_params *params);
Arthur Heymanscfd32242021-10-28 13:59:54 +0200178int smm_load_module(uintptr_t smram_base, size_t smram_size, struct smm_loader_params *params);
Aaron Durbin50a34642013-01-03 17:38:47 -0600179
Rocky Phaguraafb7a812020-07-21 14:48:48 -0700180u32 smm_get_cpu_smbase(unsigned int cpu_num);
Rocky Phaguraafb7a812020-07-21 14:48:48 -0700181
Aaron Durbinb4b9eb32014-02-13 10:26:18 -0600182/* Backup and restore default SMM region. */
183void *backup_default_smm_area(void);
184void restore_default_smm_area(void *smm_save_area);
185
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300186/*
187 * Fills in the arguments for the entire SMM region covered by chipset
188 * protections. e.g. TSEG.
189 */
Kyösti Mälkki14222d82019-08-05 15:10:18 +0300190void smm_region(uintptr_t *start, size_t *size);
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300191
Kyösti Mälkkibbba2012022-11-11 19:46:05 +0200192static 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
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300198enum {
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. */
Kyösti Mälkki14222d82019-08-05 15:10:18 +0300211int smm_subregion(int sub, uintptr_t *start, size_t *size);
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300212
Kyösti Mälkki7cdb0472019-08-08 11:16:06 +0300213/* Print the SMM memory layout on console. */
214void smm_list_regions(void);
215
Arthur Heymans342d0a82020-08-09 14:58:05 +0200216#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. */
219uint32_t smm_revision(void);
Arthur Heymans34280272020-09-29 11:51:34 +0200220/* Returns the PM ACPI SMI port. On Intel systems this typically not configurable (APM_CNT, 0xb2).
221 On AMD systems it is sometimes configurable. */
222uint16_t pm_acpi_smi_cmd_port(void);
Arthur Heymans342d0a82020-08-09 14:58:05 +0200223
Robert Ziebaac8c3782022-09-07 16:25:15 -0600224const volatile struct smm_pci_resource_info *smm_get_pci_resource_store(void);
225
226void 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. */
229void 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. */
231bool 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
234void smm_pci_resource_store_init(struct smm_runtime *smm_runtime);
235
Arthur Heymansd57d5e32023-12-27 20:54:19 +0100236void smm_get_smmstore_com_buffer(uintptr_t *base, size_t *size);
237
Edward O'Callaghanc4561e22014-06-26 15:02:40 +1000238#endif /* CPU_X86_SMM_H */