blob: a240ac2f51503b4401451bea512f7b3e1ac640eb [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. */
46int 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;
76 uint16_t class_device;
77 uint8_t class_prog;
78 struct resource resources[SMM_PCI_RESOURCE_STORE_NUM_RESOURCES];
79};
80
Aaron Durbin50a34642013-01-03 17:38:47 -060081struct smm_runtime {
82 u32 smbase;
Arthur Heymansa3eb3df2019-11-27 16:21:46 +010083 u32 smm_size;
Aaron Durbin50a34642013-01-03 17:38:47 -060084 u32 save_state_size;
Eugene Myersae438be2020-01-21 17:01:47 -050085 u32 num_cpus;
Kyösti Mälkkie769bce2020-06-16 21:37:05 +030086 u32 gnvs_ptr;
Raul E Rangelc5160982022-02-24 16:02:49 -070087 u32 cbmemc_size;
88 void *cbmemc;
Robert Ziebaac8c3782022-09-07 16:25:15 -060089#if CONFIG(SMM_PCI_RESOURCE_STORE)
90 struct smm_pci_resource_info pci_resources[CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS];
91#endif
Arthur Heymans64d9e852021-02-15 18:55:40 +010092 uintptr_t save_state_top[CONFIG_MAX_CPUS];
Johnny Lin107e7aa2021-01-14 17:49:08 +080093 int smm_log_level;
Stefan Reinauer6a001132017-07-13 02:20:27 +020094} __packed;
Aaron Durbin50a34642013-01-03 17:38:47 -060095
Aaron Durbin3eb8eb72014-03-10 16:13:58 -050096struct smm_module_params {
Patrick Rudolph24bb8032019-12-01 07:04:04 +010097 size_t cpu;
Raul E Rangeleb5d76a2018-06-25 14:22:27 -060098 /* A canary value that has been placed at the end of the stack.
99 * If (uintptr_t)canary != *canary then a stack overflow has occurred.
100 */
101 const uintptr_t *canary;
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500102};
103
Arthur Heymans5dfb3312021-02-15 13:08:43 +0100104/* These parameters are used by the SMM stub code. A pointer to the params
105 * is also passed to the C-base handler. */
106struct smm_stub_params {
107 u32 stack_size;
108 u32 stack_top;
109 u32 c_handler;
Arthur Heymansed4be452021-02-15 13:20:35 +0100110 /* The apic_id_to_cpu provides a mapping from APIC id to CPU number.
111 * The CPU number is indicated by the index into the array by matching
112 * the default APIC id and value at the index. The stub loader
113 * initializes this array with a 1:1 mapping. If the APIC ids are not
114 * contiguous like the 1:1 mapping it is up to the caller of the stub
115 * loader to adjust this mapping. */
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700116 u16 apic_id_to_cpu[CONFIG_MAX_CPUS];
Arthur Heymans5dfb3312021-02-15 13:08:43 +0100117} __packed;
118
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500119/* smm_handler_t is called with arg of smm_module_params pointer. */
Lee Leahy746d4af2017-03-07 15:31:49 -0800120typedef asmlinkage void (*smm_handler_t)(void *);
Aaron Durbin50a34642013-01-03 17:38:47 -0600121
Aaron Durbin50a34642013-01-03 17:38:47 -0600122/* SMM Runtime helpers. */
Kyösti Mälkki239abaf2020-06-28 12:12:01 +0300123#if ENV_SMM
124extern struct global_nvs *gnvs;
125#endif
Aaron Durbin50a34642013-01-03 17:38:47 -0600126
127/* Entry point for SMM modules. */
Lee Leahy22c28e02017-03-07 15:47:44 -0800128asmlinkage void smm_handler_start(void *params);
Aaron Durbin50a34642013-01-03 17:38:47 -0600129
130/* Retrieve SMM save state for a given CPU. WARNING: This does not take into
131 * account CPUs which are configured to not save their state to RAM. */
132void *smm_get_save_state(int cpu);
133
Patrick Rudolph41fec862020-05-06 10:55:12 +0200134/* Returns true if the region overlaps with the SMM */
135bool smm_region_overlaps_handler(const struct region *r);
136
137/* Returns true if the memory pointed to overlaps with SMM reserved memory. */
138static inline bool smm_points_to_smram(const void *ptr, const size_t len)
139{
140 const struct region r = {(uintptr_t)ptr, len};
141
142 return smm_region_overlaps_handler(&r);
143}
144
Aaron Durbin50a34642013-01-03 17:38:47 -0600145/* SMM Module Loading API */
146
Martin Roth0cb07e32013-07-09 21:46:01 -0600147/* The smm_loader_params structure provides direction to the SMM loader:
Arthur Heymans2412c812021-10-28 15:19:39 +0200148 * - num_cpus - number of concurrent cpus in handler needing stack
Aaron Durbin50a34642013-01-03 17:38:47 -0600149 * optional for setting up relocation handler.
Arthur Heymans1684b0a2022-04-07 21:50:16 +0200150 * - cpu_save_state_size - the SMM save state size per cpu
Aaron Durbin50a34642013-01-03 17:38:47 -0600151 * - num_concurrent_save_states - number of concurrent cpus needing save state
152 * space
153 * - handler - optional handler to call. Only used during SMM relocation setup.
Aaron Durbin50a34642013-01-03 17:38:47 -0600154 * - runtime - this field is a result only. The SMM runtime location is filled
155 * into this field so the code doing the loading can manipulate the
Elyes HAOUASccf78f02016-08-21 10:49:19 +0200156 * runtime's assumptions. e.g. updating the APIC id to CPU map to
157 * handle sparse APIC id space.
Aaron Durbin50a34642013-01-03 17:38:47 -0600158 */
159struct smm_loader_params {
Arthur Heymans2412c812021-10-28 15:19:39 +0200160 size_t num_cpus;
Aaron Durbin50a34642013-01-03 17:38:47 -0600161
Arthur Heymans1684b0a2022-04-07 21:50:16 +0200162 size_t cpu_save_state_size;
Aaron Durbin25a885b2017-06-16 11:45:32 -0500163 size_t num_concurrent_save_states;
Aaron Durbin50a34642013-01-03 17:38:47 -0600164
165 smm_handler_t handler;
Aaron Durbin50a34642013-01-03 17:38:47 -0600166};
167
Arthur Heymans96451a72021-10-28 15:14:18 +0200168/* All of these return 0 on success, < 0 on failure. */
169int smm_setup_stack(const uintptr_t perm_smbase, const size_t perm_smram_size,
170 const unsigned int total_cpus, const size_t stack_size);
171int smm_setup_relocation_handler(struct smm_loader_params *params);
Arthur Heymanscfd32242021-10-28 13:59:54 +0200172int smm_load_module(uintptr_t smram_base, size_t smram_size, struct smm_loader_params *params);
Aaron Durbin50a34642013-01-03 17:38:47 -0600173
Rocky Phaguraafb7a812020-07-21 14:48:48 -0700174u32 smm_get_cpu_smbase(unsigned int cpu_num);
Rocky Phaguraafb7a812020-07-21 14:48:48 -0700175
Aaron Durbinb4b9eb32014-02-13 10:26:18 -0600176/* Backup and restore default SMM region. */
177void *backup_default_smm_area(void);
178void restore_default_smm_area(void *smm_save_area);
179
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300180/*
181 * Fills in the arguments for the entire SMM region covered by chipset
182 * protections. e.g. TSEG.
183 */
Kyösti Mälkki14222d82019-08-05 15:10:18 +0300184void smm_region(uintptr_t *start, size_t *size);
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300185
Kyösti Mälkkibbba2012022-11-11 19:46:05 +0200186static inline void aseg_region(uintptr_t *start, size_t *size)
187{
188 *start = SMM_BASE;
189 *size = SMM_DEFAULT_SIZE; /* SMM_CODE_SEGMENT_SIZE ? */
190}
191
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300192enum {
193 /* SMM handler area. */
194 SMM_SUBREGION_HANDLER,
195 /* SMM cache region. */
196 SMM_SUBREGION_CACHE,
197 /* Chipset specific area. */
198 SMM_SUBREGION_CHIPSET,
199 /* Total sub regions supported. */
200 SMM_SUBREGION_NUM,
201};
202
203/* Fills in the start and size for the requested SMM subregion. Returns
204 * 0 on success, < 0 on failure. */
Kyösti Mälkki14222d82019-08-05 15:10:18 +0300205int smm_subregion(int sub, uintptr_t *start, size_t *size);
Kyösti Mälkkib2a5f0b2019-08-04 19:54:32 +0300206
Kyösti Mälkki7cdb0472019-08-08 11:16:06 +0300207/* Print the SMM memory layout on console. */
208void smm_list_regions(void);
209
Arthur Heymans342d0a82020-08-09 14:58:05 +0200210#define SMM_REVISION_OFFSET_FROM_TOP (0x8000 - 0x7efc)
211/* Return the SMM save state revision. The revision can be fetched from the smm savestate
212 which is always at the same offset downward from the top of the save state. */
213uint32_t smm_revision(void);
Arthur Heymans34280272020-09-29 11:51:34 +0200214/* Returns the PM ACPI SMI port. On Intel systems this typically not configurable (APM_CNT, 0xb2).
215 On AMD systems it is sometimes configurable. */
216uint16_t pm_acpi_smi_cmd_port(void);
Arthur Heymans342d0a82020-08-09 14:58:05 +0200217
Robert Ziebaac8c3782022-09-07 16:25:15 -0600218const volatile struct smm_pci_resource_info *smm_get_pci_resource_store(void);
219
220void smm_pci_get_stored_resources(const volatile struct smm_pci_resource_info **out_slots,
221 size_t *out_size);
222/* Weak handler function to store PCI BARs. */
223void smm_mainboard_pci_resource_store_init(struct smm_pci_resource_info *slots, size_t size);
224/* Helper function to fill BARs from an array of device pointers. */
225bool smm_pci_resource_store_fill_resources(struct smm_pci_resource_info *slots, size_t num_slots,
226 const struct device **devices, size_t num_devices);
227
228void smm_pci_resource_store_init(struct smm_runtime *smm_runtime);
229
Edward O'Callaghanc4561e22014-06-26 15:02:40 +1000230#endif /* CPU_X86_SMM_H */