blob: d888e4410b4fe144c8c864f08704bd2e9c951303 [file] [log] [blame]
Stefan Reinauer269563a2009-01-19 21:20:22 +00001/*
2 * This file is part of the coreboot project.
3 *
Stefan Reinauerc35a4512009-10-24 17:59:36 +00004 * Copyright (C) 2008-2009 coresystems GmbH
Stefan Reinauer269563a2009-01-19 21:20:22 +00005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Stefan Reinauer269563a2009-01-19 21:20:22 +000015 */
16
17#include <arch/io.h>
Aaron Durbin64031672018-04-21 14:45:32 -060018#include <compiler.h>
Stefan Reinauer269563a2009-01-19 21:20:22 +000019#include <console/console.h>
20#include <cpu/x86/cache.h>
21#include <cpu/x86/smm.h>
22
Martin Roth0fa92b32017-06-24 13:53:20 -060023#if IS_ENABLED(CONFIG_SPI_FLASH_SMM)
David Hendricksbb0d5ef2014-06-19 15:39:29 -070024#include <spi-generic.h>
25#endif
26
27static int do_driver_init = 1;
28
Stefan Reinauer269563a2009-01-19 21:20:22 +000029typedef enum { SMI_LOCKED, SMI_UNLOCKED } smi_semaphore;
30
31/* SMI multiprocessing semaphore */
Stefan Reinauer6a001132017-07-13 02:20:27 +020032static __attribute__((aligned(4))) volatile smi_semaphore smi_handler_status
Lee Leahy8bad6d22017-03-15 14:15:38 -070033 = SMI_UNLOCKED;
Stefan Reinauer269563a2009-01-19 21:20:22 +000034
35static int smi_obtain_lock(void)
36{
37 u8 ret = SMI_LOCKED;
38
39 asm volatile (
40 "movb %2, %%al\n"
41 "xchgb %%al, %1\n"
42 "movb %%al, %0\n"
43 : "=g" (ret), "=m" (smi_handler_status)
44 : "g" (SMI_LOCKED)
45 : "eax"
46 );
47
48 return (ret == SMI_UNLOCKED);
49}
50
Sven Schnellebfe8e512011-06-14 20:55:54 +020051void smi_release_lock(void)
Stefan Reinauer269563a2009-01-19 21:20:22 +000052{
53 asm volatile (
54 "movb %1, %%al\n"
55 "xchgb %%al, %0\n"
56 : "=m" (smi_handler_status)
57 : "g" (SMI_UNLOCKED)
58 : "eax"
59 );
60}
61
62#define LAPIC_ID 0xfee00020
63static inline __attribute__((always_inline)) unsigned long nodeid(void)
64{
65 return (*((volatile unsigned long *)(LAPIC_ID)) >> 24);
66}
67
Stefan Reinauer269563a2009-01-19 21:20:22 +000068void io_trap_handler(int smif)
69{
Stefan Reinauer3b387452009-03-06 19:52:36 +000070 /* If a handler function handled a given IO trap, it
71 * shall return a non-zero value
72 */
Elyes HAOUAS2765a892016-09-01 19:44:56 +020073 printk(BIOS_DEBUG, "SMI function trap 0x%x: ", smif);
Stefan Reinauer3b387452009-03-06 19:52:36 +000074
75 if (southbridge_io_trap_handler(smif))
76 return;
77
78 if (mainboard_io_trap_handler(smif))
79 return;
80
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000081 printk(BIOS_DEBUG, "Unknown function\n");
Stefan Reinauer269563a2009-01-19 21:20:22 +000082}
83
84/**
85 * @brief Set the EOS bit
86 */
87static void smi_set_eos(void)
88{
89 southbridge_smi_set_eos();
90}
91
Stefan Reinauercadc5452010-12-18 23:29:37 +000092static u32 pci_orig;
93
94/**
95 * @brief Backup PCI address to make sure we do not mess up the OS
96 */
97static void smi_backup_pci_address(void)
98{
99 pci_orig = inl(0xcf8);
100}
101
102/**
103 * @brief Restore PCI address previously backed up
104 */
105static void smi_restore_pci_address(void)
106{
107 outl(pci_orig, 0xcf8);
108}
109
Stefan Reinauer01327d12015-07-30 16:28:44 -0700110static inline void *smm_save_state(uintptr_t base, int arch_offset, int node)
Aaron Durbin62f100b2012-11-07 12:27:29 -0600111{
112 base += SMM_SAVE_STATE_BEGIN(arch_offset) - (node * 0x400);
113 return (void *)base;
114}
115
Stefan Reinauer269563a2009-01-19 21:20:22 +0000116/**
117 * @brief Interrupt handler for SMI#
118 *
119 * @param smm_revision revision of the smm state save map
120 */
121
122void smi_handler(u32 smm_revision)
123{
Stefan Reinauer269563a2009-01-19 21:20:22 +0000124 unsigned int node;
125 smm_state_save_area_t state_save;
Aaron Durbin62f100b2012-11-07 12:27:29 -0600126 u32 smm_base = 0xa0000; /* ASEG */
Stefan Reinauer269563a2009-01-19 21:20:22 +0000127
128 /* Are we ok to execute the handler? */
Stefan Reinauerc35a4512009-10-24 17:59:36 +0000129 if (!smi_obtain_lock()) {
130 /* For security reasons we don't release the other CPUs
131 * until the CPU with the lock is actually done
132 */
Rudolf Marek7f762902011-07-02 16:03:24 +0200133 while (smi_handler_status == SMI_LOCKED) {
134 asm volatile (
Lee Leahyc5917072017-03-15 16:38:51 -0700135 ".byte 0xf3, 0x90\n" /* hint a CPU we are in
136 * spinlock (PAUSE
137 * instruction, REP NOP)
138 */
Rudolf Marek7f762902011-07-02 16:03:24 +0200139 );
140 }
Stefan Reinauer269563a2009-01-19 21:20:22 +0000141 return;
Stefan Reinauerc35a4512009-10-24 17:59:36 +0000142 }
Stefan Reinauer269563a2009-01-19 21:20:22 +0000143
Stefan Reinauercadc5452010-12-18 23:29:37 +0000144 smi_backup_pci_address();
145
Lee Leahy8bad6d22017-03-15 14:15:38 -0700146 node = nodeid();
Stefan Reinauer269563a2009-01-19 21:20:22 +0000147
Stefan Reinauerc35a4512009-10-24 17:59:36 +0000148 console_init();
Stefan Reinauer269563a2009-01-19 21:20:22 +0000149
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000150 printk(BIOS_SPEW, "\nSMI# #%d\n", node);
Stefan Reinauer269563a2009-01-19 21:20:22 +0000151
152 switch (smm_revision) {
Stefan Reinauer881a5532010-02-22 09:32:33 +0000153 case 0x00030002:
Stefan Reinauer269563a2009-01-19 21:20:22 +0000154 case 0x00030007:
155 state_save.type = LEGACY;
Aaron Durbin62f100b2012-11-07 12:27:29 -0600156 state_save.legacy_state_save =
Patrick Rudolpha4677e42017-06-10 08:58:00 +0200157 smm_save_state(smm_base,
158 SMM_LEGACY_ARCH_OFFSET, node);
Stefan Reinauer269563a2009-01-19 21:20:22 +0000159 break;
160 case 0x00030100:
161 state_save.type = EM64T;
Aaron Durbin62f100b2012-11-07 12:27:29 -0600162 state_save.em64t_state_save =
Patrick Rudolpha4677e42017-06-10 08:58:00 +0200163 smm_save_state(smm_base,
164 SMM_EM64T_ARCH_OFFSET, node);
Patrick Georgi20e2f3c2014-08-09 20:52:21 +0200165 break;
Aaron Durbin62f100b2012-11-07 12:27:29 -0600166 case 0x00030101: /* SandyBridge, IvyBridge, and Haswell */
Duncan Laurie51cb26d2012-06-23 15:22:43 -0700167 state_save.type = EM64T101;
168 state_save.em64t101_state_save =
Aaron Durbin62f100b2012-11-07 12:27:29 -0600169 smm_save_state(smm_base,
Lee Leahya07d0dd2017-03-15 14:25:22 -0700170 SMM_EM64T101_ARCH_OFFSET, node);
Stefan Reinauer269563a2009-01-19 21:20:22 +0000171 break;
172 case 0x00030064:
173 state_save.type = AMD64;
Aaron Durbin62f100b2012-11-07 12:27:29 -0600174 state_save.amd64_state_save =
Patrick Rudolpha4677e42017-06-10 08:58:00 +0200175 smm_save_state(smm_base,
176 SMM_AMD64_ARCH_OFFSET, node);
Stefan Reinauer269563a2009-01-19 21:20:22 +0000177 break;
178 default:
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000179 printk(BIOS_DEBUG, "smm_revision: 0x%08x\n", smm_revision);
180 printk(BIOS_DEBUG, "SMI# not supported on your CPU\n");
Stefan Reinauer269563a2009-01-19 21:20:22 +0000181 /* Don't release lock, so no further SMI will happen,
182 * if we don't handle it anyways.
183 */
184 return;
185 }
186
David Hendricksbb0d5ef2014-06-19 15:39:29 -0700187 /* Allow drivers to initialize variables in SMM context. */
188 if (do_driver_init) {
Martin Roth0fa92b32017-06-24 13:53:20 -0600189#if IS_ENABLED(CONFIG_SPI_FLASH_SMM)
David Hendricksbb0d5ef2014-06-19 15:39:29 -0700190 spi_init();
191#endif
192 do_driver_init = 0;
193 }
194
Stefan Reinauer92b85aa2010-02-22 14:55:16 +0000195 /* Call chipset specific SMI handlers. */
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +0200196 cpu_smi_handler(node, &state_save);
197 northbridge_smi_handler(node, &state_save);
198 southbridge_smi_handler(node, &state_save);
Stefan Reinauer269563a2009-01-19 21:20:22 +0000199
Stefan Reinauercadc5452010-12-18 23:29:37 +0000200 smi_restore_pci_address();
201
Stefan Reinauer269563a2009-01-19 21:20:22 +0000202 smi_release_lock();
Stefan Reinauer269563a2009-01-19 21:20:22 +0000203
204 /* De-assert SMI# signal to allow another SMI */
205 smi_set_eos();
206}
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +0200207
208/* Provide a default implementation for all weak handlers so that relocation
209 * entries in the modules make sense. Without default implementations the
210 * weak relocations w/o a symbol have a 0 address which is where the modules
211 * are linked at. */
Aaron Durbin64031672018-04-21 14:45:32 -0600212int __weak mainboard_io_trap_handler(int smif) { return 0; }
213void __weak cpu_smi_handler(unsigned int node,
Lee Leahyc5917072017-03-15 16:38:51 -0700214 smm_state_save_area_t *state_save) {}
Aaron Durbin64031672018-04-21 14:45:32 -0600215void __weak northbridge_smi_handler(unsigned int node,
Lee Leahyc5917072017-03-15 16:38:51 -0700216 smm_state_save_area_t *state_save) {}
Aaron Durbin64031672018-04-21 14:45:32 -0600217void __weak southbridge_smi_handler(unsigned int node,
Lee Leahyc5917072017-03-15 16:38:51 -0700218 smm_state_save_area_t *state_save) {}
Aaron Durbin64031672018-04-21 14:45:32 -0600219void __weak mainboard_smi_gpi(u32 gpi_sts) {}
220int __weak mainboard_smi_apmc(u8 data) { return 0; }
221void __weak mainboard_smi_sleep(u8 slp_typ) {}