blob: 55c72597aa44857407c39c2dafba543360410411 [file] [log] [blame]
Kevin O'Connor84ad59a2008-07-04 05:47:26 -04001// Support for generating ACPI tables (on emulators)
Kevin O'Connor276d4a92008-06-11 22:47:01 -04002//
Kevin O'Connore2074bf2010-08-03 21:30:03 -04003// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connor276d4a92008-06-11 22:47:01 -04004// 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'Connor276d4a92008-06-11 22:47:01 -04007
8#include "acpi.h" // struct rsdp_descriptor
9#include "util.h" // memcpy
Kevin O'Connorb3064592012-08-14 21:20:10 -040010#include "byteorder.h" // cpu_to_le16
Kevin O'Connor0cd70052011-07-02 14:04:19 -040011#include "pci.h" // pci_find_init_device
Kevin O'Connor2ed2f582008-11-08 15:53:36 -050012#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
13#include "pci_regs.h" // PCI_INTERRUPT_LINE
Kevin O'Connor4bc49972012-05-13 22:58:08 -040014#include "ioport.h" // inl
Kevin O'Connorf9e4e372013-02-09 19:45:45 -050015#include "config.h" // CONFIG_*
Kevin O'Connorf85e4bc2013-02-19 01:33:45 -050016#include "paravirt.h" // RamSize
Kevin O'Connorf9e4e372013-02-09 19:45:45 -050017#include "dev-q35.h"
Kevin O'Connor276d4a92008-06-11 22:47:01 -040018
19/****************************************************/
20/* ACPI tables init */
21
22/* Table structure from Linux kernel (the ACPI tables are under the
23 BSD license) */
24
Kevin O'Connor276d4a92008-06-11 22:47:01 -040025struct acpi_table_header /* ACPI common table header */
26{
Kevin O'Connord10e4442009-03-01 12:41:20 -050027 ACPI_TABLE_HEADER_DEF
Kevin O'Connore97ca7b2009-06-21 09:10:28 -040028} PACKED;
Kevin O'Connor276d4a92008-06-11 22:47:01 -040029
30/*
31 * ACPI 1.0 Root System Description Table (RSDT)
32 */
Kevin O'Connor9967ab72008-12-18 21:57:33 -050033#define RSDT_SIGNATURE 0x54445352 // RSDT
Kevin O'Connor276d4a92008-06-11 22:47:01 -040034struct rsdt_descriptor_rev1
35{
Kevin O'Connord10e4442009-03-01 12:41:20 -050036 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
Kevin O'Connora9242a22009-10-07 19:42:07 -040037 u32 table_offset_entry[0]; /* Array of pointers to other */
Kevin O'Connord10e4442009-03-01 12:41:20 -050038 /* ACPI tables */
Kevin O'Connore97ca7b2009-06-21 09:10:28 -040039} PACKED;
Kevin O'Connor276d4a92008-06-11 22:47:01 -040040
41/*
42 * ACPI 1.0 Firmware ACPI Control Structure (FACS)
43 */
Kevin O'Connor9967ab72008-12-18 21:57:33 -050044#define FACS_SIGNATURE 0x53434146 // FACS
Kevin O'Connor276d4a92008-06-11 22:47:01 -040045struct facs_descriptor_rev1
46{
Kevin O'Connord10e4442009-03-01 12:41:20 -050047 u32 signature; /* ACPI Signature */
48 u32 length; /* Length of structure, in bytes */
49 u32 hardware_signature; /* Hardware configuration signature */
50 u32 firmware_waking_vector; /* ACPI OS waking vector */
51 u32 global_lock; /* Global Lock */
52 u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */
53 u32 reserved1 : 31; /* Must be 0 */
54 u8 resverved3 [40]; /* Reserved - must be zero */
Kevin O'Connore97ca7b2009-06-21 09:10:28 -040055} PACKED;
Kevin O'Connor276d4a92008-06-11 22:47:01 -040056
57
58/*
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +090059 * Differentiated System Description Table (DSDT)
60 */
61#define DSDT_SIGNATURE 0x54445344 // DSDT
62
63/*
Kevin O'Connor276d4a92008-06-11 22:47:01 -040064 * MADT values and structures
65 */
66
67/* Values for MADT PCATCompat */
68
69#define DUAL_PIC 0
70#define MULTIPLE_APIC 1
71
72
73/* Master MADT */
74
Kevin O'Connor9967ab72008-12-18 21:57:33 -050075#define APIC_SIGNATURE 0x43495041 // APIC
Kevin O'Connor276d4a92008-06-11 22:47:01 -040076struct multiple_apic_table
77{
Kevin O'Connord10e4442009-03-01 12:41:20 -050078 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
79 u32 local_apic_address; /* Physical address of local APIC */
Kevin O'Connor276d4a92008-06-11 22:47:01 -040080#if 0
Kevin O'Connord10e4442009-03-01 12:41:20 -050081 u32 PCATcompat : 1; /* A one indicates system also has dual 8259s */
82 u32 reserved1 : 31;
Kevin O'Connor276d4a92008-06-11 22:47:01 -040083#else
Kevin O'Connord10e4442009-03-01 12:41:20 -050084 u32 flags;
Kevin O'Connor276d4a92008-06-11 22:47:01 -040085#endif
Kevin O'Connore97ca7b2009-06-21 09:10:28 -040086} PACKED;
Kevin O'Connor276d4a92008-06-11 22:47:01 -040087
88
Kevin O'Connor590e5542009-10-08 22:09:02 -040089/* Values for Type in APIC sub-headers */
Kevin O'Connor276d4a92008-06-11 22:47:01 -040090
91#define APIC_PROCESSOR 0
92#define APIC_IO 1
93#define APIC_XRUPT_OVERRIDE 2
94#define APIC_NMI 3
95#define APIC_LOCAL_NMI 4
96#define APIC_ADDRESS_OVERRIDE 5
97#define APIC_IO_SAPIC 6
98#define APIC_LOCAL_SAPIC 7
99#define APIC_XRUPT_SOURCE 8
100#define APIC_RESERVED 9 /* 9 and greater are reserved */
101
102/*
103 * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
104 */
Kevin O'Connor590e5542009-10-08 22:09:02 -0400105#define ACPI_SUB_HEADER_DEF /* Common ACPI sub-structure header */\
Kevin O'Connord10e4442009-03-01 12:41:20 -0500106 u8 type; \
107 u8 length;
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400108
109/* Sub-structures for MADT */
110
111struct madt_processor_apic
112{
Kevin O'Connor590e5542009-10-08 22:09:02 -0400113 ACPI_SUB_HEADER_DEF
Kevin O'Connord10e4442009-03-01 12:41:20 -0500114 u8 processor_id; /* ACPI processor id */
115 u8 local_apic_id; /* Processor's local APIC id */
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400116#if 0
Kevin O'Connord10e4442009-03-01 12:41:20 -0500117 u32 processor_enabled: 1; /* Processor is usable if set */
118 u32 reserved2 : 31; /* Reserved, must be zero */
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400119#else
Kevin O'Connord10e4442009-03-01 12:41:20 -0500120 u32 flags;
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400121#endif
Kevin O'Connore97ca7b2009-06-21 09:10:28 -0400122} PACKED;
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400123
124struct madt_io_apic
125{
Kevin O'Connor590e5542009-10-08 22:09:02 -0400126 ACPI_SUB_HEADER_DEF
Kevin O'Connord10e4442009-03-01 12:41:20 -0500127 u8 io_apic_id; /* I/O APIC ID */
128 u8 reserved; /* Reserved - must be zero */
129 u32 address; /* APIC physical address */
130 u32 interrupt; /* Global system interrupt where INTI
131 * lines start */
Kevin O'Connore97ca7b2009-06-21 09:10:28 -0400132} PACKED;
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400133
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500134struct madt_intsrcovr {
Kevin O'Connor590e5542009-10-08 22:09:02 -0400135 ACPI_SUB_HEADER_DEF
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500136 u8 bus;
137 u8 source;
138 u32 gsi;
139 u16 flags;
140} PACKED;
141
Kenji Kaneshige70986382011-10-10 14:06:17 +0800142struct madt_local_nmi {
143 ACPI_SUB_HEADER_DEF
144 u8 processor_id; /* ACPI processor id */
145 u16 flags; /* MPS INTI flags */
146 u8 lint; /* Local APIC LINT# */
147} PACKED;
148
149
Kevin O'Connorf4343772009-10-08 22:05:21 -0400150/*
Kevin O'Connorf4343772009-10-08 22:05:21 -0400151 * HPET Description Table
152 */
153struct acpi_20_hpet {
154 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
155 u32 timer_block_id;
156 struct acpi_20_generic_address addr;
157 u8 hpet_number;
158 u16 min_tick;
159 u8 page_protect;
160} PACKED;
Kevin O'Connorf4343772009-10-08 22:05:21 -0400161
Jan Kiszkab8a90f52011-08-29 17:50:10 +0200162#define HPET_ID 0x000
163#define HPET_PERIOD 0x004
164
Kevin O'Connor590e5542009-10-08 22:09:02 -0400165/*
166 * SRAT (NUMA topology description) table
167 */
168
169#define SRAT_PROCESSOR 0
170#define SRAT_MEMORY 1
171
172struct system_resource_affinity_table
173{
174 ACPI_TABLE_HEADER_DEF
175 u32 reserved1;
176 u32 reserved2[2];
177} PACKED;
178
179struct srat_processor_affinity
180{
181 ACPI_SUB_HEADER_DEF
182 u8 proximity_lo;
183 u8 local_apic_id;
184 u32 flags;
185 u8 local_sapic_eid;
186 u8 proximity_hi[3];
187 u32 reserved;
188} PACKED;
189
190struct srat_memory_affinity
191{
192 ACPI_SUB_HEADER_DEF
193 u8 proximity[4];
194 u16 reserved1;
195 u32 base_addr_low,base_addr_high;
196 u32 length_low,length_high;
197 u32 reserved2;
198 u32 flags;
199 u32 reserved3[2];
200} PACKED;
201
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400202#include "acpi-dsdt.hex"
203
Kevin O'Connor2929c352009-07-25 13:48:27 -0400204static void
Kevin O'Connora9242a22009-10-07 19:42:07 -0400205build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev)
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400206{
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500207 h->signature = sig;
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400208 h->length = cpu_to_le32(len);
209 h->revision = rev;
Kevin O'Connore52ad392013-02-20 23:48:22 -0500210 memcpy(h->oem_id, BUILD_APPNAME6, 6);
211 memcpy(h->oem_table_id, BUILD_APPNAME4, 4);
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500212 memcpy(h->oem_table_id + 4, (void*)&sig, 4);
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400213 h->oem_revision = cpu_to_le32(1);
Kevin O'Connore52ad392013-02-20 23:48:22 -0500214 memcpy(h->asl_compiler_id, BUILD_APPNAME4, 4);
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400215 h->asl_compiler_revision = cpu_to_le32(1);
Kevin O'Connor523e5a92009-07-04 13:46:33 -0400216 h->checksum -= checksum(h, len);
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400217}
218
Kevin O'Connor6e4583c2011-06-19 10:09:26 -0400219#define PIIX4_ACPI_ENABLE 0xf1
220#define PIIX4_ACPI_DISABLE 0xf0
221#define PIIX4_GPE0_BLK 0xafe0
222#define PIIX4_GPE0_BLK_LEN 4
223
Isaku Yamahata229e8e22012-11-28 10:17:31 +0100224#define PIIX4_PM_INTRRUPT 9 // irq 9
225
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500226static void piix4_fadt_setup(struct pci_device *pci, void *arg)
Kevin O'Connor6e4583c2011-06-19 10:09:26 -0400227{
228 struct fadt_descriptor_rev1 *fadt = arg;
Isaku Yamahata229e8e22012-11-28 10:17:31 +0100229
230 fadt->model = 1;
231 fadt->reserved1 = 0;
232 fadt->sci_int = cpu_to_le16(PIIX4_PM_INTRRUPT);
233 fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
Kevin O'Connor6e4583c2011-06-19 10:09:26 -0400234 fadt->acpi_enable = PIIX4_ACPI_ENABLE;
235 fadt->acpi_disable = PIIX4_ACPI_DISABLE;
Isaku Yamahata229e8e22012-11-28 10:17:31 +0100236 fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
237 fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
238 fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
Kevin O'Connor6e4583c2011-06-19 10:09:26 -0400239 fadt->gpe0_blk = cpu_to_le32(PIIX4_GPE0_BLK);
Isaku Yamahata229e8e22012-11-28 10:17:31 +0100240 fadt->pm1_evt_len = 4;
241 fadt->pm1_cnt_len = 2;
242 fadt->pm_tmr_len = 4;
Kevin O'Connor6e4583c2011-06-19 10:09:26 -0400243 fadt->gpe0_blk_len = PIIX4_GPE0_BLK_LEN;
Isaku Yamahata229e8e22012-11-28 10:17:31 +0100244 fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
245 fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
246 /* WBINVD + PROC_C1 + SLP_BUTTON + RTC_S4 + USE_PLATFORM_CLOCK */
247 fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 7) |
248 (1 << 15));
Kevin O'Connor6e4583c2011-06-19 10:09:26 -0400249}
250
Isaku Yamahata72a590e2012-11-28 10:17:33 +0100251/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500252void ich9_lpc_fadt_setup(struct pci_device *dev, void *arg)
Isaku Yamahata72a590e2012-11-28 10:17:33 +0100253{
254 struct fadt_descriptor_rev1 *fadt = arg;
255
256 fadt->model = 1;
257 fadt->reserved1 = 0;
258 fadt->sci_int = cpu_to_le16(9);
259 fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
260 fadt->acpi_enable = ICH9_ACPI_ENABLE;
261 fadt->acpi_disable = ICH9_ACPI_DISABLE;
262 fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
263 fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
264 fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
265 fadt->gpe0_blk = cpu_to_le32(PORT_ACPI_PM_BASE + ICH9_PMIO_GPE0_STS);
266 fadt->pm1_evt_len = 4;
267 fadt->pm1_cnt_len = 2;
268 fadt->pm_tmr_len = 4;
269 fadt->gpe0_blk_len = ICH9_PMIO_GPE0_BLK_LEN;
270 fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
271 fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
272 /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */
273 fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) |
274 (1 << 7));
275}
276
Isaku Yamahatafe54a532010-07-20 16:37:18 +0900277static const struct pci_device_id fadt_init_tbl[] = {
278 /* PIIX4 Power Management device (for ACPI) */
279 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500280 piix4_fadt_setup),
Isaku Yamahata72a590e2012-11-28 10:17:33 +0100281 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500282 ich9_lpc_fadt_setup),
Isaku Yamahatafe54a532010-07-20 16:37:18 +0900283 PCI_DEVICE_END
284};
285
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900286static void fill_dsdt(struct fadt_descriptor_rev1 *fadt, void *dsdt)
287{
288 if (fadt->dsdt) {
289 free((void *)le32_to_cpu(fadt->dsdt));
290 }
291 fadt->dsdt = cpu_to_le32((u32)dsdt);
292 fadt->checksum -= checksum(fadt, sizeof(*fadt));
293 dprintf(1, "ACPI DSDT=%p\n", dsdt);
294}
295
Kevin O'Connor278b19f2011-06-21 22:41:15 -0400296static void *
297build_fadt(struct pci_device *pci)
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400298{
Kevin O'Connor2929c352009-07-25 13:48:27 -0400299 struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt));
Kevin O'Connor415d4292009-08-30 19:19:31 -0400300 struct facs_descriptor_rev1 *facs = memalign_high(64, sizeof(*facs));
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400301
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900302 if (!fadt || !facs) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500303 warn_noalloc();
Kevin O'Connora9242a22009-10-07 19:42:07 -0400304 return NULL;
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400305 }
306
Kevin O'Connor2929c352009-07-25 13:48:27 -0400307 /* FACS */
Kevin O'Connor2929c352009-07-25 13:48:27 -0400308 memset(facs, 0, sizeof(*facs));
309 facs->signature = FACS_SIGNATURE;
310 facs->length = cpu_to_le32(sizeof(*facs));
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400311
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400312 /* FADT */
313 memset(fadt, 0, sizeof(*fadt));
Kevin O'Connor2929c352009-07-25 13:48:27 -0400314 fadt->firmware_ctrl = cpu_to_le32((u32)facs);
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500315 fadt->dsdt = 0; /* dsdt will be filled later in acpi_setup()
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900316 by fill_dsdt() */
Kevin O'Connor278b19f2011-06-21 22:41:15 -0400317 pci_init_device(fadt_init_tbl, pci, fadt);
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400318
Kevin O'Connora9242a22009-10-07 19:42:07 -0400319 build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1);
320
321 return fadt;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400322}
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400323
Kevin O'Connora9242a22009-10-07 19:42:07 -0400324static void*
325build_madt(void)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400326{
Kevin O'Connor2929c352009-07-25 13:48:27 -0400327 int madt_size = (sizeof(struct multiple_apic_table)
Kevin O'Connora26df9b2009-10-09 09:42:11 -0400328 + sizeof(struct madt_processor_apic) * MaxCountCPUs
Kevin O'Connor2929c352009-07-25 13:48:27 -0400329 + sizeof(struct madt_io_apic)
Kenji Kaneshige70986382011-10-10 14:06:17 +0800330 + sizeof(struct madt_intsrcovr) * 16
331 + sizeof(struct madt_local_nmi));
332
Kevin O'Connor2929c352009-07-25 13:48:27 -0400333 struct multiple_apic_table *madt = malloc_high(madt_size);
334 if (!madt) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500335 warn_noalloc();
Kevin O'Connora9242a22009-10-07 19:42:07 -0400336 return NULL;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400337 }
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500338 memset(madt, 0, madt_size);
339 madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
340 madt->flags = cpu_to_le32(1);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400341 struct madt_processor_apic *apic = (void*)&madt[1];
342 int i;
Kevin O'Connora26df9b2009-10-09 09:42:11 -0400343 for (i=0; i<MaxCountCPUs; i++) {
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500344 apic->type = APIC_PROCESSOR;
345 apic->length = sizeof(*apic);
346 apic->processor_id = i;
347 apic->local_apic_id = i;
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300348 if (apic_id_is_present(apic->local_apic_id))
Kevin O'Connora26df9b2009-10-09 09:42:11 -0400349 apic->flags = cpu_to_le32(1);
350 else
351 apic->flags = cpu_to_le32(0);
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500352 apic++;
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400353 }
Kevin O'Connor2929c352009-07-25 13:48:27 -0400354 struct madt_io_apic *io_apic = (void*)apic;
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500355 io_apic->type = APIC_IO;
356 io_apic->length = sizeof(*io_apic);
Eduardo Habkoste39b9382012-07-25 15:45:29 -0300357 io_apic->io_apic_id = BUILD_IOAPIC_ID;
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500358 io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR);
359 io_apic->interrupt = cpu_to_le32(0);
360
Kevin O'Connord10e4442009-03-01 12:41:20 -0500361 struct madt_intsrcovr *intsrcovr = (void*)&io_apic[1];
Kevin O'Connor56c50892013-02-09 19:25:51 -0500362 if (romfile_loadint("etc/irq0-override", 0)) {
Kevin O'Connorb64db302009-07-29 19:20:03 -0400363 memset(intsrcovr, 0, sizeof(*intsrcovr));
364 intsrcovr->type = APIC_XRUPT_OVERRIDE;
365 intsrcovr->length = sizeof(*intsrcovr);
366 intsrcovr->source = 0;
367 intsrcovr->gsi = 2;
368 intsrcovr->flags = 0; /* conforms to bus specifications */
369 intsrcovr++;
370 }
371 for (i = 1; i < 16; i++) {
Kevin O'Connord8388152013-03-18 20:26:54 -0400372 if (!(BUILD_PCI_IRQS & (1 << i)))
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500373 /* No need for a INT source override structure. */
374 continue;
Kevin O'Connord10e4442009-03-01 12:41:20 -0500375 memset(intsrcovr, 0, sizeof(*intsrcovr));
376 intsrcovr->type = APIC_XRUPT_OVERRIDE;
377 intsrcovr->length = sizeof(*intsrcovr);
378 intsrcovr->source = i;
379 intsrcovr->gsi = i;
380 intsrcovr->flags = 0xd; /* active high, level triggered */
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500381 intsrcovr++;
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500382 }
383
Kenji Kaneshige70986382011-10-10 14:06:17 +0800384 struct madt_local_nmi *local_nmi = (void*)intsrcovr;
385 local_nmi->type = APIC_LOCAL_NMI;
386 local_nmi->length = sizeof(*local_nmi);
387 local_nmi->processor_id = 0xff; /* all processors */
388 local_nmi->flags = 0;
389 local_nmi->lint = 1; /* LINT1 */
390 local_nmi++;
391
392 build_header((void*)madt, APIC_SIGNATURE, (void*)local_nmi - (void*)madt, 1);
Kevin O'Connora9242a22009-10-07 19:42:07 -0400393 return madt;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400394}
395
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400396// Encode a hex value
397static inline char getHex(u32 val) {
398 val &= 0x0f;
399 return (val <= 9) ? ('0' + val) : ('A' + val - 10);
400}
401
402// Encode a length in an SSDT.
403static u8 *
404encodeLen(u8 *ssdt_ptr, int length, int bytes)
405{
406 switch (bytes) {
407 default:
408 case 4: ssdt_ptr[3] = ((length >> 20) & 0xff);
409 case 3: ssdt_ptr[2] = ((length >> 12) & 0xff);
410 case 2: ssdt_ptr[1] = ((length >> 4) & 0xff);
411 ssdt_ptr[0] = (((bytes-1) & 0x3) << 6) | (length & 0x0f);
412 break;
413 case 1: ssdt_ptr[0] = length & 0x3f;
414 }
415 return ssdt_ptr + bytes;
416}
417
Michael S. Tsirkinc736f0a2011-10-04 15:26:19 +0200418#include "ssdt-proc.hex"
Michael S. Tsirkinc736f0a2011-10-04 15:26:19 +0200419
420/* 0x5B 0x83 ProcessorOp PkgLength NameString ProcID */
Paolo Bonzinic8ed45e2012-08-02 15:07:22 +0200421#define PROC_OFFSET_CPUHEX (*ssdt_proc_name - *ssdt_proc_start + 2)
422#define PROC_OFFSET_CPUID1 (*ssdt_proc_name - *ssdt_proc_start + 4)
423#define PROC_OFFSET_CPUID2 (*ssdt_proc_id - *ssdt_proc_start)
424#define PROC_SIZEOF (*ssdt_proc_end - *ssdt_proc_start)
425#define PROC_AML (ssdp_proc_aml + *ssdt_proc_start)
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400426
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200427/* 0x5B 0x82 DeviceOp PkgLength NameString */
428#define PCIHP_OFFSET_HEX (*ssdt_pcihp_name - *ssdt_pcihp_start + 1)
429#define PCIHP_OFFSET_ID (*ssdt_pcihp_id - *ssdt_pcihp_start)
430#define PCIHP_OFFSET_ADR (*ssdt_pcihp_adr - *ssdt_pcihp_start)
431#define PCIHP_OFFSET_EJ0 (*ssdt_pcihp_ej0 - *ssdt_pcihp_start)
432#define PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start)
433#define PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200434#define PCI_SLOTS 32
435
Kevin O'Connor2929c352009-07-25 13:48:27 -0400436#define SSDT_SIGNATURE 0x54445353 // SSDT
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200437#define SSDT_HEADER_LENGTH 36
438
Kevin O'Connor3f8d7352013-02-27 20:46:40 -0500439#include "ssdt-misc.hex"
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200440#include "ssdt-pcihp.hex"
441
442#define PCI_RMV_BASE 0xae0c
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200443
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200444static u8*
445build_notify(u8 *ssdt_ptr, const char *name, int skip, int count,
446 const char *target, int ofs)
447{
448 count -= skip;
449
450 *(ssdt_ptr++) = 0x14; // MethodOp
451 ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*count), 2);
452 memcpy(ssdt_ptr, name, 4);
453 ssdt_ptr += 4;
454 *(ssdt_ptr++) = 0x02; // MethodOp
455
456 int i;
457 for (i = skip; count-- > 0; i++) {
458 *(ssdt_ptr++) = 0xA0; // IfOp
459 ssdt_ptr = encodeLen(ssdt_ptr, 11, 1);
460 *(ssdt_ptr++) = 0x93; // LEqualOp
461 *(ssdt_ptr++) = 0x68; // Arg0Op
462 *(ssdt_ptr++) = 0x0A; // BytePrefix
463 *(ssdt_ptr++) = i;
464 *(ssdt_ptr++) = 0x86; // NotifyOp
465 memcpy(ssdt_ptr, target, 4);
466 ssdt_ptr[ofs] = getHex(i >> 4);
467 ssdt_ptr[ofs + 1] = getHex(i);
468 ssdt_ptr += 4;
469 *(ssdt_ptr++) = 0x69; // Arg1Op
470 }
471 return ssdt_ptr;
472}
473
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200474static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject)
475{
476 ssdt_ptr[PCIHP_OFFSET_HEX] = getHex(slot >> 4);
477 ssdt_ptr[PCIHP_OFFSET_HEX+1] = getHex(slot);
478 ssdt_ptr[PCIHP_OFFSET_ID] = slot;
479 ssdt_ptr[PCIHP_OFFSET_ADR + 2] = slot;
480
481 /* Runtime patching of EJ0: to disable hotplug for a slot,
482 * replace the method name: _EJ0 by EJ0_. */
483 /* Sanity check */
484 if (memcmp(ssdt_ptr + PCIHP_OFFSET_EJ0, "_EJ0", 4)) {
485 warn_internalerror();
486 }
487 if (!eject) {
488 memcpy(ssdt_ptr + PCIHP_OFFSET_EJ0, "EJ0_", 4);
489 }
490}
491
Kevin O'Connora9242a22009-10-07 19:42:07 -0400492static void*
493build_ssdt(void)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400494{
Kevin O'Connora26df9b2009-10-09 09:42:11 -0400495 int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs;
Kevin O'Connor3f8d7352013-02-27 20:46:40 -0500496 int length = (sizeof(ssdp_misc_aml) // _S3_ / _S4_ / _S5_
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200497 + (1+3+4) // Scope(_SB_)
Paolo Bonzinic8ed45e2012-08-02 15:07:22 +0200498 + (acpi_cpus * PROC_SIZEOF) // procs
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200499 + (1+2+5+(12*acpi_cpus)) // NTFY
500 + (6+2+1+(1*acpi_cpus)) // CPON
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200501 + (1+3+4) // Scope(PCI0)
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200502 + ((PCI_SLOTS - 1) * PCIHP_SIZEOF) // slots
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200503 + (1+2+5+(12*(PCI_SLOTS - 1)))); // PCNT
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200504 u8 *ssdt = malloc_high(length);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400505 if (! ssdt) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500506 warn_noalloc();
Kevin O'Connora9242a22009-10-07 19:42:07 -0400507 return NULL;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400508 }
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200509 u8 *ssdt_ptr = ssdt;
510
511 // Copy header and encode fwcfg values in the S3_ / S4_ / S5_ packages
512 int sys_state_size;
513 char *sys_states = romfile_loadfile("etc/system-states", &sys_state_size);
514 if (!sys_states || sys_state_size != 6)
515 sys_states = (char[]){128, 0, 0, 129, 128, 128};
516
Kevin O'Connor3f8d7352013-02-27 20:46:40 -0500517 memcpy(ssdt_ptr, ssdp_misc_aml, sizeof(ssdp_misc_aml));
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200518 if (!(sys_states[3] & 128))
519 ssdt_ptr[acpi_s3_name[0]] = 'X';
520 if (!(sys_states[4] & 128))
521 ssdt_ptr[acpi_s4_name[0]] = 'X';
522 else
523 ssdt_ptr[acpi_s4_pkg[0] + 1] = ssdt[acpi_s4_pkg[0] + 3] = sys_states[4] & 127;
Kevin O'Connor76e58022013-03-06 21:50:09 -0500524
525 // store pci io windows
526 *(u32*)&ssdt_ptr[acpi_pci32_start[0]] = pcimem_start;
527 *(u32*)&ssdt_ptr[acpi_pci32_end[0]] = pcimem_end - 1;
528 if (pcimem64_start) {
529 ssdt_ptr[acpi_pci64_valid[0]] = 1;
530 *(u64*)&ssdt_ptr[acpi_pci64_start[0]] = pcimem64_start;
531 *(u64*)&ssdt_ptr[acpi_pci64_end[0]] = pcimem64_end - 1;
532 *(u64*)&ssdt_ptr[acpi_pci64_length[0]] = pcimem64_end - pcimem64_start;
533 } else {
534 ssdt_ptr[acpi_pci64_valid[0]] = 0;
535 }
536
Kevin O'Connor3f8d7352013-02-27 20:46:40 -0500537 ssdt_ptr += sizeof(ssdp_misc_aml);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400538
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400539 // build Scope(_SB_) header
Kevin O'Connor2929c352009-07-25 13:48:27 -0400540 *(ssdt_ptr++) = 0x10; // ScopeOp
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200541 ssdt_ptr = encodeLen(ssdt_ptr, length - (ssdt_ptr - ssdt), 3);
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400542 *(ssdt_ptr++) = '_';
543 *(ssdt_ptr++) = 'S';
544 *(ssdt_ptr++) = 'B';
Kevin O'Connor2929c352009-07-25 13:48:27 -0400545 *(ssdt_ptr++) = '_';
546
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400547 // build Processor object for each processor
Kevin O'Connor2929c352009-07-25 13:48:27 -0400548 int i;
549 for (i=0; i<acpi_cpus; i++) {
Paolo Bonzinic8ed45e2012-08-02 15:07:22 +0200550 memcpy(ssdt_ptr, PROC_AML, PROC_SIZEOF);
551 ssdt_ptr[PROC_OFFSET_CPUHEX] = getHex(i >> 4);
552 ssdt_ptr[PROC_OFFSET_CPUHEX+1] = getHex(i);
553 ssdt_ptr[PROC_OFFSET_CPUID1] = i;
554 ssdt_ptr[PROC_OFFSET_CPUID2] = i;
555 ssdt_ptr += PROC_SIZEOF;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400556 }
557
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400558 // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}"
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300559 // Arg0 = Processor ID = APIC ID
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200560 ssdt_ptr = build_notify(ssdt_ptr, "NTFY", 0, acpi_cpus, "CP00", 2);
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400561
562 // build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })"
563 *(ssdt_ptr++) = 0x08; // NameOp
564 *(ssdt_ptr++) = 'C';
565 *(ssdt_ptr++) = 'P';
566 *(ssdt_ptr++) = 'O';
567 *(ssdt_ptr++) = 'N';
568 *(ssdt_ptr++) = 0x12; // PackageOp
569 ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*acpi_cpus), 2);
570 *(ssdt_ptr++) = acpi_cpus;
571 for (i=0; i<acpi_cpus; i++)
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300572 *(ssdt_ptr++) = (apic_id_is_present(i)) ? 0x01 : 0x00;
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400573
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200574 // build Scope(PCI0) opcode
575 *(ssdt_ptr++) = 0x10; // ScopeOp
576 ssdt_ptr = encodeLen(ssdt_ptr, length - (ssdt_ptr - ssdt), 3);
577 *(ssdt_ptr++) = 'P';
578 *(ssdt_ptr++) = 'C';
579 *(ssdt_ptr++) = 'I';
580 *(ssdt_ptr++) = '0';
581
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200582 // build Device object for each slot
583 u32 rmvc_pcrm = inl(PCI_RMV_BASE);
584 for (i=1; i<PCI_SLOTS; i++) {
585 u32 eject = rmvc_pcrm & (0x1 << i);
586 memcpy(ssdt_ptr, PCIHP_AML, PCIHP_SIZEOF);
587 patch_pcihp(i, ssdt_ptr, eject != 0);
588 ssdt_ptr += PCIHP_SIZEOF;
589 }
590
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200591 ssdt_ptr = build_notify(ssdt_ptr, "PCNT", 1, PCI_SLOTS, "S00_", 1);
592
Kevin O'Connora9242a22009-10-07 19:42:07 -0400593 build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
594
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400595 //hexdump(ssdt, ssdt_ptr - ssdt);
596
Kevin O'Connora9242a22009-10-07 19:42:07 -0400597 return ssdt;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400598}
599
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400600#define HPET_SIGNATURE 0x54455048 // HPET
Kevin O'Connorf4343772009-10-08 22:05:21 -0400601static void*
602build_hpet(void)
603{
Jan Kiszkab8a90f52011-08-29 17:50:10 +0200604 struct acpi_20_hpet *hpet;
Kevin O'Connor7859eda2011-09-20 19:40:28 -0400605 const void *hpet_base = (void *)BUILD_HPET_ADDRESS;
Jan Kiszkab8a90f52011-08-29 17:50:10 +0200606 u32 hpet_vendor = readl(hpet_base + HPET_ID) >> 16;
607 u32 hpet_period = readl(hpet_base + HPET_PERIOD);
608
609 if (hpet_vendor == 0 || hpet_vendor == 0xffff ||
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400610 hpet_period == 0 || hpet_period > 100000000)
Jan Kiszkab8a90f52011-08-29 17:50:10 +0200611 return NULL;
612
613 hpet = malloc_high(sizeof(*hpet));
Kevin O'Connorf4343772009-10-08 22:05:21 -0400614 if (!hpet) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500615 warn_noalloc();
Kevin O'Connorf4343772009-10-08 22:05:21 -0400616 return NULL;
617 }
618
619 memset(hpet, 0, sizeof(*hpet));
620 /* Note timer_block_id value must be kept in sync with value advertised by
621 * emulated hpet
622 */
623 hpet->timer_block_id = cpu_to_le32(0x8086a201);
Kevin O'Connor7859eda2011-09-20 19:40:28 -0400624 hpet->addr.address = cpu_to_le32(BUILD_HPET_ADDRESS);
Kevin O'Connorf4343772009-10-08 22:05:21 -0400625 build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1);
626
627 return hpet;
628}
629
Kevin O'Connor590e5542009-10-08 22:09:02 -0400630static void
631acpi_build_srat_memory(struct srat_memory_affinity *numamem,
632 u64 base, u64 len, int node, int enabled)
633{
634 numamem->type = SRAT_MEMORY;
635 numamem->length = sizeof(*numamem);
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400636 memset(numamem->proximity, 0 ,4);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400637 numamem->proximity[0] = node;
638 numamem->flags = cpu_to_le32(!!enabled);
639 numamem->base_addr_low = base & 0xFFFFFFFF;
640 numamem->base_addr_high = base >> 32;
641 numamem->length_low = len & 0xFFFFFFFF;
642 numamem->length_high = len >> 32;
643}
644
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400645#define SRAT_SIGNATURE 0x54415253 // SRAT
Kevin O'Connor590e5542009-10-08 22:09:02 -0400646static void *
647build_srat(void)
648{
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400649 int numadatasize, numacpusize;
650 u64 *numadata = romfile_loadfile("etc/numa-nodes", &numadatasize);
651 u64 *numacpumap = romfile_loadfile("etc/numa-cpu-map", &numacpusize);
652 if (!numadata || !numacpumap)
653 goto fail;
654 int max_cpu = numacpusize / sizeof(u64);
655 int nb_numa_nodes = numadatasize / sizeof(u64);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400656
657 struct system_resource_affinity_table *srat;
658 int srat_size = sizeof(*srat) +
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500659 sizeof(struct srat_processor_affinity) * max_cpu +
Kevin O'Connor590e5542009-10-08 22:09:02 -0400660 sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
661
662 srat = malloc_high(srat_size);
663 if (!srat) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500664 warn_noalloc();
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400665 goto fail;
Kevin O'Connor590e5542009-10-08 22:09:02 -0400666 }
667
668 memset(srat, 0, srat_size);
669 srat->reserved1=1;
670 struct srat_processor_affinity *core = (void*)(srat + 1);
671 int i;
672 u64 curnode;
673
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500674 for (i = 0; i < max_cpu; ++i) {
Kevin O'Connor590e5542009-10-08 22:09:02 -0400675 core->type = SRAT_PROCESSOR;
676 core->length = sizeof(*core);
677 core->local_apic_id = i;
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400678 curnode = *numacpumap++;
Kevin O'Connor590e5542009-10-08 22:09:02 -0400679 core->proximity_lo = curnode;
680 memset(core->proximity_hi, 0, 3);
681 core->local_sapic_eid = 0;
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300682 if (apic_id_is_present(i))
Kevin O'Connor590e5542009-10-08 22:09:02 -0400683 core->flags = cpu_to_le32(1);
684 else
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300685 core->flags = cpu_to_le32(0);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400686 core++;
687 }
688
689
690 /* the memory map is a bit tricky, it contains at least one hole
691 * from 640k-1M and possibly another one from 3.5G-4G.
692 */
693 struct srat_memory_affinity *numamem = (void*)core;
694 int slots = 0;
695 u64 mem_len, mem_base, next_base = 0;
696
697 acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
698 next_base = 1024 * 1024;
699 numamem++;
700 slots++;
701 for (i = 1; i < nb_numa_nodes + 1; ++i) {
702 mem_base = next_base;
703 mem_len = *numadata++;
704 if (i == 1)
705 mem_len -= 1024 * 1024;
706 next_base = mem_base + mem_len;
707
708 /* Cut out the PCI hole */
709 if (mem_base <= RamSize && next_base > RamSize) {
710 mem_len -= next_base - RamSize;
711 if (mem_len > 0) {
712 acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
713 numamem++;
714 slots++;
715 }
716 mem_base = 1ULL << 32;
717 mem_len = next_base - RamSize;
718 next_base += (1ULL << 32) - RamSize;
719 }
720 acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
721 numamem++;
722 slots++;
723 }
724 for (; slots < nb_numa_nodes + 2; slots++) {
725 acpi_build_srat_memory(numamem, 0, 0, 0, 0);
726 numamem++;
727 }
728
729 build_header((void*)srat, SRAT_SIGNATURE, srat_size, 1);
730
Isaku Yamahatae1920be2010-02-12 11:36:20 +0900731 free(numadata);
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400732 free(numacpumap);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400733 return srat;
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400734fail:
735 free(numadata);
736 free(numacpumap);
737 return NULL;
Kevin O'Connor590e5542009-10-08 22:09:02 -0400738}
739
Gerd Hoffmann7e269b42012-11-28 10:17:35 +0100740static void *
741build_mcfg_q35(void)
742{
743 struct acpi_table_mcfg *mcfg;
744
745 int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]);
746 mcfg = malloc_high(len);
747 if (!mcfg) {
748 warn_noalloc();
749 return NULL;
750 }
751 memset(mcfg, 0, len);
752 mcfg->allocation[0].address = Q35_HOST_BRIDGE_PCIEXBAR_ADDR;
753 mcfg->allocation[0].pci_segment = Q35_HOST_PCIE_PCI_SEGMENT;
754 mcfg->allocation[0].start_bus_number = Q35_HOST_PCIE_START_BUS_NUMBER;
755 mcfg->allocation[0].end_bus_number = Q35_HOST_PCIE_END_BUS_NUMBER;
756
757 build_header((void *)mcfg, MCFG_SIGNATURE, len, 1);
758 return mcfg;
759}
760
Isaku Yamahata4c67f902010-07-20 16:37:19 +0900761static const struct pci_device_id acpi_find_tbl[] = {
762 /* PIIX4 Power Management device. */
763 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL),
Isaku Yamahata72a590e2012-11-28 10:17:33 +0100764 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, NULL),
Isaku Yamahata4c67f902010-07-20 16:37:19 +0900765 PCI_DEVICE_END,
766};
767
Kevin O'Connor2929c352009-07-25 13:48:27 -0400768struct rsdp_descriptor *RsdpAddr;
769
Kevin O'Connora9242a22009-10-07 19:42:07 -0400770#define MAX_ACPI_TABLES 20
Kevin O'Connor2929c352009-07-25 13:48:27 -0400771void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500772acpi_setup(void)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400773{
774 if (! CONFIG_ACPI)
775 return;
776
777 dprintf(3, "init ACPI tables\n");
778
779 // This code is hardcoded for PIIX4 Power Management device.
Kevin O'Connor278b19f2011-06-21 22:41:15 -0400780 struct pci_device *pci = pci_find_init_device(acpi_find_tbl, NULL);
781 if (!pci)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400782 // Device not found
783 return;
784
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400785 // Build ACPI tables
Kevin O'Connora9242a22009-10-07 19:42:07 -0400786 u32 tables[MAX_ACPI_TABLES], tbl_idx = 0;
787
788#define ACPI_INIT_TABLE(X) \
789 do { \
790 tables[tbl_idx] = (u32)(X); \
791 if (tables[tbl_idx]) \
792 tbl_idx++; \
793 } while(0)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400794
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900795 struct fadt_descriptor_rev1 *fadt = build_fadt(pci);
796 ACPI_INIT_TABLE(fadt);
Kevin O'Connora9242a22009-10-07 19:42:07 -0400797 ACPI_INIT_TABLE(build_ssdt());
798 ACPI_INIT_TABLE(build_madt());
Kevin O'Connorf4343772009-10-08 22:05:21 -0400799 ACPI_INIT_TABLE(build_hpet());
Kevin O'Connor590e5542009-10-08 22:09:02 -0400800 ACPI_INIT_TABLE(build_srat());
Gerd Hoffmann7e269b42012-11-28 10:17:35 +0100801 if (pci->device == PCI_DEVICE_ID_INTEL_ICH9_LPC)
802 ACPI_INIT_TABLE(build_mcfg_q35());
Kevin O'Connor2929c352009-07-25 13:48:27 -0400803
Kevin O'Connor188d9942013-02-09 15:24:08 -0500804 struct romfile_s *file = NULL;
805 for (;;) {
806 file = romfile_findprefix("acpi/", file);
807 if (!file)
808 break;
809 struct acpi_table_header *table = malloc_high(file->size);
810 if (!table) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500811 warn_noalloc();
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400812 continue;
813 }
Kevin O'Connor188d9942013-02-09 15:24:08 -0500814 int ret = file->copy(file, table, file->size);
815 if (ret <= sizeof(*table))
816 continue;
817 if (table->signature == DSDT_SIGNATURE) {
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900818 if (fadt) {
Kevin O'Connor188d9942013-02-09 15:24:08 -0500819 fill_dsdt(fadt, table);
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900820 }
821 } else {
Kevin O'Connor188d9942013-02-09 15:24:08 -0500822 ACPI_INIT_TABLE(table);
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900823 }
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400824 if (tbl_idx == MAX_ACPI_TABLES) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500825 warn_noalloc();
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400826 break;
827 }
828 }
Michael S. Tsirkin5aef5632013-03-18 15:18:25 +0200829
830 if (CONFIG_ACPI_DSDT && fadt && !fadt->dsdt) {
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900831 /* default DSDT */
832 void *dsdt = malloc_high(sizeof(AmlCode));
833 if (!dsdt) {
834 warn_noalloc();
835 return;
836 }
837 memcpy(dsdt, AmlCode, sizeof(AmlCode));
838 fill_dsdt(fadt, dsdt);
839 }
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400840
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400841 // Build final rsdt table
Kevin O'Connora9242a22009-10-07 19:42:07 -0400842 struct rsdt_descriptor_rev1 *rsdt;
843 size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx;
844 rsdt = malloc_high(rsdt_len);
Kevin O'Connora9242a22009-10-07 19:42:07 -0400845 if (!rsdt) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500846 warn_noalloc();
Kevin O'Connora9242a22009-10-07 19:42:07 -0400847 return;
848 }
849 memset(rsdt, 0, rsdt_len);
850 memcpy(rsdt->table_offset_entry, tables, sizeof(u32) * tbl_idx);
Kevin O'Connora9242a22009-10-07 19:42:07 -0400851 build_header((void*)rsdt, RSDT_SIGNATURE, rsdt_len, 1);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400852
853 // Build rsdp pointer table
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400854 struct rsdp_descriptor *rsdp = malloc_fseg(sizeof(*rsdp));
855 if (!rsdp) {
856 warn_noalloc();
857 return;
858 }
Kevin O'Connor2929c352009-07-25 13:48:27 -0400859 memset(rsdp, 0, sizeof(*rsdp));
860 rsdp->signature = RSDP_SIGNATURE;
Kevin O'Connore52ad392013-02-20 23:48:22 -0500861 memcpy(rsdp->oem_id, BUILD_APPNAME6, 6);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400862 rsdp->rsdt_physical_address = cpu_to_le32((u32)rsdt);
863 rsdp->checksum -= checksum(rsdp, 20);
864 RsdpAddr = rsdp;
865 dprintf(1, "ACPI tables: RSDP=%p RSDT=%p\n", rsdp, rsdt);
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400866}
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500867
David Woodhouse3219dfa2013-02-03 23:41:41 +0100868static struct fadt_descriptor_rev1 *
869find_fadt(void)
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500870{
871 dprintf(4, "rsdp=%p\n", RsdpAddr);
872 if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE)
David Woodhouse3219dfa2013-02-03 23:41:41 +0100873 return NULL;
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500874 struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address;
875 dprintf(4, "rsdt=%p\n", rsdt);
876 if (!rsdt || rsdt->signature != RSDT_SIGNATURE)
David Woodhouse3219dfa2013-02-03 23:41:41 +0100877 return NULL;
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500878 void *end = (void*)rsdt + rsdt->length;
879 int i;
880 for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) {
881 struct fadt_descriptor_rev1 *fadt = (void*)rsdt->table_offset_entry[i];
882 if (!fadt || fadt->signature != FACP_SIGNATURE)
883 continue;
884 dprintf(4, "fadt=%p\n", fadt);
David Woodhouse3219dfa2013-02-03 23:41:41 +0100885 return fadt;
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500886 }
David Woodhouse3219dfa2013-02-03 23:41:41 +0100887 dprintf(4, "no fadt found\n");
888 return NULL;
889}
890
891u32
892find_resume_vector(void)
893{
894 struct fadt_descriptor_rev1 *fadt = find_fadt();
895 if (!fadt)
896 return 0;
897 struct facs_descriptor_rev1 *facs = (void*)fadt->firmware_ctrl;
898 dprintf(4, "facs=%p\n", facs);
899 if (! facs || facs->signature != FACS_SIGNATURE)
900 return 0;
901 // Found it.
902 dprintf(4, "resume addr=%d\n", facs->firmware_waking_vector);
903 return facs->firmware_waking_vector;
904}
905
906void
David Woodhoused304fe42013-02-23 00:24:48 +0000907find_acpi_features(void)
David Woodhouse3219dfa2013-02-03 23:41:41 +0100908{
909 struct fadt_descriptor_rev1 *fadt = find_fadt();
910 if (!fadt)
911 return;
David Woodhoused304fe42013-02-23 00:24:48 +0000912 u32 pm_tmr = le32_to_cpu(fadt->pm_tmr_blk);
David Woodhouse3219dfa2013-02-03 23:41:41 +0100913 dprintf(4, "pm_tmr_blk=%x\n", pm_tmr);
David Woodhoused304fe42013-02-23 00:24:48 +0000914 if (pm_tmr)
915 pmtimer_setup(pm_tmr, 3579);
David Woodhoused338eb92013-02-23 00:24:49 +0000916
917 // Theoretically we should check the 'reset_reg_sup' flag, but Windows
918 // doesn't and thus nobody seems to *set* it. If the table is large enough
919 // to include it, let the sanity checks in acpi_set_reset_reg() suffice.
920 if (fadt->length >= 129) {
921 void *p = fadt;
922 acpi_set_reset_reg(p + 116, *(u8 *)(p + 128));
923 }
924}
925
926static struct acpi_20_generic_address acpi_reset_reg;
927static u8 acpi_reset_val;
928
929void
930acpi_reboot(void)
931{
932 // Check it passed the sanity checks in acpi_set_reset_reg() and was set
933 if (acpi_reset_reg.register_bit_width != 8)
934 return;
935
936 u64 addr = le64_to_cpu(acpi_reset_reg.address);
937
938 dprintf(1, "ACPI hard reset %d:%llx (%x)\n",
939 acpi_reset_reg.address_space_id, addr, acpi_reset_val);
940
941 switch (acpi_reset_reg.address_space_id) {
942 case 0: // System Memory
943 writeb((void *)(u32)addr, acpi_reset_val);
944 break;
945 case 1: // System I/O
946 outb(acpi_reset_val, addr);
947 break;
948 case 2: // PCI config space
949 pci_config_writeb(acpi_ga_to_bdf(addr), addr & 0xffff, acpi_reset_val);
950 break;
951 }
952}
953
954void
955acpi_set_reset_reg(struct acpi_20_generic_address *reg, u8 val)
956{
957 if (!reg || reg->address_space_id > 2 ||
958 reg->register_bit_width != 8 || reg->register_bit_offset)
959 return;
960
961 acpi_reset_reg = *reg;
962 acpi_reset_val = val;
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500963}