blob: 7e5289206855a8727575065ca1645bcf53022e33 [file] [log] [blame]
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -04001// System Management Mode support (on emulators)
2//
3// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2006 Fabrice Bellard
5//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05006// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -04007
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -05008#include "pci.h" // pci_config_writel
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -04009#include "util.h" // wbinvd
Kevin O'Connor9521e262008-07-04 13:04:29 -040010#include "config.h" // CONFIG_*
11#include "ioport.h" // outb
Kevin O'Connor2ed2f582008-11-08 15:53:36 -050012#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
Isaku Yamahataaec19c92010-07-20 16:50:46 +090013#include "dev-i440fx.h"
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040014
Kevin O'Connor52a300f2009-12-26 23:32:57 -050015ASM32FLAT(
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040016 ".global smm_relocation_start\n"
17 ".global smm_relocation_end\n"
18 ".global smm_code_start\n"
19 ".global smm_code_end\n"
20 " .code16\n"
21
22 /* code to relocate SMBASE to 0xa0000 */
23 "smm_relocation_start:\n"
Kevin O'Connore682cbc2008-12-06 23:11:56 -050024 " mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7efc, %ebx\n"
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040025 " addr32 mov (%ebx), %al\n" /* revision ID to see if x86_64 or x86 */
26 " cmp $0x64, %al\n"
27 " je 1f\n"
Kevin O'Connore682cbc2008-12-06 23:11:56 -050028 " mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7ef8, %ebx\n"
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040029 " jmp 2f\n"
30 "1:\n"
Kevin O'Connore682cbc2008-12-06 23:11:56 -050031 " mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7f00, %ebx\n"
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040032 "2:\n"
Kevin O'Connore682cbc2008-12-06 23:11:56 -050033 " movl $" __stringify(BUILD_SMM_ADDR) " - 0x8000, %eax\n"
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040034 " addr32 movl %eax, (%ebx)\n"
35 /* indicate to the BIOS that the SMM code was executed */
36 " mov $0x00, %al\n"
Kevin O'Connore682cbc2008-12-06 23:11:56 -050037 " movw $" __stringify(PORT_SMI_STATUS) ", %dx\n"
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040038 " outb %al, %dx\n"
39 " rsm\n"
40 "smm_relocation_end:\n"
41
42 /* minimal SMM code to enable or disable ACPI */
43 "smm_code_start:\n"
Kevin O'Connore682cbc2008-12-06 23:11:56 -050044 " movw $" __stringify(PORT_SMI_CMD) ", %dx\n"
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040045 " inb %dx, %al\n"
46 " cmp $0xf0, %al\n"
47 " jne 1f\n"
48
49 /* ACPI disable */
Kevin O'Connore682cbc2008-12-06 23:11:56 -050050 " mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040051 " inw %dx, %ax\n"
52 " andw $~1, %ax\n"
53 " outw %ax, %dx\n"
54
55 " jmp 2f\n"
56
57 "1:\n"
58 " cmp $0xf1, %al\n"
59 " jne 2f\n"
60
61 /* ACPI enable */
Kevin O'Connore682cbc2008-12-06 23:11:56 -050062 " mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040063 " inw %dx, %ax\n"
64 " orw $1, %ax\n"
65 " outw %ax, %dx\n"
66
67 "2:\n"
68 " rsm\n"
69 "smm_code_end:\n"
70 " .code32\n"
71 );
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040072
73extern u8 smm_relocation_start, smm_relocation_end;
74extern u8 smm_code_start, smm_code_end;
75
76void
Isaku Yamahataaec19c92010-07-20 16:50:46 +090077smm_save_and_copy(void)
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040078{
Kevin O'Connore682cbc2008-12-06 23:11:56 -050079 /* save original memory content */
80 memcpy((void *)BUILD_SMM_ADDR, (void *)BUILD_SMM_INIT_ADDR, BUILD_SMM_SIZE);
81
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040082 /* copy the SMM relocation code */
Kevin O'Connore682cbc2008-12-06 23:11:56 -050083 memcpy((void *)BUILD_SMM_INIT_ADDR, &smm_relocation_start,
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040084 &smm_relocation_end - &smm_relocation_start);
Isaku Yamahataaec19c92010-07-20 16:50:46 +090085}
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040086
Isaku Yamahataaec19c92010-07-20 16:50:46 +090087void
88smm_relocate_and_restore(void)
89{
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040090 /* init APM status port */
Kevin O'Connore682cbc2008-12-06 23:11:56 -050091 outb(0x01, PORT_SMI_STATUS);
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040092
93 /* raise an SMI interrupt */
Kevin O'Connore682cbc2008-12-06 23:11:56 -050094 outb(0x00, PORT_SMI_CMD);
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040095
96 /* wait until SMM code executed */
Kevin O'Connore682cbc2008-12-06 23:11:56 -050097 while (inb(PORT_SMI_STATUS) != 0x00)
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -040098 ;
99
Kevin O'Connore682cbc2008-12-06 23:11:56 -0500100 /* restore original memory content */
101 memcpy((void *)BUILD_SMM_INIT_ADDR, (void *)BUILD_SMM_ADDR, BUILD_SMM_SIZE);
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -0400102
103 /* copy the SMM code */
Kevin O'Connore682cbc2008-12-06 23:11:56 -0500104 memcpy((void *)BUILD_SMM_ADDR, &smm_code_start
105 , &smm_code_end - &smm_code_start);
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -0400106 wbinvd();
Isaku Yamahataaec19c92010-07-20 16:50:46 +0900107}
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -0400108
Isaku Yamahataaec19c92010-07-20 16:50:46 +0900109static const struct pci_device_id smm_init_tbl[] = {
110 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
111 piix4_apmc_smm_init),
112
113 PCI_DEVICE_END,
114};
115
116void
117smm_init(void)
118{
119 if (CONFIG_COREBOOT)
120 // SMM only supported on emulators.
121 return;
122 if (!CONFIG_USE_SMM)
123 return;
124
125 dprintf(3, "init smm\n");
126 pci_find_init_device(smm_init_tbl, NULL);
Kevin O'Connorf7ba6d72008-07-04 05:05:54 -0400127}