+ struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt));
+ struct facs_descriptor_rev1 *facs = memalign_high(64, sizeof(*facs));
+ void *dsdt = malloc_high(sizeof(AmlCode));
+
+ if (!fadt || !facs || !dsdt) {
+ dprintf(1, "Not enough memory for fadt!\n");
+ return NULL;
+ }
+
+ /* FACS */
+ memset(facs, 0, sizeof(*facs));
+ facs->signature = FACS_SIGNATURE;
+ facs->length = cpu_to_le32(sizeof(*facs));
+
+ /* DSDT */
+ memcpy(dsdt, AmlCode, sizeof(AmlCode));
+
+ /* FADT */
+ memset(fadt, 0, sizeof(*fadt));
+ fadt->firmware_ctrl = cpu_to_le32((u32)facs);
+ fadt->dsdt = cpu_to_le32((u32)dsdt);
+ fadt->model = 1;
+ fadt->reserved1 = 0;
+ int pm_sci_int = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+ fadt->sci_int = cpu_to_le16(pm_sci_int);
+ fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+ fadt->acpi_enable = 0xf1;
+ fadt->acpi_disable = 0xf0;
+ fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
+ fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
+ fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
+ fadt->pm1_evt_len = 4;
+ fadt->pm1_cnt_len = 2;
+ fadt->pm_tmr_len = 4;
+ fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+ fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+ fadt->gpe0_blk = cpu_to_le32(0xafe0);
+ fadt->gpe0_blk_len = 4;
+ /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC */
+ fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6));
+
+ build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1);
+
+ return fadt;
+}
+
+static void*
+build_madt(void)
+{
+ int madt_size = (sizeof(struct multiple_apic_table)
+ + sizeof(struct madt_processor_apic) * MaxCountCPUs
+ + sizeof(struct madt_io_apic)
+ + sizeof(struct madt_intsrcovr) * 16);
+ struct multiple_apic_table *madt = malloc_high(madt_size);
+ if (!madt) {
+ dprintf(1, "Not enough memory for madt!\n");
+ return NULL;
+ }
+ memset(madt, 0, madt_size);
+ madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
+ madt->flags = cpu_to_le32(1);
+ struct madt_processor_apic *apic = (void*)&madt[1];
+ int i;
+ for (i=0; i<MaxCountCPUs; i++) {
+ apic->type = APIC_PROCESSOR;
+ apic->length = sizeof(*apic);
+ apic->processor_id = i;
+ apic->local_apic_id = i;
+ if (i < CountCPUs)
+ apic->flags = cpu_to_le32(1);
+ else
+ apic->flags = cpu_to_le32(0);
+ apic++;
+ }
+ struct madt_io_apic *io_apic = (void*)apic;
+ io_apic->type = APIC_IO;
+ io_apic->length = sizeof(*io_apic);
+ io_apic->io_apic_id = CountCPUs;
+ io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR);
+ io_apic->interrupt = cpu_to_le32(0);
+
+ struct madt_intsrcovr *intsrcovr = (void*)&io_apic[1];
+ if (qemu_cfg_irq0_override()) {
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = APIC_XRUPT_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = 0;
+ intsrcovr->gsi = 2;
+ intsrcovr->flags = 0; /* conforms to bus specifications */
+ intsrcovr++;
+ }
+ for (i = 1; i < 16; i++) {
+ if (!(PCI_ISA_IRQ_MASK & (1 << i)))
+ /* No need for a INT source override structure. */
+ continue;
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = APIC_XRUPT_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = i;
+ intsrcovr->gsi = i;
+ intsrcovr->flags = 0xd; /* active high, level triggered */
+ intsrcovr++;
+ }
+
+ build_header((void*)madt, APIC_SIGNATURE, (void*)intsrcovr - (void*)madt, 1);
+ return madt;
+}
+
+#define SSDT_SIGNATURE 0x54445353 // SSDT
+static void*
+build_ssdt(void)
+{
+ int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs;
+ // calculate the length of processor block and scope block
+ // excluding PkgLength
+ int cpu_length = 13 * acpi_cpus + 4;
+
+ int length = sizeof(struct acpi_table_header) + 3 + cpu_length;
+ u8 *ssdt = malloc_high(length);
+ if (! ssdt) {
+ dprintf(1, "No space for ssdt!\n");
+ return NULL;
+ }