blob: beb88faeab0cb716a2a7948a4f2d17abb3eabb49 [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;
Stefan Reinauer6a001132017-07-13 02:20:27 +020096} __packed;
Aaron Durbin50a34642013-01-03 17:38:47 -060097
Aaron Durbin3eb8eb72014-03-10 16:13:58 -050098struct smm_module_params {
Patrick Rudolph24bb8032019-12-01 07:04:04 +010099 size_t cpu;
Raul E Rangeleb5d76a2018-06-25 14:22:27 -0600100 /* A canary value that has been placed at the end of the stack.
101 * If (uintptr_t)canary != *canary then a stack overflow has occurred.
102 */
103 const uintptr_t *canary;
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500104};
105
Arthur Heymans5dfb3312021-02-15 13:08:43 +0100106/* These parameters are used by the SMM stub code. A pointer to the params
107 * is also passed to the C-base handler. */
108struct smm_stub_params {
109 u32 stack_size;
110 u32 stack_top;
111 u32 c_handler;
Arthur Heymansed4be452021-02-15 13:20:35 +0100112 /* The apic_id_to_cpu provides a mapping from APIC id to CPU number.
113 * The CPU number is indicated by the index into the array by matching
114 * the default APIC id and value at the index. The stub loader
115 * initializes this array with a 1:1 mapping. If the APIC ids are not
116 * contiguous like the 1:1 mapping it is up to the caller of the stub
117 * loader to adjust this mapping. */
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700118 u16 apic_id_to_cpu[CONFIG_MAX_CPUS];
Arthur Heymans5dfb3312021-02-15 13:08:43 +0100119} __packed;
120
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500121/* smm_handler_t is called with arg of smm_module_params pointer. */
Lee Leahy746d4af2017-03-07 15:31:49 -0800122typedef asmlinkage void (*smm_handler_t)(void *);
Aaron Durbin50a34642013-01-03 17:38:47 -0600123
Aaron Durbin50a34642013-01-03 17:38:47 -0600124/* SMM Runtime helpers. */
Kyösti Mälkki239abaf2020-06-28 12:12:01 +0300125#if ENV_SMM
126extern struct global_nvs *gnvs;
127#endif
Aaron Durbin50a34642013-01-03 17:38:47 -0600128
129/* Entry point for SMM modules. */
Lee Leahy22c28e02017-03-07 15:47:44 -0800130asmlinkage void smm_handler_start(void *params);
Aaron Durbin50a34642013-01-03 17:38:47 -0600131
132/* Retrieve SMM save state for a given CPU. WARNING: This does not take into
133 * account CPUs which are configured to not save their state to RAM. */
134void *smm_get_save_state(int cpu);
135
Patrick Rudolph41fec862020-05-06 10:55:12 +0200136/* Returns true if the region overlaps with the SMM */
137bool smm_region_overlaps_handler(const struct region *r);
138
139/* Returns true if the memory pointed to overlaps with SMM reserved memory. */
140static inline bool smm_points_to_smram(const void *ptr, const size_t len)
141{
142 const struct region r = {(uintptr_t)ptr, len};
143
144 return smm_region_overlaps_handler(&r);
145}
146
Aaron Durbin50a34642013-01-03 17:38:47 -0600147/* SMM Module Loading API */
148
Martin Roth0cb07e32013-07-09 21:46:01 -0600149/* The smm_loader_params structure provides direction to the SMM loader:
Arthur Heymans2412c812021-10-28 15:19:39 +0200150 * - num_cpus - number of concurrent cpus in handler needing stack
Aaron Durbin50a34642013-01-03 17:38:47 -0600151 * optional for setting up relocation handler.
Arthur Heymans1684b0a2022-04-07 21:50:16 +0200152 * - cpu_save_state_size - the SMM save state size per cpu
Aaron Durbin50a34642013-01-03 17:38:47 -0600153 * - num_concurrent_save_states - number of concurrent cpus needing save state
154 * space
155 * - handler - optional handler to call. Only used during SMM relocation setup.
Aaron Durbin50a34642013-01-03 17:38:47 -0600156 * - runtime - this field is a result only. The SMM runtime location is filled
157 * into this field so the code doing the loading can manipulate the
Elyes HAOUASccf78f02016-08-21 10:49:19 +0200158 * runtime's assumptions. e.g. updating the APIC id to CPU map to
159 * handle sparse APIC id space.
Aaron Durbin50a34642013-01-03 17:38:47 -0600160 */
161struct smm_loader_params {
Arthur Heymans2412c812021-10-28 15:19:39 +0200162 size_t num_cpus;
Aaron Durbin50a34642013-01-03 17:38:47 -0600163
Arthur Heymans1684b0a2022-04-07 21:50:16 +0200164 size_t cpu_save_state_size;
Aaron Durbin25a885b2017-06-16 11:45:32 -0500165 size_t num_concurrent_save_states;
Aaron Durbin50a34642013-01-03 17:38:47 -0600166
167 smm_handler_t handler;
Aaron Durbin50a34642013-01-03 17:38:47 -0600168};
169
Arthur Heymans96451a72021-10-28 15:14:18 +0200170/* All of these return 0 on success, < 0 on failure. */
171int smm_setup_stack(const uintptr_t perm_smbase, const size_t perm_smram_size,
172 const unsigned int total_cpus, const size_t stack_size);
173int smm_setup_relocation_handler(struct smm_loader_params *params);
Arthur Heymanscfd32242021-10-28 13:59:54 +0200174int smm_load_module(uintptr_t smram_base, size_t smram_size, struct smm_loader_params *params);
Aaron Durbin50a34642013-01-03 17:38:47 -0600175
Rocky Phaguraafb7a812020-07-21 14:48:48 -0700176u32 smm_get_cpu_smbase(unsigned int cpu_num);
Rocky Phaguraafb7a812020-07-21 14:48:48 -0700177
Aaron Durbinb4b9eb32014-02-13 10:26:18 -0600178/* Backup and restore default SMM region. */
179void *backup_default_smm_area(void);
180void restore_default_smm_area(void *smm_save_area);
181
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300182/*
183 * Fills in the arguments for the entire SMM region covered by chipset
184 * protections. e.g. TSEG.
185 */
Kyösti Mälkki14222d82019-08-05 15:10:18 +0300186void smm_region(uintptr_t *start, size_t *size);
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300187
Kyösti Mälkkibbba2012022-11-11 19:46:05 +0200188static inline void aseg_region(uintptr_t *start, size_t *size)
189{
190 *start = SMM_BASE;
191 *size = SMM_DEFAULT_SIZE; /* SMM_CODE_SEGMENT_SIZE ? */
192}
193
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300194enum {
195 /* SMM handler area. */
196 SMM_SUBREGION_HANDLER,
197 /* SMM cache region. */
198 SMM_SUBREGION_CACHE,
199 /* Chipset specific area. */
200 SMM_SUBREGION_CHIPSET,
201 /* Total sub regions supported. */
202 SMM_SUBREGION_NUM,
203};
204
205/* Fills in the start and size for the requested SMM subregion. Returns
206 * 0 on success, < 0 on failure. */
Kyösti Mälkki14222d82019-08-05 15:10:18 +0300207int smm_subregion(int sub, uintptr_t *start, size_t *size);
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300208
Kyösti Mälkki7cdb0472019-08-08 11:16:06 +0300209/* Print the SMM memory layout on console. */
210void smm_list_regions(void);
211
Arthur Heymans342d0a82020-08-09 14:58:05 +0200212#define SMM_REVISION_OFFSET_FROM_TOP (0x8000 - 0x7efc)
213/* Return the SMM save state revision. The revision can be fetched from the smm savestate
214 which is always at the same offset downward from the top of the save state. */
215uint32_t smm_revision(void);
Arthur Heymans34280272020-09-29 11:51:34 +0200216/* Returns the PM ACPI SMI port. On Intel systems this typically not configurable (APM_CNT, 0xb2).
217 On AMD systems it is sometimes configurable. */
218uint16_t pm_acpi_smi_cmd_port(void);
Arthur Heymans342d0a82020-08-09 14:58:05 +0200219
Robert Ziebaac8c3782022-09-07 16:25:15 -0600220const volatile struct smm_pci_resource_info *smm_get_pci_resource_store(void);
221
222void smm_pci_get_stored_resources(const volatile struct smm_pci_resource_info **out_slots,
223 size_t *out_size);
224/* Weak handler function to store PCI BARs. */
225void smm_mainboard_pci_resource_store_init(struct smm_pci_resource_info *slots, size_t size);
226/* Helper function to fill BARs from an array of device pointers. */
227bool smm_pci_resource_store_fill_resources(struct smm_pci_resource_info *slots, size_t num_slots,
228 const struct device **devices, size_t num_devices);
229
230void smm_pci_resource_store_init(struct smm_runtime *smm_runtime);
231
Edward O'Callaghanc4561e22014-06-26 15:02:40 +1000232#endif /* CPU_X86_SMM_H */