blob: 64759b0bd295745aa0771a710938217d735d7229 [file] [log] [blame]
Stefan Reinauerdebb11f2008-10-29 04:46:52 +00001/*
2 * This file is part of the coreboot project.
3 *
Stefan Reinauer36c83402009-03-01 10:16:01 +00004 * Copyright (C) 2008-2009 coresystems GmbH
Stefan Reinauerdebb11f2008-10-29 04:46:52 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Stefan Reinauerdebb11f2008-10-29 04:46:52 +000014 */
15
Stefan Reinauer14e22772010-04-27 06:56:47 +000016/* AMD64 SMM State-Save Area
Stefan Reinauerdebb11f2008-10-29 04:46:52 +000017 * starts @ 0x7e00
18 */
Sven Schnelle180f81e2011-06-28 08:06:18 +020019
20#ifndef CPU_X86_SMM_H
21#define CPU_X86_SMM_H
22
Edward O'Callaghanc4561e22014-06-26 15:02:40 +100023#include <arch/cpu.h>
24#include <types.h>
25
Aaron Durbin1fef1f52012-12-19 17:15:43 -060026#define SMM_DEFAULT_BASE 0x30000
27#define SMM_DEFAULT_SIZE 0x10000
28
Rudolf Marekb5b3b3b2011-07-02 16:36:17 +020029/* used only by C programs so far */
30#define SMM_BASE 0xa0000
31
Aaron Durbin62f100b2012-11-07 12:27:29 -060032#define SMM_ENTRY_OFFSET 0x8000
33#define SMM_SAVE_STATE_BEGIN(x) (SMM_ENTRY_OFFSET + (x))
34
Stefan Reinauerdebb11f2008-10-29 04:46:52 +000035typedef struct {
36 u16 es_selector;
37 u16 es_attributes;
38 u32 es_limit;
39 u64 es_base;
40
41 u16 cs_selector;
42 u16 cs_attributcs;
43 u32 cs_limit;
44 u64 cs_base;
45
46 u16 ss_selector;
47 u16 ss_attributss;
48 u32 ss_limit;
49 u64 ss_base;
50
51 u16 ds_selector;
52 u16 ds_attributds;
53 u32 ds_limit;
54 u64 ds_base;
55
56 u16 fs_selector;
57 u16 fs_attributfs;
58 u32 fs_limit;
59 u64 fs_base;
60
61 u16 gs_selector;
62 u16 gs_attributgs;
63 u32 gs_limit;
64 u64 gs_base;
65
66 u8 reserved0[4];
67 u16 gdtr_limit;
68 u8 reserved1[2];
69 u64 gdtr_base;
70
71 u16 ldtr_selector;
72 u16 ldtr_attributes;
73 u32 ldtr_limit;
74 u64 ldtr_base;
75
76 u8 reserved2[4];
77 u16 idtr_limit;
78 u8 reserved3[2];
79 u64 idtr_base;
80
81 u16 tr_selector;
82 u16 tr_attributes;
83 u32 tr_limit;
84 u64 tr_base;
85
86 u8 reserved4[40];
87
88 u8 io_restart;
89 u8 autohalt_restart;
90
91 u8 reserved5[6];
92
93 u64 efer;
94
95 u8 reserved6[36];
96
97 u32 smm_revision;
98 u32 smbase;
99
100 u8 reserved7[68];
101
102 u64 cr4;
103 u64 cr3;
104 u64 cr0;
105 u64 dr7;
106 u64 dr6;
107
108 u64 rflags;
109 u64 rip;
110 u64 r15;
111 u64 r14;
112 u64 r13;
113 u64 r12;
114 u64 r11;
115 u64 r10;
116 u64 r9;
117 u64 r8;
118
119 u64 rdi;
120 u64 rsi;
121 u64 rpb;
122 u64 rsp;
123 u64 rbx;
124 u64 rdx;
125 u64 rcx;
126 u64 rax;
127} __attribute__((packed)) amd64_smm_state_save_area_t;
128
129
Stefan Reinauer14e22772010-04-27 06:56:47 +0000130/* Intel Core 2 (EM64T) SMM State-Save Area
Stefan Reinauerdebb11f2008-10-29 04:46:52 +0000131 * starts @ 0x7d00
132 */
133typedef struct {
134 u8 reserved0[208];
135
136 u32 gdtr_upper_base;
137 u32 ldtr_upper_base;
138 u32 idtr_upper_base;
139
140 u8 reserved1[4];
141
142 u64 io_rdi;
143 u64 io_rip;
144 u64 io_rcx;
145 u64 io_rsi;
146 u64 cr4;
147
148 u8 reserved2[68];
149
150 u64 gdtr_base;
151 u64 idtr_base;
152 u64 ldtr_base;
153
154 u8 reserved3[84];
155
156 u32 smm_revision;
157 u32 smbase;
158
159 u16 io_restart;
160 u16 autohalt_restart;
161
162 u8 reserved4[24];
163
164 u64 r15;
165 u64 r14;
166 u64 r13;
167 u64 r12;
168 u64 r11;
169 u64 r10;
170 u64 r9;
171 u64 r8;
172
173 u64 rax;
174 u64 rcx;
175 u64 rdx;
176 u64 rbx;
177
178 u64 rsp;
179 u64 rbp;
180 u64 rsi;
181 u64 rdi;
182
183
184 u64 io_mem_addr;
185 u32 io_misc_info;
186
187 u32 es_sel;
188 u32 cs_sel;
189 u32 ss_sel;
190 u32 ds_sel;
191 u32 fs_sel;
192 u32 gs_sel;
193
194 u32 ldtr_sel;
195 u32 tr_sel;
196
197 u64 dr7;
198 u64 dr6;
199 u64 rip;
200 u64 efer;
201 u64 rflags;
202
203 u64 cr3;
204 u64 cr0;
205} __attribute__((packed)) em64t_smm_state_save_area_t;
206
207
Aaron Durbind0520402013-10-21 22:21:12 -0500208/* Intel Revision 30100 SMM State-Save Area
209 * The following processor architectures use this:
210 * - Bay Trail
211 */
212#define SMM_EM64T100_ARCH_OFFSET 0x7c00
213#define SMM_EM64T100_SAVE_STATE_OFFSET \
214 SMM_SAVE_STATE_BEGIN(SMM_EM64T100_ARCH_OFFSET)
215typedef struct {
216 u8 reserved0[256];
217 u8 reserved1[208];
218
219 u32 gdtr_upper_base;
220 u32 ldtr_upper_base;
221 u32 idtr_upper_base;
222
223 u8 reserved2[4];
224
225 u64 io_rdi;
226 u64 io_rip;
227 u64 io_rcx;
228 u64 io_rsi;
229
230 u8 reserved3[64];
231 u32 cr4;
232
233 u8 reserved4[72];
234
235 u32 gdtr_base;
236 u8 reserved5[4];
237 u32 idtr_base;
238 u8 reserved6[4];
239 u32 ldtr_base;
240
241 u8 reserved7[88];
242
243 u32 smbase;
244 u32 smm_revision;
245
246 u16 io_restart;
247 u16 autohalt_restart;
248
249 u8 reserved8[24];
250
251 u64 r15;
252 u64 r14;
253 u64 r13;
254 u64 r12;
255 u64 r11;
256 u64 r10;
257 u64 r9;
258 u64 r8;
259
260 u64 rax;
261 u64 rcx;
262 u64 rdx;
263 u64 rbx;
264
265 u64 rsp;
266 u64 rbp;
267 u64 rsi;
268 u64 rdi;
269
270
271 u64 io_mem_addr;
272 u32 io_misc_info;
273
274 u32 es_sel;
275 u32 cs_sel;
276 u32 ss_sel;
277 u32 ds_sel;
278 u32 fs_sel;
279 u32 gs_sel;
280
281 u32 ldtr_sel;
282 u32 tr_sel;
283
284 u64 dr7;
285 u64 dr6;
286 u64 rip;
287 u64 efer;
288 u64 rflags;
289
290 u64 cr3;
291 u64 cr0;
292} __attribute__((packed)) em64t100_smm_state_save_area_t;
293
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700294/* Intel Revision 30101 SMM State-Save Area
Aaron Durbin62f100b2012-11-07 12:27:29 -0600295 * The following processor architectures use this:
296 * - SandyBridge
297 * - IvyBridge
298 * - Haswell
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700299 */
Aaron Durbin62f100b2012-11-07 12:27:29 -0600300#define SMM_EM64T101_ARCH_OFFSET 0x7c00
301#define SMM_EM64T101_SAVE_STATE_OFFSET \
302 SMM_SAVE_STATE_BEGIN(SMM_EM64T101_ARCH_OFFSET)
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700303typedef struct {
Aaron Durbin62f100b2012-11-07 12:27:29 -0600304 u8 reserved0[256];
305 u8 reserved1[208];
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700306
307 u32 gdtr_upper_base;
308 u32 ldtr_upper_base;
309 u32 idtr_upper_base;
310
311 u32 io_cf8;
312
313 u64 io_rdi;
314 u64 io_rip;
315 u64 io_rcx;
316 u64 io_rsi;
317
Aaron Durbin62f100b2012-11-07 12:27:29 -0600318 u8 reserved2[52];
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700319 u32 shutdown_auto_restart;
Aaron Durbin62f100b2012-11-07 12:27:29 -0600320 u8 reserved3[8];
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700321 u32 cr4;
322
Aaron Durbin62f100b2012-11-07 12:27:29 -0600323 u8 reserved4[72];
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700324
325 u32 gdtr_base;
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700326 u8 reserved5[4];
Aaron Durbin62f100b2012-11-07 12:27:29 -0600327 u32 idtr_base;
328 u8 reserved6[4];
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700329 u32 ldtr_base;
330
Aaron Durbin62f100b2012-11-07 12:27:29 -0600331 u8 reserved7[56];
332 /* EPTP fields are only on Haswell according to BWGs, but Intel was
333 * wise and reused the same revision number. */
334 u64 eptp;
335 u32 eptp_en;
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700336 u32 cs_base;
Aaron Durbin62f100b2012-11-07 12:27:29 -0600337 u8 reserved8[4];
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700338 u32 iedbase;
339
Aaron Durbin62f100b2012-11-07 12:27:29 -0600340 u8 reserved9[8];
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700341
342 u32 smbase;
343 u32 smm_revision;
344
345 u16 io_restart;
346 u16 autohalt_restart;
347
Aaron Durbin62f100b2012-11-07 12:27:29 -0600348 u8 reserved10[24];
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700349
350 u64 r15;
351 u64 r14;
352 u64 r13;
353 u64 r12;
354 u64 r11;
355 u64 r10;
356 u64 r9;
357 u64 r8;
358
359 u64 rax;
360 u64 rcx;
361 u64 rdx;
362 u64 rbx;
363
364 u64 rsp;
365 u64 rbp;
366 u64 rsi;
367 u64 rdi;
368
369
370 u64 io_mem_addr;
371 u32 io_misc_info;
372
373 u32 es_sel;
374 u32 cs_sel;
375 u32 ss_sel;
376 u32 ds_sel;
377 u32 fs_sel;
378 u32 gs_sel;
379
380 u32 ldtr_sel;
381 u32 tr_sel;
382
383 u64 dr7;
384 u64 dr6;
385 u64 rip;
386 u64 efer;
387 u64 rflags;
388
389 u64 cr3;
390 u64 cr0;
391} __attribute__((packed)) em64t101_smm_state_save_area_t;
392
393
Stefan Reinauer14e22772010-04-27 06:56:47 +0000394/* Legacy x86 SMM State-Save Area
Stefan Reinauerdebb11f2008-10-29 04:46:52 +0000395 * starts @ 0x7e00
396 */
397
398typedef struct {
399 u8 reserved0[248];
400 u32 smbase;
401 u32 smm_revision;
402 u16 io_restart;
403 u16 autohalt_restart;
404 u8 reserved1[132];
405 u32 gdtbase;
406 u8 reserved2[8];
407 u32 idtbase;
408 u8 reserved3[16];
409 u32 es;
410 u32 cs;
411 u32 ss;
412 u32 ds;
413 u32 fs;
414 u32 gs;
415 u32 ldtbase;
416 u32 tr;
417 u32 dr7;
418 u32 dr6;
419 u32 eax;
420 u32 ecx;
421 u32 edx;
422 u32 ebx;
423 u32 esp;
424 u32 ebp;
425 u32 esi;
426 u32 edi;
427 u32 eip;
428 u32 eflags;
429 u32 cr3;
430 u32 cr0;
431} __attribute__((packed)) legacy_smm_state_save_area_t;
432
433typedef enum {
434 AMD64,
435 EM64T,
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700436 EM64T101,
Stefan Reinauerdebb11f2008-10-29 04:46:52 +0000437 LEGACY
438} save_state_type_t;
439
440
441typedef struct {
442 save_state_type_t type;
443 union {
444 amd64_smm_state_save_area_t *amd64_state_save;
445 em64t_smm_state_save_area_t *em64t_state_save;
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700446 em64t101_smm_state_save_area_t *em64t101_state_save;
Stefan Reinauerdebb11f2008-10-29 04:46:52 +0000447 legacy_smm_state_save_area_t *legacy_state_save;
448 };
449} smm_state_save_area_t;
450
Sven Schnellef4dc1a72011-06-05 11:33:41 +0200451#define APM_CNT 0xb2
452#define APM_CNT_CST_CONTROL 0x85
453#define APM_CNT_PST_CONTROL 0x80
454#define APM_CNT_ACPI_DISABLE 0x1e
455#define APM_CNT_ACPI_ENABLE 0xe1
456#define APM_CNT_MBI_UPDATE 0xeb
457#define APM_CNT_GNVS_UPDATE 0xea
Duncan Laurie911cedf2013-07-30 16:05:55 -0700458#define APM_CNT_FINALIZE 0xcb
Marc Jones9afc5c02014-09-24 10:53:48 -0600459#define APM_CNT_LEGACY 0xcc
Sven Schnellef4dc1a72011-06-05 11:33:41 +0200460#define APM_STS 0xb3
Stefan Reinauer3b387452009-03-06 19:52:36 +0000461
462/* SMI handler function prototypes */
Stefan Reinauer348a1ba2010-03-17 01:51:11 +0000463void smi_handler(u32 smm_revision);
464
Stefan Reinauerbe7f7982009-03-13 15:42:27 +0000465void io_trap_handler(int smif);
Stefan Reinauer3b387452009-03-06 19:52:36 +0000466int southbridge_io_trap_handler(int smif);
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +0200467int mainboard_io_trap_handler(int smif);
Stefan Reinauer3b387452009-03-06 19:52:36 +0000468
Stefan Reinauer348a1ba2010-03-17 01:51:11 +0000469void southbridge_smi_set_eos(void);
470
Vladimir Serbinenko44cbe102015-05-28 21:09:31 +0200471#if CONFIG_SMM_TSEG
Aaron Durbin50a34642013-01-03 17:38:47 -0600472void cpu_smi_handler(void);
473void northbridge_smi_handler(void);
474void southbridge_smi_handler(void);
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +0200475#else
476void cpu_smi_handler(unsigned int node, smm_state_save_area_t *state_save);
477void northbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save);
478void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save);
Vladimir Serbinenko44cbe102015-05-28 21:09:31 +0200479#endif /* CONFIG_SMM_TSEG */
Duncan Laurie0edc2242013-04-29 15:04:30 -0700480void mainboard_smi_gpi(u32 gpi_sts);
Aaron Durbin50a34642013-01-03 17:38:47 -0600481int mainboard_smi_apmc(u8 data);
482void mainboard_smi_sleep(u8 slp_typ);
Stefan Reinauerbf34e942012-04-27 00:44:04 +0200483
Stefan Reinauer3aa067f2012-04-02 13:24:04 -0700484#if !CONFIG_SMM_TSEG
Sven Schnellebfe8e512011-06-14 20:55:54 +0200485void smi_release_lock(void);
Stefan Reinauer3aa067f2012-04-02 13:24:04 -0700486#endif
Sven Schnelle180f81e2011-06-28 08:06:18 +0200487
Duncan Laurie7f3d4422012-10-03 19:01:57 -0700488/* Get PMBASE address */
489u16 smm_get_pmbase(void);
490
Vladimir Serbinenko44cbe102015-05-28 21:09:31 +0200491#if CONFIG_SMM_TSEG
Aaron Durbin50a34642013-01-03 17:38:47 -0600492
493struct smm_runtime {
494 u32 smbase;
495 u32 save_state_size;
496 /* The apic_id_to_cpu provides a mapping from APIC id to cpu number.
497 * The cpu number is indicated by the index into the array by matching
Martin Roth0cb07e32013-07-09 21:46:01 -0600498 * the default APIC id and value at the index. The stub loader
Aaron Durbin50a34642013-01-03 17:38:47 -0600499 * initializes this array with a 1:1 mapping. If the APIC ids are not
500 * contiguous like the 1:1 mapping it is up to the caller of the stub
501 * loader to adjust this mapping. */
502 u8 apic_id_to_cpu[CONFIG_MAX_CPUS];
503} __attribute__ ((packed));
504
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500505struct smm_module_params {
506 void *arg;
507 int cpu;
508 const struct smm_runtime *runtime;
509};
510
511/* smm_handler_t is called with arg of smm_module_params pointer. */
512typedef void asmlinkage (*smm_handler_t)(void *);
Aaron Durbin50a34642013-01-03 17:38:47 -0600513
514#ifdef __SMM__
515/* SMM Runtime helpers. */
516
517/* Entry point for SMM modules. */
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500518void asmlinkage smm_handler_start(void *params);
Aaron Durbin50a34642013-01-03 17:38:47 -0600519
520/* Retrieve SMM save state for a given CPU. WARNING: This does not take into
521 * account CPUs which are configured to not save their state to RAM. */
522void *smm_get_save_state(int cpu);
523
524#else
525/* SMM Module Loading API */
526
Martin Roth0cb07e32013-07-09 21:46:01 -0600527/* The smm_loader_params structure provides direction to the SMM loader:
Aaron Durbin50a34642013-01-03 17:38:47 -0600528 * - stack_top - optional external stack provided to loader. It must be at
529 * least per_cpu_stack_size * num_concurrent_stacks in size.
530 * - per_cpu_stack_size - stack size per cpu for smm modules.
531 * - num_concurrent_stacks - number of concurrent cpus in handler needing stack
532 * optional for setting up relocation handler.
533 * - per_cpu_save_state_size - the smm save state size per cpu
534 * - num_concurrent_save_states - number of concurrent cpus needing save state
535 * space
536 * - handler - optional handler to call. Only used during SMM relocation setup.
537 * - handler_arg - optional argument to handler for SMM relocation setup. For
538 * loading the SMM module, the handler_arg is filled in with
539 * the address of the module's parameters (if present).
540 * - runtime - this field is a result only. The SMM runtime location is filled
541 * into this field so the code doing the loading can manipulate the
542 * runtime's assumptions. e.g. updating the apic id to cpu map to
543 * handle sparse apic id space.
544 */
545struct smm_loader_params {
546 void *stack_top;
547 int per_cpu_stack_size;
548 int num_concurrent_stacks;
549
550 int per_cpu_save_state_size;
551 int num_concurrent_save_states;
552
553 smm_handler_t handler;
554 void *handler_arg;
555
556 struct smm_runtime *runtime;
557};
558
559/* Both of these return 0 on success, < 0 on failure. */
560int smm_setup_relocation_handler(struct smm_loader_params *params);
561int smm_load_module(void *smram, int size, struct smm_loader_params *params);
562#endif /* __SMM__ */
Vladimir Serbinenko44cbe102015-05-28 21:09:31 +0200563#endif /* CONFIG_SMM_TSEG */
Aaron Durbin50a34642013-01-03 17:38:47 -0600564
Aaron Durbinb4b9eb32014-02-13 10:26:18 -0600565/* Backup and restore default SMM region. */
566void *backup_default_smm_area(void);
567void restore_default_smm_area(void *smm_save_area);
568
Edward O'Callaghanc4561e22014-06-26 15:02:40 +1000569#endif /* CPU_X86_SMM_H */