summaryrefslogtreecommitdiffstats
path: root/src/include/cpu/x86/smm.h
blob: dfb27cd20238ceafe33a29d3ca5c7670863dc478 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/* SPDX-License-Identifier: GPL-2.0-only */

#ifndef CPU_X86_SMM_H
#define CPU_X86_SMM_H

#include <arch/cpu.h>
#include <commonlib/region.h>
#include <device/pci_type.h>
#include <device/resource.h>
#include <types.h>

#define SMM_DEFAULT_BASE 0x30000
#define SMM_DEFAULT_SIZE 0x10000

/* used only by C programs so far */
#define SMM_BASE 0xa0000

#define SMM_ENTRY_OFFSET 0x8000
#define SMM_SAVE_STATE_BEGIN(x) (SMM_ENTRY_OFFSET + (x))

#define APM_CNT		0xb2
#define APM_CNT_NOOP_SMI	0x00
#define APM_CNT_ACPI_DISABLE	0x1e
#define APM_CNT_ACPI_ENABLE	0xe1
#define APM_CNT_ROUTE_ALL_XHCI	0xca
#define APM_CNT_FINALIZE	0xcb
#define APM_CNT_LEGACY		0xcc
#define APM_CNT_MBI_UPDATE	0xeb
#define APM_CNT_SMMINFO		0xec
#define APM_CNT_SMMSTORE	0xed
#define APM_CNT_ELOG_GSMI	0xef
#define APM_STS		0xb3

#define SMM_PCI_RESOURCE_STORE_NUM_RESOURCES 6

/*
 * SMI Transfer Monitor (STM) descriptor reserved in SMM save state.
 */
#if CONFIG(STM)
#define STM_PSD_SIZE ALIGN_UP(sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR), 0x100)
#else
#define STM_PSD_SIZE 0
#endif

/* Send cmd to APM_CNT with HAVE_SMI_HANDLER checking. */
enum cb_err apm_control(u8 cmd);
u8 apm_get_apmc(void);

void io_trap_handler(int smif);
int mainboard_io_trap_handler(int smif);

void southbridge_smi_set_eos(void);

void global_smi_enable(void);
void global_smi_enable_no_pwrbtn(void);

void cpu_smi_handler(void);
void northbridge_smi_handler(void);
void southbridge_smi_handler(void);

void mainboard_smi_gpi(u32 gpi_sts);
int  mainboard_smi_apmc(u8 data);
void mainboard_smi_sleep(u8 slp_typ);
void mainboard_smi_finalize(void);
int mainboard_set_smm_log_level(void);

void smm_soc_early_init(void);
void smm_soc_exit(void);

/* This is the SMM handler. */
extern unsigned char _binary_smm_start[];
extern unsigned char _binary_smm_end[];

struct smm_pci_resource_info {
	pci_devfn_t pci_addr;
	uint16_t class_device;
	uint8_t class_prog;
	struct resource resources[SMM_PCI_RESOURCE_STORE_NUM_RESOURCES];
};

struct smm_runtime {
	u32 smbase;
	u32 smm_size;
	u32 save_state_size;
	u32 num_cpus;
	u32 gnvs_ptr;
	u32 cbmemc_size;
	void *cbmemc;
#if CONFIG(SMM_PCI_RESOURCE_STORE)
	struct smm_pci_resource_info pci_resources[CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS];
#endif
	uintptr_t save_state_top[CONFIG_MAX_CPUS];
	int smm_log_level;
} __packed;

struct smm_module_params {
	size_t cpu;
	/* A canary value that has been placed at the end of the stack.
	 * If (uintptr_t)canary != *canary then a stack overflow has occurred.
	 */
	const uintptr_t *canary;
};

/* These parameters are used by the SMM stub code. A pointer to the params
 * is also passed to the C-base handler. */
struct smm_stub_params {
	u32 stack_size;
	u32 stack_top;
	u32 c_handler;
	/* The apic_id_to_cpu provides a mapping from APIC id to CPU number.
	 * The CPU number is indicated by the index into the array by matching
	 * the default APIC id and value at the index. The stub loader
	 * initializes this array with a 1:1 mapping. If the APIC ids are not
	 * contiguous like the 1:1 mapping it is up to the caller of the stub
	 * loader to adjust this mapping. */
	u16 apic_id_to_cpu[CONFIG_MAX_CPUS];
} __packed;

/* smm_handler_t is called with arg of smm_module_params pointer. */
typedef asmlinkage void (*smm_handler_t)(void *);

/* SMM Runtime helpers. */
#if ENV_SMM
extern struct global_nvs *gnvs;
#endif

/* Entry point for SMM modules. */
asmlinkage void smm_handler_start(void *params);

/* Retrieve SMM save state for a given CPU. WARNING: This does not take into
 * account CPUs which are configured to not save their state to RAM. */
void *smm_get_save_state(int cpu);

/* Returns true if the region overlaps with the SMM */
bool smm_region_overlaps_handler(const struct region *r);

/* Returns true if the memory pointed to overlaps with SMM reserved memory. */
static inline bool smm_points_to_smram(const void *ptr, const size_t len)
{
	const struct region r = {(uintptr_t)ptr, len};

	return smm_region_overlaps_handler(&r);
}

/* SMM Module Loading API */

/* The smm_loader_params structure provides direction to the SMM loader:
 * - num_cpus - number of concurrent cpus in handler needing stack
 *                           optional for setting up relocation handler.
 * - cpu_save_state_size - the SMM save state size per cpu
 * - num_concurrent_save_states - number of concurrent cpus needing save state
 *                                space
 * - handler - optional handler to call. Only used during SMM relocation setup.
 * - runtime - this field is a result only. The SMM runtime location is filled
 *             into this field so the code doing the loading can manipulate the
 *             runtime's assumptions. e.g. updating the APIC id to CPU map to
 *             handle sparse APIC id space.
 */
struct smm_loader_params {
	size_t num_cpus;

	size_t cpu_save_state_size;
	size_t num_concurrent_save_states;

	smm_handler_t handler;
};

/* All of these return 0 on success, < 0 on failure. */
int smm_setup_stack(const uintptr_t perm_smbase, const size_t perm_smram_size,
		    const unsigned int total_cpus, const size_t stack_size);
int smm_setup_relocation_handler(struct smm_loader_params *params);
int smm_load_module(uintptr_t smram_base, size_t smram_size, struct smm_loader_params *params);

u32 smm_get_cpu_smbase(unsigned int cpu_num);

/* Backup and restore default SMM region. */
void *backup_default_smm_area(void);
void restore_default_smm_area(void *smm_save_area);

/*
 * Fills in the arguments for the entire SMM region covered by chipset
 * protections. e.g. TSEG.
 */
void smm_region(uintptr_t *start, size_t *size);

static inline void aseg_region(uintptr_t *start, size_t *size)
{
	*start = SMM_BASE;
	*size = SMM_DEFAULT_SIZE; /* SMM_CODE_SEGMENT_SIZE ? */
}

enum {
	/* SMM handler area. */
	SMM_SUBREGION_HANDLER,
	/* SMM cache region. */
	SMM_SUBREGION_CACHE,
	/* Chipset specific area. */
	SMM_SUBREGION_CHIPSET,
	/* Total sub regions supported. */
	SMM_SUBREGION_NUM,
};

/* Fills in the start and size for the requested SMM subregion. Returns
 * 0 on success, < 0 on failure. */
int smm_subregion(int sub, uintptr_t *start, size_t *size);

/* Print the SMM memory layout on console. */
void smm_list_regions(void);

#define SMM_REVISION_OFFSET_FROM_TOP (0x8000 - 0x7efc)
/* Return the SMM save state revision. The revision can be fetched from the smm savestate
   which is always at the same offset downward from the top of the save state. */
uint32_t smm_revision(void);
/* Returns the PM ACPI SMI port. On Intel systems this typically not configurable (APM_CNT, 0xb2).
   On AMD systems it is sometimes configurable. */
uint16_t pm_acpi_smi_cmd_port(void);

const volatile struct smm_pci_resource_info *smm_get_pci_resource_store(void);

void smm_pci_get_stored_resources(const volatile struct smm_pci_resource_info **out_slots,
				  size_t *out_size);
/* Weak handler function to store PCI BARs. */
void smm_mainboard_pci_resource_store_init(struct smm_pci_resource_info *slots, size_t size);
/* Helper function to fill BARs from an array of device pointers. */
bool smm_pci_resource_store_fill_resources(struct smm_pci_resource_info *slots, size_t num_slots,
					   const struct device **devices, size_t num_devices);

void smm_pci_resource_store_init(struct smm_runtime *smm_runtime);

#endif /* CPU_X86_SMM_H */