blob: f94a6fb85b0b54dc6461d56e56ccb3d540eed9c5 [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
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -04009#include "util.h" // dprintf
Kevin O'Connorb3064592012-08-14 21:20:10 -040010#include "byteorder.h" // cpu_to_le16
Kevin O'Connor5d369d82013-09-02 20:48:46 -040011#include "hw/pci.h" // pci_find_init_device
12#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
13#include "hw/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'Connor41639f82013-09-14 19:37:36 -040018#include "romfile.h" // romfile_loadint
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040019#include "string.h" // memset
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040020#include "x86.h" // readl
Kevin O'Connor276d4a92008-06-11 22:47:01 -040021
Kevin O'Connorccee6e82013-09-02 21:25:21 -040022#include "src/fw/acpi-dsdt.hex"
Kevin O'Connor276d4a92008-06-11 22:47:01 -040023
Gerd Hoffmann5b631092013-07-25 09:47:18 +020024u32 acpi_pm1a_cnt VARFSEG;
25
Kevin O'Connor2929c352009-07-25 13:48:27 -040026static void
Kevin O'Connora9242a22009-10-07 19:42:07 -040027build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev)
Kevin O'Connor276d4a92008-06-11 22:47:01 -040028{
Kevin O'Connor51684b72013-03-30 10:18:47 -040029 h->signature = cpu_to_le32(sig);
Kevin O'Connor276d4a92008-06-11 22:47:01 -040030 h->length = cpu_to_le32(len);
31 h->revision = rev;
Kevin O'Connore52ad392013-02-20 23:48:22 -050032 memcpy(h->oem_id, BUILD_APPNAME6, 6);
33 memcpy(h->oem_table_id, BUILD_APPNAME4, 4);
Kevin O'Connor9967ab72008-12-18 21:57:33 -050034 memcpy(h->oem_table_id + 4, (void*)&sig, 4);
Kevin O'Connor276d4a92008-06-11 22:47:01 -040035 h->oem_revision = cpu_to_le32(1);
Kevin O'Connore52ad392013-02-20 23:48:22 -050036 memcpy(h->asl_compiler_id, BUILD_APPNAME4, 4);
Kevin O'Connor276d4a92008-06-11 22:47:01 -040037 h->asl_compiler_revision = cpu_to_le32(1);
Kevin O'Connor523e5a92009-07-04 13:46:33 -040038 h->checksum -= checksum(h, len);
Kevin O'Connor276d4a92008-06-11 22:47:01 -040039}
40
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040041#define PIIX4_ACPI_ENABLE 0xf1
42#define PIIX4_ACPI_DISABLE 0xf0
43#define PIIX4_GPE0_BLK 0xafe0
44#define PIIX4_GPE0_BLK_LEN 4
45
Isaku Yamahata229e8e22012-11-28 10:17:31 +010046#define PIIX4_PM_INTRRUPT 9 // irq 9
47
Kevin O'Connord83c87b2013-01-21 01:14:12 -050048static void piix4_fadt_setup(struct pci_device *pci, void *arg)
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040049{
50 struct fadt_descriptor_rev1 *fadt = arg;
Isaku Yamahata229e8e22012-11-28 10:17:31 +010051
52 fadt->model = 1;
53 fadt->reserved1 = 0;
54 fadt->sci_int = cpu_to_le16(PIIX4_PM_INTRRUPT);
55 fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040056 fadt->acpi_enable = PIIX4_ACPI_ENABLE;
57 fadt->acpi_disable = PIIX4_ACPI_DISABLE;
Isaku Yamahata229e8e22012-11-28 10:17:31 +010058 fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
59 fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
60 fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040061 fadt->gpe0_blk = cpu_to_le32(PIIX4_GPE0_BLK);
Isaku Yamahata229e8e22012-11-28 10:17:31 +010062 fadt->pm1_evt_len = 4;
63 fadt->pm1_cnt_len = 2;
64 fadt->pm_tmr_len = 4;
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040065 fadt->gpe0_blk_len = PIIX4_GPE0_BLK_LEN;
Isaku Yamahata229e8e22012-11-28 10:17:31 +010066 fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
67 fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
68 /* WBINVD + PROC_C1 + SLP_BUTTON + RTC_S4 + USE_PLATFORM_CLOCK */
69 fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 7) |
70 (1 << 15));
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040071}
72
Isaku Yamahata72a590e2012-11-28 10:17:33 +010073/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
Kevin O'Connord83c87b2013-01-21 01:14:12 -050074void ich9_lpc_fadt_setup(struct pci_device *dev, void *arg)
Isaku Yamahata72a590e2012-11-28 10:17:33 +010075{
76 struct fadt_descriptor_rev1 *fadt = arg;
77
78 fadt->model = 1;
79 fadt->reserved1 = 0;
80 fadt->sci_int = cpu_to_le16(9);
81 fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
82 fadt->acpi_enable = ICH9_ACPI_ENABLE;
83 fadt->acpi_disable = ICH9_ACPI_DISABLE;
84 fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
85 fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
86 fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
87 fadt->gpe0_blk = cpu_to_le32(PORT_ACPI_PM_BASE + ICH9_PMIO_GPE0_STS);
88 fadt->pm1_evt_len = 4;
89 fadt->pm1_cnt_len = 2;
90 fadt->pm_tmr_len = 4;
91 fadt->gpe0_blk_len = ICH9_PMIO_GPE0_BLK_LEN;
92 fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
93 fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
Michael S. Tsirkined88f652013-07-17 08:14:53 +030094 /* WBINVD + PROC_C1 + SLP_BUTTON + RTC_S4 + USE_PLATFORM_CLOCK */
95 fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 7) |
96 (1 << 15));
Isaku Yamahata72a590e2012-11-28 10:17:33 +010097}
98
Isaku Yamahatafe54a532010-07-20 16:37:18 +090099static const struct pci_device_id fadt_init_tbl[] = {
100 /* PIIX4 Power Management device (for ACPI) */
101 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500102 piix4_fadt_setup),
Isaku Yamahata72a590e2012-11-28 10:17:33 +0100103 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500104 ich9_lpc_fadt_setup),
Isaku Yamahatafe54a532010-07-20 16:37:18 +0900105 PCI_DEVICE_END
106};
107
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900108static void fill_dsdt(struct fadt_descriptor_rev1 *fadt, void *dsdt)
109{
110 if (fadt->dsdt) {
111 free((void *)le32_to_cpu(fadt->dsdt));
112 }
113 fadt->dsdt = cpu_to_le32((u32)dsdt);
114 fadt->checksum -= checksum(fadt, sizeof(*fadt));
115 dprintf(1, "ACPI DSDT=%p\n", dsdt);
116}
117
Kevin O'Connor278b19f2011-06-21 22:41:15 -0400118static void *
119build_fadt(struct pci_device *pci)
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400120{
Kevin O'Connor2929c352009-07-25 13:48:27 -0400121 struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt));
Kevin O'Connor415d4292009-08-30 19:19:31 -0400122 struct facs_descriptor_rev1 *facs = memalign_high(64, sizeof(*facs));
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400123
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900124 if (!fadt || !facs) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500125 warn_noalloc();
Kevin O'Connora9242a22009-10-07 19:42:07 -0400126 return NULL;
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400127 }
128
Kevin O'Connor2929c352009-07-25 13:48:27 -0400129 /* FACS */
Kevin O'Connor2929c352009-07-25 13:48:27 -0400130 memset(facs, 0, sizeof(*facs));
Kevin O'Connor51684b72013-03-30 10:18:47 -0400131 facs->signature = cpu_to_le32(FACS_SIGNATURE);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400132 facs->length = cpu_to_le32(sizeof(*facs));
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400133
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400134 /* FADT */
135 memset(fadt, 0, sizeof(*fadt));
Kevin O'Connor2929c352009-07-25 13:48:27 -0400136 fadt->firmware_ctrl = cpu_to_le32((u32)facs);
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500137 fadt->dsdt = 0; /* dsdt will be filled later in acpi_setup()
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900138 by fill_dsdt() */
Kevin O'Connor278b19f2011-06-21 22:41:15 -0400139 pci_init_device(fadt_init_tbl, pci, fadt);
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400140
Kevin O'Connora9242a22009-10-07 19:42:07 -0400141 build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1);
142
143 return fadt;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400144}
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400145
Kevin O'Connora9242a22009-10-07 19:42:07 -0400146static void*
147build_madt(void)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400148{
Kevin O'Connor2929c352009-07-25 13:48:27 -0400149 int madt_size = (sizeof(struct multiple_apic_table)
Kevin O'Connora26df9b2009-10-09 09:42:11 -0400150 + sizeof(struct madt_processor_apic) * MaxCountCPUs
Kevin O'Connor2929c352009-07-25 13:48:27 -0400151 + sizeof(struct madt_io_apic)
Kenji Kaneshige70986382011-10-10 14:06:17 +0800152 + sizeof(struct madt_intsrcovr) * 16
153 + sizeof(struct madt_local_nmi));
154
Kevin O'Connor2929c352009-07-25 13:48:27 -0400155 struct multiple_apic_table *madt = malloc_high(madt_size);
156 if (!madt) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500157 warn_noalloc();
Kevin O'Connora9242a22009-10-07 19:42:07 -0400158 return NULL;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400159 }
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500160 memset(madt, 0, madt_size);
161 madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
162 madt->flags = cpu_to_le32(1);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400163 struct madt_processor_apic *apic = (void*)&madt[1];
164 int i;
Kevin O'Connora26df9b2009-10-09 09:42:11 -0400165 for (i=0; i<MaxCountCPUs; i++) {
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500166 apic->type = APIC_PROCESSOR;
167 apic->length = sizeof(*apic);
168 apic->processor_id = i;
169 apic->local_apic_id = i;
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300170 if (apic_id_is_present(apic->local_apic_id))
Kevin O'Connora26df9b2009-10-09 09:42:11 -0400171 apic->flags = cpu_to_le32(1);
172 else
173 apic->flags = cpu_to_le32(0);
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500174 apic++;
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400175 }
Kevin O'Connor2929c352009-07-25 13:48:27 -0400176 struct madt_io_apic *io_apic = (void*)apic;
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500177 io_apic->type = APIC_IO;
178 io_apic->length = sizeof(*io_apic);
Eduardo Habkoste39b9382012-07-25 15:45:29 -0300179 io_apic->io_apic_id = BUILD_IOAPIC_ID;
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500180 io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR);
181 io_apic->interrupt = cpu_to_le32(0);
182
Kevin O'Connord10e4442009-03-01 12:41:20 -0500183 struct madt_intsrcovr *intsrcovr = (void*)&io_apic[1];
Kevin O'Connor56c50892013-02-09 19:25:51 -0500184 if (romfile_loadint("etc/irq0-override", 0)) {
Kevin O'Connorb64db302009-07-29 19:20:03 -0400185 memset(intsrcovr, 0, sizeof(*intsrcovr));
186 intsrcovr->type = APIC_XRUPT_OVERRIDE;
187 intsrcovr->length = sizeof(*intsrcovr);
188 intsrcovr->source = 0;
Kevin O'Connor51684b72013-03-30 10:18:47 -0400189 intsrcovr->gsi = cpu_to_le32(2);
190 intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */
Kevin O'Connorb64db302009-07-29 19:20:03 -0400191 intsrcovr++;
192 }
193 for (i = 1; i < 16; i++) {
Kevin O'Connord8388152013-03-18 20:26:54 -0400194 if (!(BUILD_PCI_IRQS & (1 << i)))
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500195 /* No need for a INT source override structure. */
196 continue;
Kevin O'Connord10e4442009-03-01 12:41:20 -0500197 memset(intsrcovr, 0, sizeof(*intsrcovr));
198 intsrcovr->type = APIC_XRUPT_OVERRIDE;
199 intsrcovr->length = sizeof(*intsrcovr);
200 intsrcovr->source = i;
Kevin O'Connor51684b72013-03-30 10:18:47 -0400201 intsrcovr->gsi = cpu_to_le32(i);
202 intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500203 intsrcovr++;
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500204 }
205
Kenji Kaneshige70986382011-10-10 14:06:17 +0800206 struct madt_local_nmi *local_nmi = (void*)intsrcovr;
207 local_nmi->type = APIC_LOCAL_NMI;
208 local_nmi->length = sizeof(*local_nmi);
209 local_nmi->processor_id = 0xff; /* all processors */
Kevin O'Connor51684b72013-03-30 10:18:47 -0400210 local_nmi->flags = cpu_to_le16(0);
Kenji Kaneshige70986382011-10-10 14:06:17 +0800211 local_nmi->lint = 1; /* LINT1 */
212 local_nmi++;
213
214 build_header((void*)madt, APIC_SIGNATURE, (void*)local_nmi - (void*)madt, 1);
Kevin O'Connora9242a22009-10-07 19:42:07 -0400215 return madt;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400216}
217
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400218// Encode a hex value
219static inline char getHex(u32 val) {
220 val &= 0x0f;
221 return (val <= 9) ? ('0' + val) : ('A' + val - 10);
222}
223
224// Encode a length in an SSDT.
225static u8 *
226encodeLen(u8 *ssdt_ptr, int length, int bytes)
227{
228 switch (bytes) {
229 default:
230 case 4: ssdt_ptr[3] = ((length >> 20) & 0xff);
231 case 3: ssdt_ptr[2] = ((length >> 12) & 0xff);
232 case 2: ssdt_ptr[1] = ((length >> 4) & 0xff);
233 ssdt_ptr[0] = (((bytes-1) & 0x3) << 6) | (length & 0x0f);
234 break;
235 case 1: ssdt_ptr[0] = length & 0x3f;
236 }
237 return ssdt_ptr + bytes;
238}
239
Kevin O'Connorccee6e82013-09-02 21:25:21 -0400240#include "src/fw/ssdt-proc.hex"
Michael S. Tsirkinc736f0a2011-10-04 15:26:19 +0200241
242/* 0x5B 0x83 ProcessorOp PkgLength NameString ProcID */
Paolo Bonzinic8ed45e2012-08-02 15:07:22 +0200243#define PROC_OFFSET_CPUHEX (*ssdt_proc_name - *ssdt_proc_start + 2)
244#define PROC_OFFSET_CPUID1 (*ssdt_proc_name - *ssdt_proc_start + 4)
245#define PROC_OFFSET_CPUID2 (*ssdt_proc_id - *ssdt_proc_start)
246#define PROC_SIZEOF (*ssdt_proc_end - *ssdt_proc_start)
247#define PROC_AML (ssdp_proc_aml + *ssdt_proc_start)
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400248
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200249/* 0x5B 0x82 DeviceOp PkgLength NameString */
250#define PCIHP_OFFSET_HEX (*ssdt_pcihp_name - *ssdt_pcihp_start + 1)
251#define PCIHP_OFFSET_ID (*ssdt_pcihp_id - *ssdt_pcihp_start)
252#define PCIHP_OFFSET_ADR (*ssdt_pcihp_adr - *ssdt_pcihp_start)
253#define PCIHP_OFFSET_EJ0 (*ssdt_pcihp_ej0 - *ssdt_pcihp_start)
254#define PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start)
255#define PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200256#define PCI_SLOTS 32
257
Kevin O'Connor2929c352009-07-25 13:48:27 -0400258#define SSDT_SIGNATURE 0x54445353 // SSDT
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200259#define SSDT_HEADER_LENGTH 36
260
Kevin O'Connorccee6e82013-09-02 21:25:21 -0400261#include "src/fw/ssdt-misc.hex"
262#include "src/fw/ssdt-pcihp.hex"
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200263
264#define PCI_RMV_BASE 0xae0c
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200265
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200266static u8*
267build_notify(u8 *ssdt_ptr, const char *name, int skip, int count,
268 const char *target, int ofs)
269{
270 count -= skip;
271
272 *(ssdt_ptr++) = 0x14; // MethodOp
273 ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*count), 2);
274 memcpy(ssdt_ptr, name, 4);
275 ssdt_ptr += 4;
276 *(ssdt_ptr++) = 0x02; // MethodOp
277
278 int i;
279 for (i = skip; count-- > 0; i++) {
280 *(ssdt_ptr++) = 0xA0; // IfOp
281 ssdt_ptr = encodeLen(ssdt_ptr, 11, 1);
282 *(ssdt_ptr++) = 0x93; // LEqualOp
283 *(ssdt_ptr++) = 0x68; // Arg0Op
284 *(ssdt_ptr++) = 0x0A; // BytePrefix
285 *(ssdt_ptr++) = i;
286 *(ssdt_ptr++) = 0x86; // NotifyOp
287 memcpy(ssdt_ptr, target, 4);
288 ssdt_ptr[ofs] = getHex(i >> 4);
289 ssdt_ptr[ofs + 1] = getHex(i);
290 ssdt_ptr += 4;
291 *(ssdt_ptr++) = 0x69; // Arg1Op
292 }
293 return ssdt_ptr;
294}
295
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200296static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject)
297{
298 ssdt_ptr[PCIHP_OFFSET_HEX] = getHex(slot >> 4);
299 ssdt_ptr[PCIHP_OFFSET_HEX+1] = getHex(slot);
300 ssdt_ptr[PCIHP_OFFSET_ID] = slot;
301 ssdt_ptr[PCIHP_OFFSET_ADR + 2] = slot;
302
303 /* Runtime patching of EJ0: to disable hotplug for a slot,
304 * replace the method name: _EJ0 by EJ0_. */
305 /* Sanity check */
306 if (memcmp(ssdt_ptr + PCIHP_OFFSET_EJ0, "_EJ0", 4)) {
307 warn_internalerror();
308 }
309 if (!eject) {
310 memcpy(ssdt_ptr + PCIHP_OFFSET_EJ0, "EJ0_", 4);
311 }
312}
313
Kevin O'Connora9242a22009-10-07 19:42:07 -0400314static void*
315build_ssdt(void)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400316{
Kevin O'Connora26df9b2009-10-09 09:42:11 -0400317 int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs;
Kevin O'Connor3f8d7352013-02-27 20:46:40 -0500318 int length = (sizeof(ssdp_misc_aml) // _S3_ / _S4_ / _S5_
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200319 + (1+3+4) // Scope(_SB_)
Paolo Bonzinic8ed45e2012-08-02 15:07:22 +0200320 + (acpi_cpus * PROC_SIZEOF) // procs
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200321 + (1+2+5+(12*acpi_cpus)) // NTFY
322 + (6+2+1+(1*acpi_cpus)) // CPON
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200323 + (1+3+4) // Scope(PCI0)
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200324 + ((PCI_SLOTS - 1) * PCIHP_SIZEOF) // slots
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200325 + (1+2+5+(12*(PCI_SLOTS - 1)))); // PCNT
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200326 u8 *ssdt = malloc_high(length);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400327 if (! ssdt) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500328 warn_noalloc();
Kevin O'Connora9242a22009-10-07 19:42:07 -0400329 return NULL;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400330 }
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200331 u8 *ssdt_ptr = ssdt;
332
333 // Copy header and encode fwcfg values in the S3_ / S4_ / S5_ packages
334 int sys_state_size;
335 char *sys_states = romfile_loadfile("etc/system-states", &sys_state_size);
336 if (!sys_states || sys_state_size != 6)
337 sys_states = (char[]){128, 0, 0, 129, 128, 128};
338
Kevin O'Connor3f8d7352013-02-27 20:46:40 -0500339 memcpy(ssdt_ptr, ssdp_misc_aml, sizeof(ssdp_misc_aml));
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200340 if (!(sys_states[3] & 128))
341 ssdt_ptr[acpi_s3_name[0]] = 'X';
342 if (!(sys_states[4] & 128))
343 ssdt_ptr[acpi_s4_name[0]] = 'X';
344 else
345 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 -0500346
347 // store pci io windows
Kevin O'Connor51684b72013-03-30 10:18:47 -0400348 *(u32*)&ssdt_ptr[acpi_pci32_start[0]] = cpu_to_le32(pcimem_start);
349 *(u32*)&ssdt_ptr[acpi_pci32_end[0]] = cpu_to_le32(pcimem_end - 1);
Kevin O'Connor76e58022013-03-06 21:50:09 -0500350 if (pcimem64_start) {
351 ssdt_ptr[acpi_pci64_valid[0]] = 1;
Kevin O'Connor51684b72013-03-30 10:18:47 -0400352 *(u64*)&ssdt_ptr[acpi_pci64_start[0]] = cpu_to_le64(pcimem64_start);
353 *(u64*)&ssdt_ptr[acpi_pci64_end[0]] = cpu_to_le64(pcimem64_end - 1);
354 *(u64*)&ssdt_ptr[acpi_pci64_length[0]] = cpu_to_le64(
355 pcimem64_end - pcimem64_start);
Kevin O'Connor76e58022013-03-06 21:50:09 -0500356 } else {
357 ssdt_ptr[acpi_pci64_valid[0]] = 0;
358 }
359
Hu Taoe9725dd2013-04-05 15:17:51 +0800360 int pvpanic_port = romfile_loadint("etc/pvpanic-port", 0x0);
361 *(u16 *)(ssdt_ptr + *ssdt_isa_pest) = pvpanic_port;
362
Kevin O'Connor3f8d7352013-02-27 20:46:40 -0500363 ssdt_ptr += sizeof(ssdp_misc_aml);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400364
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400365 // build Scope(_SB_) header
Kevin O'Connor2929c352009-07-25 13:48:27 -0400366 *(ssdt_ptr++) = 0x10; // ScopeOp
Paolo Bonzinicf5bef42012-08-02 15:07:21 +0200367 ssdt_ptr = encodeLen(ssdt_ptr, length - (ssdt_ptr - ssdt), 3);
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400368 *(ssdt_ptr++) = '_';
369 *(ssdt_ptr++) = 'S';
370 *(ssdt_ptr++) = 'B';
Kevin O'Connor2929c352009-07-25 13:48:27 -0400371 *(ssdt_ptr++) = '_';
372
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400373 // build Processor object for each processor
Kevin O'Connor2929c352009-07-25 13:48:27 -0400374 int i;
375 for (i=0; i<acpi_cpus; i++) {
Paolo Bonzinic8ed45e2012-08-02 15:07:22 +0200376 memcpy(ssdt_ptr, PROC_AML, PROC_SIZEOF);
377 ssdt_ptr[PROC_OFFSET_CPUHEX] = getHex(i >> 4);
378 ssdt_ptr[PROC_OFFSET_CPUHEX+1] = getHex(i);
379 ssdt_ptr[PROC_OFFSET_CPUID1] = i;
380 ssdt_ptr[PROC_OFFSET_CPUID2] = i;
381 ssdt_ptr += PROC_SIZEOF;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400382 }
383
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400384 // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}"
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300385 // Arg0 = Processor ID = APIC ID
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200386 ssdt_ptr = build_notify(ssdt_ptr, "NTFY", 0, acpi_cpus, "CP00", 2);
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400387
388 // build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })"
389 *(ssdt_ptr++) = 0x08; // NameOp
390 *(ssdt_ptr++) = 'C';
391 *(ssdt_ptr++) = 'P';
392 *(ssdt_ptr++) = 'O';
393 *(ssdt_ptr++) = 'N';
394 *(ssdt_ptr++) = 0x12; // PackageOp
395 ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*acpi_cpus), 2);
396 *(ssdt_ptr++) = acpi_cpus;
397 for (i=0; i<acpi_cpus; i++)
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300398 *(ssdt_ptr++) = (apic_id_is_present(i)) ? 0x01 : 0x00;
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400399
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200400 // build Scope(PCI0) opcode
401 *(ssdt_ptr++) = 0x10; // ScopeOp
402 ssdt_ptr = encodeLen(ssdt_ptr, length - (ssdt_ptr - ssdt), 3);
403 *(ssdt_ptr++) = 'P';
404 *(ssdt_ptr++) = 'C';
405 *(ssdt_ptr++) = 'I';
406 *(ssdt_ptr++) = '0';
407
Paolo Bonzini71ed8e32012-08-02 15:07:26 +0200408 // build Device object for each slot
409 u32 rmvc_pcrm = inl(PCI_RMV_BASE);
410 for (i=1; i<PCI_SLOTS; i++) {
411 u32 eject = rmvc_pcrm & (0x1 << i);
412 memcpy(ssdt_ptr, PCIHP_AML, PCIHP_SIZEOF);
413 patch_pcihp(i, ssdt_ptr, eject != 0);
414 ssdt_ptr += PCIHP_SIZEOF;
415 }
416
Paolo Bonzini7dceba32012-08-02 15:07:25 +0200417 ssdt_ptr = build_notify(ssdt_ptr, "PCNT", 1, PCI_SLOTS, "S00_", 1);
418
Kevin O'Connora9242a22009-10-07 19:42:07 -0400419 build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
420
Kevin O'Connore2074bf2010-08-03 21:30:03 -0400421 //hexdump(ssdt, ssdt_ptr - ssdt);
422
Kevin O'Connora9242a22009-10-07 19:42:07 -0400423 return ssdt;
Kevin O'Connor2929c352009-07-25 13:48:27 -0400424}
425
Kevin O'Connor45cced12013-03-30 09:34:10 -0400426#define HPET_ID 0x000
427#define HPET_PERIOD 0x004
428
Kevin O'Connorf4343772009-10-08 22:05:21 -0400429static void*
430build_hpet(void)
431{
Jan Kiszkab8a90f52011-08-29 17:50:10 +0200432 struct acpi_20_hpet *hpet;
Kevin O'Connor7859eda2011-09-20 19:40:28 -0400433 const void *hpet_base = (void *)BUILD_HPET_ADDRESS;
Jan Kiszkab8a90f52011-08-29 17:50:10 +0200434 u32 hpet_vendor = readl(hpet_base + HPET_ID) >> 16;
435 u32 hpet_period = readl(hpet_base + HPET_PERIOD);
436
437 if (hpet_vendor == 0 || hpet_vendor == 0xffff ||
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400438 hpet_period == 0 || hpet_period > 100000000)
Jan Kiszkab8a90f52011-08-29 17:50:10 +0200439 return NULL;
440
441 hpet = malloc_high(sizeof(*hpet));
Kevin O'Connorf4343772009-10-08 22:05:21 -0400442 if (!hpet) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500443 warn_noalloc();
Kevin O'Connorf4343772009-10-08 22:05:21 -0400444 return NULL;
445 }
446
447 memset(hpet, 0, sizeof(*hpet));
448 /* Note timer_block_id value must be kept in sync with value advertised by
449 * emulated hpet
450 */
451 hpet->timer_block_id = cpu_to_le32(0x8086a201);
Kevin O'Connor51684b72013-03-30 10:18:47 -0400452 hpet->addr.address = cpu_to_le64(BUILD_HPET_ADDRESS);
Kevin O'Connorf4343772009-10-08 22:05:21 -0400453 build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1);
454
455 return hpet;
456}
457
Kevin O'Connor590e5542009-10-08 22:09:02 -0400458static void
459acpi_build_srat_memory(struct srat_memory_affinity *numamem,
460 u64 base, u64 len, int node, int enabled)
461{
462 numamem->type = SRAT_MEMORY;
463 numamem->length = sizeof(*numamem);
Kevin O'Connor51684b72013-03-30 10:18:47 -0400464 memset(numamem->proximity, 0, 4);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400465 numamem->proximity[0] = node;
466 numamem->flags = cpu_to_le32(!!enabled);
Kevin O'Connor51684b72013-03-30 10:18:47 -0400467 numamem->base_addr = cpu_to_le64(base);
468 numamem->range_length = cpu_to_le64(len);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400469}
470
Kevin O'Connor590e5542009-10-08 22:09:02 -0400471static void *
472build_srat(void)
473{
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400474 int numadatasize, numacpusize;
475 u64 *numadata = romfile_loadfile("etc/numa-nodes", &numadatasize);
476 u64 *numacpumap = romfile_loadfile("etc/numa-cpu-map", &numacpusize);
477 if (!numadata || !numacpumap)
478 goto fail;
479 int max_cpu = numacpusize / sizeof(u64);
480 int nb_numa_nodes = numadatasize / sizeof(u64);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400481
482 struct system_resource_affinity_table *srat;
483 int srat_size = sizeof(*srat) +
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500484 sizeof(struct srat_processor_affinity) * max_cpu +
Kevin O'Connor590e5542009-10-08 22:09:02 -0400485 sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
486
487 srat = malloc_high(srat_size);
488 if (!srat) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500489 warn_noalloc();
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400490 goto fail;
Kevin O'Connor590e5542009-10-08 22:09:02 -0400491 }
492
493 memset(srat, 0, srat_size);
Kevin O'Connor51684b72013-03-30 10:18:47 -0400494 srat->reserved1=cpu_to_le32(1);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400495 struct srat_processor_affinity *core = (void*)(srat + 1);
496 int i;
497 u64 curnode;
498
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500499 for (i = 0; i < max_cpu; ++i) {
Kevin O'Connor590e5542009-10-08 22:09:02 -0400500 core->type = SRAT_PROCESSOR;
501 core->length = sizeof(*core);
502 core->local_apic_id = i;
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400503 curnode = *numacpumap++;
Kevin O'Connor590e5542009-10-08 22:09:02 -0400504 core->proximity_lo = curnode;
505 memset(core->proximity_hi, 0, 3);
506 core->local_sapic_eid = 0;
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300507 if (apic_id_is_present(i))
Kevin O'Connor590e5542009-10-08 22:09:02 -0400508 core->flags = cpu_to_le32(1);
509 else
Eduardo Habkost008c1fc2012-07-25 15:45:30 -0300510 core->flags = cpu_to_le32(0);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400511 core++;
512 }
513
514
515 /* the memory map is a bit tricky, it contains at least one hole
516 * from 640k-1M and possibly another one from 3.5G-4G.
517 */
518 struct srat_memory_affinity *numamem = (void*)core;
519 int slots = 0;
520 u64 mem_len, mem_base, next_base = 0;
521
522 acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
523 next_base = 1024 * 1024;
524 numamem++;
525 slots++;
526 for (i = 1; i < nb_numa_nodes + 1; ++i) {
527 mem_base = next_base;
528 mem_len = *numadata++;
529 if (i == 1)
530 mem_len -= 1024 * 1024;
531 next_base = mem_base + mem_len;
532
533 /* Cut out the PCI hole */
534 if (mem_base <= RamSize && next_base > RamSize) {
535 mem_len -= next_base - RamSize;
536 if (mem_len > 0) {
537 acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
538 numamem++;
539 slots++;
540 }
541 mem_base = 1ULL << 32;
542 mem_len = next_base - RamSize;
543 next_base += (1ULL << 32) - RamSize;
544 }
545 acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
546 numamem++;
547 slots++;
548 }
549 for (; slots < nb_numa_nodes + 2; slots++) {
550 acpi_build_srat_memory(numamem, 0, 0, 0, 0);
551 numamem++;
552 }
553
554 build_header((void*)srat, SRAT_SIGNATURE, srat_size, 1);
555
Isaku Yamahatae1920be2010-02-12 11:36:20 +0900556 free(numadata);
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400557 free(numacpumap);
Kevin O'Connor590e5542009-10-08 22:09:02 -0400558 return srat;
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400559fail:
560 free(numadata);
561 free(numacpumap);
562 return NULL;
Kevin O'Connor590e5542009-10-08 22:09:02 -0400563}
564
Gerd Hoffmann7e269b42012-11-28 10:17:35 +0100565static void *
566build_mcfg_q35(void)
567{
568 struct acpi_table_mcfg *mcfg;
569
570 int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]);
571 mcfg = malloc_high(len);
572 if (!mcfg) {
573 warn_noalloc();
574 return NULL;
575 }
576 memset(mcfg, 0, len);
Kevin O'Connor51684b72013-03-30 10:18:47 -0400577 mcfg->allocation[0].address = cpu_to_le64(Q35_HOST_BRIDGE_PCIEXBAR_ADDR);
578 mcfg->allocation[0].pci_segment = cpu_to_le16(Q35_HOST_PCIE_PCI_SEGMENT);
Gerd Hoffmann7e269b42012-11-28 10:17:35 +0100579 mcfg->allocation[0].start_bus_number = Q35_HOST_PCIE_START_BUS_NUMBER;
580 mcfg->allocation[0].end_bus_number = Q35_HOST_PCIE_END_BUS_NUMBER;
581
582 build_header((void *)mcfg, MCFG_SIGNATURE, len, 1);
583 return mcfg;
584}
585
Isaku Yamahata4c67f902010-07-20 16:37:19 +0900586static const struct pci_device_id acpi_find_tbl[] = {
587 /* PIIX4 Power Management device. */
588 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL),
Isaku Yamahata72a590e2012-11-28 10:17:33 +0100589 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, NULL),
Isaku Yamahata4c67f902010-07-20 16:37:19 +0900590 PCI_DEVICE_END,
591};
592
Kevin O'Connor2929c352009-07-25 13:48:27 -0400593struct rsdp_descriptor *RsdpAddr;
594
Kevin O'Connora9242a22009-10-07 19:42:07 -0400595#define MAX_ACPI_TABLES 20
Kevin O'Connor2929c352009-07-25 13:48:27 -0400596void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500597acpi_setup(void)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400598{
599 if (! CONFIG_ACPI)
600 return;
601
602 dprintf(3, "init ACPI tables\n");
603
604 // This code is hardcoded for PIIX4 Power Management device.
Kevin O'Connor278b19f2011-06-21 22:41:15 -0400605 struct pci_device *pci = pci_find_init_device(acpi_find_tbl, NULL);
606 if (!pci)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400607 // Device not found
608 return;
609
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400610 // Build ACPI tables
Kevin O'Connora9242a22009-10-07 19:42:07 -0400611 u32 tables[MAX_ACPI_TABLES], tbl_idx = 0;
612
613#define ACPI_INIT_TABLE(X) \
614 do { \
Kevin O'Connor51684b72013-03-30 10:18:47 -0400615 tables[tbl_idx] = cpu_to_le32((u32)(X)); \
616 if (le32_to_cpu(tables[tbl_idx])) \
Kevin O'Connora9242a22009-10-07 19:42:07 -0400617 tbl_idx++; \
618 } while(0)
Kevin O'Connor2929c352009-07-25 13:48:27 -0400619
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900620 struct fadt_descriptor_rev1 *fadt = build_fadt(pci);
621 ACPI_INIT_TABLE(fadt);
Kevin O'Connora9242a22009-10-07 19:42:07 -0400622 ACPI_INIT_TABLE(build_ssdt());
623 ACPI_INIT_TABLE(build_madt());
Kevin O'Connorf4343772009-10-08 22:05:21 -0400624 ACPI_INIT_TABLE(build_hpet());
Kevin O'Connor590e5542009-10-08 22:09:02 -0400625 ACPI_INIT_TABLE(build_srat());
Gerd Hoffmann7e269b42012-11-28 10:17:35 +0100626 if (pci->device == PCI_DEVICE_ID_INTEL_ICH9_LPC)
627 ACPI_INIT_TABLE(build_mcfg_q35());
Kevin O'Connor2929c352009-07-25 13:48:27 -0400628
Kevin O'Connor188d9942013-02-09 15:24:08 -0500629 struct romfile_s *file = NULL;
630 for (;;) {
631 file = romfile_findprefix("acpi/", file);
632 if (!file)
633 break;
634 struct acpi_table_header *table = malloc_high(file->size);
635 if (!table) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500636 warn_noalloc();
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400637 continue;
638 }
Kevin O'Connor188d9942013-02-09 15:24:08 -0500639 int ret = file->copy(file, table, file->size);
640 if (ret <= sizeof(*table))
641 continue;
642 if (table->signature == DSDT_SIGNATURE) {
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900643 if (fadt) {
Kevin O'Connor188d9942013-02-09 15:24:08 -0500644 fill_dsdt(fadt, table);
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900645 }
646 } else {
Kevin O'Connor188d9942013-02-09 15:24:08 -0500647 ACPI_INIT_TABLE(table);
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900648 }
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400649 if (tbl_idx == MAX_ACPI_TABLES) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500650 warn_noalloc();
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400651 break;
652 }
653 }
Michael S. Tsirkin5aef5632013-03-18 15:18:25 +0200654
655 if (CONFIG_ACPI_DSDT && fadt && !fadt->dsdt) {
Isaku Yamahataf2fd79b2011-10-24 17:11:08 +0900656 /* default DSDT */
657 void *dsdt = malloc_high(sizeof(AmlCode));
658 if (!dsdt) {
659 warn_noalloc();
660 return;
661 }
662 memcpy(dsdt, AmlCode, sizeof(AmlCode));
663 fill_dsdt(fadt, dsdt);
664 }
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400665
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400666 // Build final rsdt table
Kevin O'Connora9242a22009-10-07 19:42:07 -0400667 struct rsdt_descriptor_rev1 *rsdt;
668 size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx;
669 rsdt = malloc_high(rsdt_len);
Kevin O'Connora9242a22009-10-07 19:42:07 -0400670 if (!rsdt) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500671 warn_noalloc();
Kevin O'Connora9242a22009-10-07 19:42:07 -0400672 return;
673 }
674 memset(rsdt, 0, rsdt_len);
675 memcpy(rsdt->table_offset_entry, tables, sizeof(u32) * tbl_idx);
Kevin O'Connora9242a22009-10-07 19:42:07 -0400676 build_header((void*)rsdt, RSDT_SIGNATURE, rsdt_len, 1);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400677
678 // Build rsdp pointer table
Kevin O'Connor8a161c92011-09-02 18:11:58 -0400679 struct rsdp_descriptor *rsdp = malloc_fseg(sizeof(*rsdp));
680 if (!rsdp) {
681 warn_noalloc();
682 return;
683 }
Kevin O'Connor2929c352009-07-25 13:48:27 -0400684 memset(rsdp, 0, sizeof(*rsdp));
Kevin O'Connor51684b72013-03-30 10:18:47 -0400685 rsdp->signature = cpu_to_le64(RSDP_SIGNATURE);
Kevin O'Connore52ad392013-02-20 23:48:22 -0500686 memcpy(rsdp->oem_id, BUILD_APPNAME6, 6);
Kevin O'Connor2929c352009-07-25 13:48:27 -0400687 rsdp->rsdt_physical_address = cpu_to_le32((u32)rsdt);
688 rsdp->checksum -= checksum(rsdp, 20);
689 RsdpAddr = rsdp;
690 dprintf(1, "ACPI tables: RSDP=%p RSDT=%p\n", rsdp, rsdt);
Kevin O'Connor276d4a92008-06-11 22:47:01 -0400691}
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500692
David Woodhouse3219dfa2013-02-03 23:41:41 +0100693static struct fadt_descriptor_rev1 *
694find_fadt(void)
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500695{
696 dprintf(4, "rsdp=%p\n", RsdpAddr);
697 if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE)
David Woodhouse3219dfa2013-02-03 23:41:41 +0100698 return NULL;
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500699 struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address;
700 dprintf(4, "rsdt=%p\n", rsdt);
701 if (!rsdt || rsdt->signature != RSDT_SIGNATURE)
David Woodhouse3219dfa2013-02-03 23:41:41 +0100702 return NULL;
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500703 void *end = (void*)rsdt + rsdt->length;
704 int i;
705 for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) {
706 struct fadt_descriptor_rev1 *fadt = (void*)rsdt->table_offset_entry[i];
707 if (!fadt || fadt->signature != FACP_SIGNATURE)
708 continue;
709 dprintf(4, "fadt=%p\n", fadt);
David Woodhouse3219dfa2013-02-03 23:41:41 +0100710 return fadt;
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500711 }
David Woodhouse3219dfa2013-02-03 23:41:41 +0100712 dprintf(4, "no fadt found\n");
713 return NULL;
714}
715
716u32
717find_resume_vector(void)
718{
719 struct fadt_descriptor_rev1 *fadt = find_fadt();
720 if (!fadt)
721 return 0;
722 struct facs_descriptor_rev1 *facs = (void*)fadt->firmware_ctrl;
723 dprintf(4, "facs=%p\n", facs);
724 if (! facs || facs->signature != FACS_SIGNATURE)
725 return 0;
726 // Found it.
727 dprintf(4, "resume addr=%d\n", facs->firmware_waking_vector);
728 return facs->firmware_waking_vector;
729}
730
731void
David Woodhoused304fe42013-02-23 00:24:48 +0000732find_acpi_features(void)
David Woodhouse3219dfa2013-02-03 23:41:41 +0100733{
734 struct fadt_descriptor_rev1 *fadt = find_fadt();
735 if (!fadt)
736 return;
David Woodhoused304fe42013-02-23 00:24:48 +0000737 u32 pm_tmr = le32_to_cpu(fadt->pm_tmr_blk);
Gerd Hoffmann5b631092013-07-25 09:47:18 +0200738 u32 pm1a_cnt = le32_to_cpu(fadt->pm1a_cnt_blk);
David Woodhouse3219dfa2013-02-03 23:41:41 +0100739 dprintf(4, "pm_tmr_blk=%x\n", pm_tmr);
David Woodhoused304fe42013-02-23 00:24:48 +0000740 if (pm_tmr)
Kevin O'Connor118605f2013-07-20 11:06:51 -0400741 pmtimer_setup(pm_tmr);
Gerd Hoffmann5b631092013-07-25 09:47:18 +0200742 if (pm1a_cnt)
743 acpi_pm1a_cnt = pm1a_cnt;
David Woodhoused338eb92013-02-23 00:24:49 +0000744
745 // Theoretically we should check the 'reset_reg_sup' flag, but Windows
746 // doesn't and thus nobody seems to *set* it. If the table is large enough
747 // to include it, let the sanity checks in acpi_set_reset_reg() suffice.
748 if (fadt->length >= 129) {
749 void *p = fadt;
750 acpi_set_reset_reg(p + 116, *(u8 *)(p + 128));
751 }
752}
753
754static struct acpi_20_generic_address acpi_reset_reg;
755static u8 acpi_reset_val;
756
757void
758acpi_reboot(void)
759{
760 // Check it passed the sanity checks in acpi_set_reset_reg() and was set
761 if (acpi_reset_reg.register_bit_width != 8)
762 return;
763
764 u64 addr = le64_to_cpu(acpi_reset_reg.address);
765
766 dprintf(1, "ACPI hard reset %d:%llx (%x)\n",
767 acpi_reset_reg.address_space_id, addr, acpi_reset_val);
768
769 switch (acpi_reset_reg.address_space_id) {
770 case 0: // System Memory
771 writeb((void *)(u32)addr, acpi_reset_val);
772 break;
773 case 1: // System I/O
774 outb(acpi_reset_val, addr);
775 break;
776 case 2: // PCI config space
777 pci_config_writeb(acpi_ga_to_bdf(addr), addr & 0xffff, acpi_reset_val);
778 break;
779 }
780}
781
782void
783acpi_set_reset_reg(struct acpi_20_generic_address *reg, u8 val)
784{
785 if (!reg || reg->address_space_id > 2 ||
786 reg->register_bit_width != 8 || reg->register_bit_offset)
787 return;
788
789 acpi_reset_reg = *reg;
790 acpi_reset_val = val;
Kevin O'Connor9967ab72008-12-18 21:57:33 -0500791}