Rename __attribute__((packed)) --> __packed
[coreboot.git] / src / cpu / x86 / smm / smihandler.c
blob6999f566e2ebb7314e49a46be3f101c6688bb22e
1 /*
2 * This file is part of the coreboot project.
4 * Copyright (C) 2008-2009 coresystems GmbH
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.
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.
17 #include <arch/io.h>
18 #include <console/console.h>
19 #include <cpu/x86/cache.h>
20 #include <cpu/x86/smm.h>
22 #if CONFIG_SPI_FLASH_SMM
23 #include <spi-generic.h>
24 #endif
26 static int do_driver_init = 1;
28 typedef enum { SMI_LOCKED, SMI_UNLOCKED } smi_semaphore;
30 /* SMI multiprocessing semaphore */
31 static __attribute__((aligned(4))) volatile smi_semaphore smi_handler_status
32 = SMI_UNLOCKED;
34 static int smi_obtain_lock(void)
36 u8 ret = SMI_LOCKED;
38 asm volatile (
39 "movb %2, %%al\n"
40 "xchgb %%al, %1\n"
41 "movb %%al, %0\n"
42 : "=g" (ret), "=m" (smi_handler_status)
43 : "g" (SMI_LOCKED)
44 : "eax"
47 return (ret == SMI_UNLOCKED);
50 void smi_release_lock(void)
52 asm volatile (
53 "movb %1, %%al\n"
54 "xchgb %%al, %0\n"
55 : "=m" (smi_handler_status)
56 : "g" (SMI_UNLOCKED)
57 : "eax"
61 #define LAPIC_ID 0xfee00020
62 static inline __attribute__((always_inline)) unsigned long nodeid(void)
64 return (*((volatile unsigned long *)(LAPIC_ID)) >> 24);
67 void io_trap_handler(int smif)
69 /* If a handler function handled a given IO trap, it
70 * shall return a non-zero value
72 printk(BIOS_DEBUG, "SMI function trap 0x%x: ", smif);
74 if (southbridge_io_trap_handler(smif))
75 return;
77 if (mainboard_io_trap_handler(smif))
78 return;
80 printk(BIOS_DEBUG, "Unknown function\n");
83 /**
84 * @brief Set the EOS bit
86 static void smi_set_eos(void)
88 southbridge_smi_set_eos();
91 static u32 pci_orig;
93 /**
94 * @brief Backup PCI address to make sure we do not mess up the OS
96 static void smi_backup_pci_address(void)
98 pci_orig = inl(0xcf8);
102 * @brief Restore PCI address previously backed up
104 static void smi_restore_pci_address(void)
106 outl(pci_orig, 0xcf8);
109 static inline void *smm_save_state(uintptr_t base, int arch_offset, int node)
111 base += SMM_SAVE_STATE_BEGIN(arch_offset) - (node * 0x400);
112 return (void *)base;
116 * @brief Interrupt handler for SMI#
118 * @param smm_revision revision of the smm state save map
121 void smi_handler(u32 smm_revision)
123 unsigned int node;
124 smm_state_save_area_t state_save;
125 u32 smm_base = 0xa0000; /* ASEG */
127 /* Are we ok to execute the handler? */
128 if (!smi_obtain_lock()) {
129 /* For security reasons we don't release the other CPUs
130 * until the CPU with the lock is actually done
132 while (smi_handler_status == SMI_LOCKED) {
133 asm volatile (
134 ".byte 0xf3, 0x90\n" /* hint a CPU we are in
135 * spinlock (PAUSE
136 * instruction, REP NOP)
140 return;
143 smi_backup_pci_address();
145 node = nodeid();
147 console_init();
149 printk(BIOS_SPEW, "\nSMI# #%d\n", node);
151 switch (smm_revision) {
152 case 0x00030002:
153 case 0x00030007:
154 state_save.type = LEGACY;
155 state_save.legacy_state_save =
156 smm_save_state(smm_base,
157 SMM_LEGACY_ARCH_OFFSET, node);
158 break;
159 case 0x00030100:
160 state_save.type = EM64T;
161 state_save.em64t_state_save =
162 smm_save_state(smm_base,
163 SMM_EM64T_ARCH_OFFSET, node);
164 break;
165 case 0x00030101: /* SandyBridge, IvyBridge, and Haswell */
166 state_save.type = EM64T101;
167 state_save.em64t101_state_save =
168 smm_save_state(smm_base,
169 SMM_EM64T101_ARCH_OFFSET, node);
170 break;
171 case 0x00030064:
172 state_save.type = AMD64;
173 state_save.amd64_state_save =
174 smm_save_state(smm_base,
175 SMM_AMD64_ARCH_OFFSET, node);
176 break;
177 default:
178 printk(BIOS_DEBUG, "smm_revision: 0x%08x\n", smm_revision);
179 printk(BIOS_DEBUG, "SMI# not supported on your CPU\n");
180 /* Don't release lock, so no further SMI will happen,
181 * if we don't handle it anyways.
183 return;
186 /* Allow drivers to initialize variables in SMM context. */
187 if (do_driver_init) {
188 #if CONFIG_SPI_FLASH_SMM
189 spi_init();
190 #endif
191 do_driver_init = 0;
194 /* Call chipset specific SMI handlers. */
195 cpu_smi_handler(node, &state_save);
196 northbridge_smi_handler(node, &state_save);
197 southbridge_smi_handler(node, &state_save);
199 smi_restore_pci_address();
201 smi_release_lock();
203 /* De-assert SMI# signal to allow another SMI */
204 smi_set_eos();
207 /* Provide a default implementation for all weak handlers so that relocation
208 * entries in the modules make sense. Without default implementations the
209 * weak relocations w/o a symbol have a 0 address which is where the modules
210 * are linked at. */
211 int __attribute__((weak)) mainboard_io_trap_handler(int smif) { return 0; }
212 void __attribute__((weak)) cpu_smi_handler(unsigned int node,
213 smm_state_save_area_t *state_save) {}
214 void __attribute__((weak)) northbridge_smi_handler(unsigned int node,
215 smm_state_save_area_t *state_save) {}
216 void __attribute__((weak)) southbridge_smi_handler(unsigned int node,
217 smm_state_save_area_t *state_save) {}
218 void __attribute__((weak)) mainboard_smi_gpi(u32 gpi_sts) {}
219 int __attribute__((weak)) mainboard_smi_apmc(u8 data) { return 0; }
220 void __attribute__((weak)) mainboard_smi_sleep(u8 slp_typ) {}