summaryrefslogtreecommitdiff
path: root/src/include/cpu/x86/smm.h
blob: df7e3de5a67a4861513138b143e9260ea868c123 (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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2008-2009 coresystems GmbH
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

/* AMD64 SMM State-Save Area
 * starts @ 0x7e00
 */

#ifndef CPU_X86_SMM_H
#define CPU_X86_SMM_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))

#include <arch/cpu.h>
#include <types.h>
typedef struct {
	u16	es_selector;
	u16	es_attributes;
	u32	es_limit;
	u64	es_base;

	u16	cs_selector;
	u16	cs_attributcs;
	u32	cs_limit;
	u64	cs_base;

	u16	ss_selector;
	u16	ss_attributss;
	u32	ss_limit;
	u64	ss_base;

	u16	ds_selector;
	u16	ds_attributds;
	u32	ds_limit;
	u64	ds_base;

	u16	fs_selector;
	u16	fs_attributfs;
	u32	fs_limit;
	u64	fs_base;

	u16	gs_selector;
	u16	gs_attributgs;
	u32	gs_limit;
	u64	gs_base;

	u8	reserved0[4];
	u16	gdtr_limit;
	u8	reserved1[2];
	u64	gdtr_base;

	u16	ldtr_selector;
	u16	ldtr_attributes;
	u32	ldtr_limit;
	u64	ldtr_base;

	u8	reserved2[4];
	u16	idtr_limit;
	u8	reserved3[2];
	u64	idtr_base;

	u16	tr_selector;
	u16	tr_attributes;
	u32	tr_limit;
	u64	tr_base;

	u8	reserved4[40];

	u8	io_restart;
	u8	autohalt_restart;

	u8	reserved5[6];

	u64	efer;

	u8	reserved6[36];

	u32	smm_revision;
	u32	smbase;

	u8	reserved7[68];

	u64	cr4;
	u64	cr3;
	u64	cr0;
	u64	dr7;
	u64	dr6;

	u64	rflags;
	u64	rip;
	u64	r15;
	u64	r14;
	u64	r13;
	u64	r12;
	u64	r11;
	u64	r10;
	u64	r9;
	u64	r8;

	u64	rdi;
	u64	rsi;
	u64	rpb;
	u64	rsp;
	u64	rbx;
	u64	rdx;
	u64	rcx;
	u64	rax;
} __attribute__((packed)) amd64_smm_state_save_area_t;


/* Intel Core 2 (EM64T) SMM State-Save Area
 * starts @ 0x7d00
 */
typedef struct {
	u8	reserved0[208];

	u32	gdtr_upper_base;
	u32	ldtr_upper_base;
	u32	idtr_upper_base;

	u8	reserved1[4];

	u64	io_rdi;
	u64	io_rip;
	u64	io_rcx;
	u64	io_rsi;
	u64	cr4;

	u8	reserved2[68];

	u64	gdtr_base;
	u64	idtr_base;
	u64	ldtr_base;

	u8	reserved3[84];

	u32	smm_revision;
	u32	smbase;

	u16	io_restart;
	u16	autohalt_restart;

	u8	reserved4[24];

	u64	r15;
	u64	r14;
	u64	r13;
	u64	r12;
	u64	r11;
	u64	r10;
	u64	r9;
	u64	r8;

	u64	rax;
	u64	rcx;
	u64	rdx;
	u64	rbx;

	u64	rsp;
	u64	rbp;
	u64	rsi;
	u64	rdi;


	u64	io_mem_addr;
	u32	io_misc_info;

	u32	es_sel;
	u32	cs_sel;
	u32	ss_sel;
	u32	ds_sel;
	u32	fs_sel;
	u32	gs_sel;

	u32	ldtr_sel;
	u32	tr_sel;

	u64	dr7;
	u64	dr6;
	u64	rip;
	u64	efer;
	u64	rflags;

	u64	cr3;
	u64	cr0;
} __attribute__((packed)) em64t_smm_state_save_area_t;


/* Intel Revision 30101 SMM State-Save Area
 * The following processor architectures use this:
 * - SandyBridge
 * - IvyBridge
 * - Haswell
 */
#define SMM_EM64T101_ARCH_OFFSET 0x7c00
#define SMM_EM64T101_SAVE_STATE_OFFSET \
	SMM_SAVE_STATE_BEGIN(SMM_EM64T101_ARCH_OFFSET)
typedef struct {
	u8	reserved0[256];
	u8	reserved1[208];

	u32	gdtr_upper_base;
	u32	ldtr_upper_base;
	u32	idtr_upper_base;

	u32	io_cf8;

	u64	io_rdi;
	u64	io_rip;
	u64	io_rcx;
	u64	io_rsi;

	u8	reserved2[52];
	u32	shutdown_auto_restart;
	u8	reserved3[8];
	u32	cr4;

	u8	reserved4[72];

	u32	gdtr_base;
	u8	reserved5[4];
	u32	idtr_base;
	u8	reserved6[4];
	u32	ldtr_base;

	u8	reserved7[56];
	/* EPTP fields are only on Haswell according to BWGs, but Intel was
	 * wise and reused the same revision number. */
	u64	eptp;
	u32	eptp_en;
	u32	cs_base;
	u8	reserved8[4];
	u32	iedbase;

	u8	reserved9[8];

	u32	smbase;
	u32	smm_revision;

	u16	io_restart;
	u16	autohalt_restart;

	u8	reserved10[24];

	u64	r15;
	u64	r14;
	u64	r13;
	u64	r12;
	u64	r11;
	u64	r10;
	u64	r9;
	u64	r8;

	u64	rax;
	u64	rcx;
	u64	rdx;
	u64	rbx;

	u64	rsp;
	u64	rbp;
	u64	rsi;
	u64	rdi;


	u64	io_mem_addr;
	u32	io_misc_info;

	u32	es_sel;
	u32	cs_sel;
	u32	ss_sel;
	u32	ds_sel;
	u32	fs_sel;
	u32	gs_sel;

	u32	ldtr_sel;
	u32	tr_sel;

	u64	dr7;
	u64	dr6;
	u64	rip;
	u64	efer;
	u64	rflags;

	u64	cr3;
	u64	cr0;
} __attribute__((packed)) em64t101_smm_state_save_area_t;


/* Legacy x86 SMM State-Save Area
 * starts @ 0x7e00
 */

typedef struct {
	u8	reserved0[248];
	u32	smbase;
	u32	smm_revision;
	u16	io_restart;
	u16	autohalt_restart;
	u8	reserved1[132];
	u32	gdtbase;
	u8	reserved2[8];
	u32	idtbase;
	u8	reserved3[16];
	u32	es;
	u32	cs;
	u32	ss;
	u32	ds;
	u32	fs;
	u32	gs;
	u32	ldtbase;
	u32	tr;
	u32	dr7;
	u32	dr6;
	u32	eax;
	u32	ecx;
	u32	edx;
	u32	ebx;
	u32	esp;
	u32	ebp;
	u32	esi;
	u32	edi;
	u32	eip;
	u32	eflags;
	u32	cr3;
	u32	cr0;
} __attribute__((packed)) legacy_smm_state_save_area_t;

typedef enum {
	AMD64,
	EM64T,
	EM64T101,
	LEGACY
} save_state_type_t;


typedef struct {
	save_state_type_t type;
	union {
	amd64_smm_state_save_area_t *amd64_state_save;
	em64t_smm_state_save_area_t *em64t_state_save;
	em64t101_smm_state_save_area_t *em64t101_state_save;
	legacy_smm_state_save_area_t *legacy_state_save;
	};
} smm_state_save_area_t;

#define APM_CNT		0xb2
#define APM_CNT_CST_CONTROL	0x85
#define APM_CNT_PST_CONTROL	0x80
#define APM_CNT_ACPI_DISABLE	0x1e
#define APM_CNT_ACPI_ENABLE	0xe1
#define APM_CNT_MBI_UPDATE	0xeb
#define APM_CNT_GNVS_UPDATE	0xea
#define APM_STS		0xb3

/* SMI handler function prototypes */
void smi_handler(u32 smm_revision);

void io_trap_handler(int smif);
int southbridge_io_trap_handler(int smif);
int __attribute__((weak)) mainboard_io_trap_handler(int smif);

void southbridge_smi_set_eos(void);

#if CONFIG_SMM_MODULES
void cpu_smi_handler(void);
void northbridge_smi_handler(void);
void southbridge_smi_handler(void);
void mainboard_smi_gpi(u16 gpi_sts);
int  mainboard_smi_apmc(u8 data);
void mainboard_smi_sleep(u8 slp_typ);
#else
void __attribute__((weak)) cpu_smi_handler(unsigned int node, smm_state_save_area_t *state_save);
void __attribute__((weak)) northbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save);
void __attribute__((weak)) southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save);

void __attribute__((weak)) mainboard_smi_gpi(u16 gpi_sts);
int __attribute__((weak)) mainboard_smi_apmc(u8 data);
void __attribute__((weak)) mainboard_smi_sleep(u8 slp_typ);
#endif /* CONFIG_SMM_MODULES */

#if !CONFIG_SMM_TSEG
void smi_release_lock(void);
#define tseg_relocate(ptr)
#elif CONFIG_SMM_MODULES
#define tseg_relocate(ptr)
#define smi_get_tseg_base() 0
#else
/* Return address of TSEG base */
u32 smi_get_tseg_base(void);
/* Adjust pointer with TSEG base */
void tseg_relocate(void **ptr);
#endif

/* Get PMBASE address */
u16 smm_get_pmbase(void);

#if CONFIG_SMM_MODULES

struct smm_runtime {
	u32 smbase;
	u32 save_state_size;
	/* 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 deafult 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. */
	u8 apic_id_to_cpu[CONFIG_MAX_CPUS];
} __attribute__ ((packed));

typedef void asmlinkage (*smm_handler_t)(void *arg, int cpu,
                                         const struct smm_runtime *runtime);

#ifdef __SMM__
/* SMM Runtime helpers. */

/* Entry point for SMM modules. */
void smm_handler_start(void *arg, int cpu, const struct smm_runtime *runtime);

/* 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);

#else
/* SMM Module Loading API */

/* Ths smm_loader_params structure provides direction to the SMM loader:
 * - stack_top - optional external stack provided to loader. It must be at
 *               least per_cpu_stack_size * num_concurrent_stacks in size.
 * - per_cpu_stack_size - stack size per cpu for smm modules.
 * - num_concurrent_stacks - number of concurrent cpus in handler needing stack
 *                           optional for setting up relocation handler.
 * - per_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.
 * - handler_arg - optional argument to handler for SMM relocation setup. For
 *                 loading the SMM module, the handler_arg is filled in with
 *                 the address of the module's parameters (if present).
 * - 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 {
	void *stack_top;
	int per_cpu_stack_size;
	int num_concurrent_stacks;

	int per_cpu_save_state_size;
	int num_concurrent_save_states;

	smm_handler_t handler;
	void *handler_arg;

	struct smm_runtime *runtime;
};

/* Both of these return 0 on success, < 0 on failure. */
int smm_setup_relocation_handler(struct smm_loader_params *params);
int smm_load_module(void *smram, int size, struct smm_loader_params *params);
#endif /* __SMM__ */
#endif /* CONFIG_SMM_MODULES */

#endif