Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / smm.c
1 // System Management Mode support (on emulators)
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2006 Fabrice Bellard
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "pci.h" // pci_config_writel
9 #include "util.h" // wbinvd
10 #include "config.h" // CONFIG_*
11 #include "ioport.h" // outb
12 #include "pci_ids.h" // PCI_VENDOR_ID_INTEL
13
14 ASM32FLAT(
15     ".global smm_relocation_start\n"
16     ".global smm_relocation_end\n"
17     ".global smm_code_start\n"
18     ".global smm_code_end\n"
19     "  .code16\n"
20
21     /* code to relocate SMBASE to 0xa0000 */
22     "smm_relocation_start:\n"
23     "  mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7efc, %ebx\n"
24     "  addr32 mov (%ebx), %al\n"  /* revision ID to see if x86_64 or x86 */
25     "  cmp $0x64, %al\n"
26     "  je 1f\n"
27     "  mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7ef8, %ebx\n"
28     "  jmp 2f\n"
29     "1:\n"
30     "  mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7f00, %ebx\n"
31     "2:\n"
32     "  movl $" __stringify(BUILD_SMM_ADDR) " - 0x8000, %eax\n"
33     "  addr32 movl %eax, (%ebx)\n"
34     /* indicate to the BIOS that the SMM code was executed */
35     "  mov $0x00, %al\n"
36     "  movw $" __stringify(PORT_SMI_STATUS) ", %dx\n"
37     "  outb %al, %dx\n"
38     "  rsm\n"
39     "smm_relocation_end:\n"
40
41     /* minimal SMM code to enable or disable ACPI */
42     "smm_code_start:\n"
43     "  movw $" __stringify(PORT_SMI_CMD) ", %dx\n"
44     "  inb %dx, %al\n"
45     "  cmp $0xf0, %al\n"
46     "  jne 1f\n"
47
48     /* ACPI disable */
49     "  mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
50     "  inw %dx, %ax\n"
51     "  andw $~1, %ax\n"
52     "  outw %ax, %dx\n"
53
54     "  jmp 2f\n"
55
56     "1:\n"
57     "  cmp $0xf1, %al\n"
58     "  jne 2f\n"
59
60     /* ACPI enable */
61     "  mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
62     "  inw %dx, %ax\n"
63     "  orw $1, %ax\n"
64     "  outw %ax, %dx\n"
65
66     "2:\n"
67     "  rsm\n"
68     "smm_code_end:\n"
69     "  .code32\n"
70     );
71
72 extern u8 smm_relocation_start, smm_relocation_end;
73 extern u8 smm_code_start, smm_code_end;
74
75 static void
76 smm_save_and_copy(void)
77 {
78     /* save original memory content */
79     memcpy((void *)BUILD_SMM_ADDR, (void *)BUILD_SMM_INIT_ADDR, BUILD_SMM_SIZE);
80
81     /* copy the SMM relocation code */
82     memcpy((void *)BUILD_SMM_INIT_ADDR, &smm_relocation_start,
83            &smm_relocation_end - &smm_relocation_start);
84 }
85
86 static void
87 smm_relocate_and_restore(void)
88 {
89     /* init APM status port */
90     outb(0x01, PORT_SMI_STATUS);
91
92     /* raise an SMI interrupt */
93     outb(0x00, PORT_SMI_CMD);
94
95     /* wait until SMM code executed */
96     while (inb(PORT_SMI_STATUS) != 0x00)
97         ;
98
99     /* restore original memory content */
100     memcpy((void *)BUILD_SMM_INIT_ADDR, (void *)BUILD_SMM_ADDR, BUILD_SMM_SIZE);
101
102     /* copy the SMM code */
103     memcpy((void *)BUILD_SMM_ADDR, &smm_code_start
104            , &smm_code_end - &smm_code_start);
105     wbinvd();
106 }
107
108 #define I440FX_SMRAM    0x72
109 #define PIIX_DEVACTB    0x58
110 #define PIIX_APMC_EN    (1 << 25)
111
112 // This code is hardcoded for PIIX4 Power Management device.
113 static void piix4_apmc_smm_init(struct pci_device *pci, void *arg)
114 {
115     struct pci_device *i440_pci = pci_find_device(PCI_VENDOR_ID_INTEL
116                                                   , PCI_DEVICE_ID_INTEL_82441);
117     if (!i440_pci)
118         return;
119
120     /* check if SMM init is already done */
121     u32 value = pci_config_readl(pci->bdf, PIIX_DEVACTB);
122     if (value & PIIX_APMC_EN)
123         return;
124
125     /* enable the SMM memory window */
126     pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x48);
127
128     smm_save_and_copy();
129
130     /* enable SMI generation when writing to the APMC register */
131     pci_config_writel(pci->bdf, PIIX_DEVACTB, value | PIIX_APMC_EN);
132
133     smm_relocate_and_restore();
134
135     /* close the SMM memory window and enable normal SMM */
136     pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x08);
137 }
138
139 static const struct pci_device_id smm_init_tbl[] = {
140     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
141                piix4_apmc_smm_init),
142
143     PCI_DEVICE_END,
144 };
145
146 void
147 smm_init(void)
148 {
149     if (CONFIG_COREBOOT)
150         // SMM only supported on emulators.
151         return;
152     if (!CONFIG_USE_SMM)
153         return;
154
155     dprintf(3, "init smm\n");
156     pci_find_init_device(smm_init_tbl, NULL);
157 }