xref: /openbmc/qemu/hw/loongarch/virt-acpi-build.c (revision cf2f8cf3b7b2d4eadb4023eb18f4ae45b294fe82)
15dd3a714SBibo Mao /* SPDX-License-Identifier: GPL-2.0-or-later */
25dd3a714SBibo Mao /*
35dd3a714SBibo Mao  * Support for generating ACPI tables and passing them to Guests
45dd3a714SBibo Mao  *
55dd3a714SBibo Mao  * Copyright (C) 2021 Loongson Technology Corporation Limited
65dd3a714SBibo Mao  */
75dd3a714SBibo Mao 
85dd3a714SBibo Mao #include "qemu/osdep.h"
95dd3a714SBibo Mao #include "qapi/error.h"
105dd3a714SBibo Mao #include "qemu/error-report.h"
115dd3a714SBibo Mao #include "qemu/bitmap.h"
125dd3a714SBibo Mao #include "hw/pci/pci.h"
135dd3a714SBibo Mao #include "hw/core/cpu.h"
145dd3a714SBibo Mao #include "target/loongarch/cpu.h"
155dd3a714SBibo Mao #include "hw/acpi/acpi-defs.h"
165dd3a714SBibo Mao #include "hw/acpi/acpi.h"
175dd3a714SBibo Mao #include "hw/nvram/fw_cfg.h"
185dd3a714SBibo Mao #include "hw/acpi/bios-linker-loader.h"
195dd3a714SBibo Mao #include "migration/vmstate.h"
205dd3a714SBibo Mao #include "hw/mem/memory-device.h"
215dd3a714SBibo Mao #include "system/reset.h"
225dd3a714SBibo Mao 
235dd3a714SBibo Mao /* Supported chipsets: */
245dd3a714SBibo Mao #include "hw/pci-host/ls7a.h"
255dd3a714SBibo Mao #include "hw/loongarch/virt.h"
265dd3a714SBibo Mao 
275dd3a714SBibo Mao #include "hw/acpi/utils.h"
285dd3a714SBibo Mao #include "hw/acpi/pci.h"
295dd3a714SBibo Mao 
305dd3a714SBibo Mao #include "qom/qom-qobject.h"
315dd3a714SBibo Mao 
325dd3a714SBibo Mao #include "hw/acpi/generic_event_device.h"
335dd3a714SBibo Mao #include "hw/pci-host/gpex.h"
345dd3a714SBibo Mao #include "system/system.h"
355dd3a714SBibo Mao #include "system/tpm.h"
365dd3a714SBibo Mao #include "hw/platform-bus.h"
375dd3a714SBibo Mao #include "hw/acpi/aml-build.h"
385dd3a714SBibo Mao #include "hw/acpi/hmat.h"
395dd3a714SBibo Mao 
405dd3a714SBibo Mao #define ACPI_BUILD_ALIGN_SIZE             0x1000
415dd3a714SBibo Mao #define ACPI_BUILD_TABLE_SIZE             0x20000
425dd3a714SBibo Mao 
435dd3a714SBibo Mao #ifdef DEBUG_ACPI_BUILD
445dd3a714SBibo Mao #define ACPI_BUILD_DPRINTF(fmt, ...)        \
455dd3a714SBibo Mao     do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0)
465dd3a714SBibo Mao #else
475dd3a714SBibo Mao #define ACPI_BUILD_DPRINTF(fmt, ...)
485dd3a714SBibo Mao #endif
495dd3a714SBibo Mao 
virt_madt_cpu_entry(int uid,const CPUArchIdList * apic_ids,GArray * entry,bool force_enabled)50*25cdac98SBibo Mao static void virt_madt_cpu_entry(int uid,
51*25cdac98SBibo Mao                                 const CPUArchIdList *apic_ids,
52*25cdac98SBibo Mao                                 GArray *entry, bool force_enabled)
53*25cdac98SBibo Mao {
54*25cdac98SBibo Mao     uint32_t flags, apic_id = apic_ids->cpus[uid].arch_id;
55*25cdac98SBibo Mao 
56*25cdac98SBibo Mao     flags = apic_ids->cpus[uid].cpu || force_enabled ? 1 /* Enabled */ : 0;
57*25cdac98SBibo Mao 
58*25cdac98SBibo Mao     /* Rev 1.0b, Table 5-13 Processor Local APIC Structure */
59*25cdac98SBibo Mao     build_append_int_noprefix(entry, 0, 1);       /* Type */
60*25cdac98SBibo Mao     build_append_int_noprefix(entry, 8, 1);       /* Length */
61*25cdac98SBibo Mao     build_append_int_noprefix(entry, uid, 1);     /* ACPI Processor ID */
62*25cdac98SBibo Mao     build_append_int_noprefix(entry, apic_id, 1); /* APIC ID */
63*25cdac98SBibo Mao     build_append_int_noprefix(entry, flags, 4); /* Flags */
64*25cdac98SBibo Mao }
65*25cdac98SBibo Mao 
665dd3a714SBibo Mao /* build FADT */
init_common_fadt_data(AcpiFadtData * data)675dd3a714SBibo Mao static void init_common_fadt_data(AcpiFadtData *data)
685dd3a714SBibo Mao {
695dd3a714SBibo Mao     AcpiFadtData fadt = {
705dd3a714SBibo Mao         /* ACPI 5.0: 4.1 Hardware-Reduced ACPI */
715dd3a714SBibo Mao         .rev = 5,
725dd3a714SBibo Mao         .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
735dd3a714SBibo Mao                   (1 << ACPI_FADT_F_RESET_REG_SUP)),
745dd3a714SBibo Mao 
755dd3a714SBibo Mao         /* ACPI 5.0: 4.8.3.7 Sleep Control and Status Registers */
765dd3a714SBibo Mao         .sleep_ctl = {
775dd3a714SBibo Mao             .space_id = AML_AS_SYSTEM_MEMORY,
785dd3a714SBibo Mao             .bit_width = 8,
795dd3a714SBibo Mao             .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_CTL,
805dd3a714SBibo Mao         },
815dd3a714SBibo Mao         .sleep_sts = {
825dd3a714SBibo Mao             .space_id = AML_AS_SYSTEM_MEMORY,
835dd3a714SBibo Mao             .bit_width = 8,
845dd3a714SBibo Mao             .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_STS,
855dd3a714SBibo Mao         },
865dd3a714SBibo Mao 
875dd3a714SBibo Mao         /* ACPI 5.0: 4.8.3.6 Reset Register */
885dd3a714SBibo Mao         .reset_reg = {
895dd3a714SBibo Mao             .space_id = AML_AS_SYSTEM_MEMORY,
905dd3a714SBibo Mao             .bit_width = 8,
915dd3a714SBibo Mao             .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_RESET,
925dd3a714SBibo Mao         },
935dd3a714SBibo Mao         .reset_val = ACPI_GED_RESET_VALUE,
945dd3a714SBibo Mao     };
955dd3a714SBibo Mao     *data = fadt;
965dd3a714SBibo Mao }
975dd3a714SBibo Mao 
acpi_align_size(GArray * blob,unsigned align)985dd3a714SBibo Mao static void acpi_align_size(GArray *blob, unsigned align)
995dd3a714SBibo Mao {
1005dd3a714SBibo Mao     /*
1015dd3a714SBibo Mao      * Align size to multiple of given size. This reduces the chance
1025dd3a714SBibo Mao      * we need to change size in the future (breaking cross version migration).
1035dd3a714SBibo Mao      */
1045dd3a714SBibo Mao     g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
1055dd3a714SBibo Mao }
1065dd3a714SBibo Mao 
1075dd3a714SBibo Mao /* build FACS */
1085dd3a714SBibo Mao static void
build_facs(GArray * table_data)1095dd3a714SBibo Mao build_facs(GArray *table_data)
1105dd3a714SBibo Mao {
1115dd3a714SBibo Mao     const char *sig = "FACS";
1125dd3a714SBibo Mao     const uint8_t reserved[40] = {};
1135dd3a714SBibo Mao 
1145dd3a714SBibo Mao     g_array_append_vals(table_data, sig, 4); /* Signature */
1155dd3a714SBibo Mao     build_append_int_noprefix(table_data, 64, 4); /* Length */
1165dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */
1175dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */
1185dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0, 4); /* Global Lock */
1195dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0, 4); /* Flags */
1205dd3a714SBibo Mao     g_array_append_vals(table_data, reserved, 40); /* Reserved */
1215dd3a714SBibo Mao }
1225dd3a714SBibo Mao 
1235dd3a714SBibo Mao /* build MADT */
1245dd3a714SBibo Mao static void
build_madt(GArray * table_data,BIOSLinker * linker,LoongArchVirtMachineState * lvms)1255dd3a714SBibo Mao build_madt(GArray *table_data, BIOSLinker *linker,
1265dd3a714SBibo Mao            LoongArchVirtMachineState *lvms)
1275dd3a714SBibo Mao {
1285dd3a714SBibo Mao     MachineState *ms = MACHINE(lvms);
1295dd3a714SBibo Mao     MachineClass *mc = MACHINE_GET_CLASS(ms);
1305dd3a714SBibo Mao     const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
131*25cdac98SBibo Mao     int i, arch_id, flags;
1325dd3a714SBibo Mao     AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lvms->oem_id,
1335dd3a714SBibo Mao                         .oem_table_id = lvms->oem_table_id };
1345dd3a714SBibo Mao 
1355dd3a714SBibo Mao     acpi_table_begin(&table, table_data);
1365dd3a714SBibo Mao 
1375dd3a714SBibo Mao     /* Local APIC Address */
1385dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0, 4);
1395dd3a714SBibo Mao     build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
1405dd3a714SBibo Mao 
1415dd3a714SBibo Mao     for (i = 0; i < arch_ids->len; i++) {
1425dd3a714SBibo Mao         /* Processor Core Interrupt Controller Structure */
1435dd3a714SBibo Mao         arch_id = arch_ids->cpus[i].arch_id;
144*25cdac98SBibo Mao         flags   = arch_ids->cpus[i].cpu ? 1 : 0;
1455dd3a714SBibo Mao         build_append_int_noprefix(table_data, 17, 1);    /* Type */
1465dd3a714SBibo Mao         build_append_int_noprefix(table_data, 15, 1);    /* Length */
1475dd3a714SBibo Mao         build_append_int_noprefix(table_data, 1, 1);     /* Version */
1485dd3a714SBibo Mao         build_append_int_noprefix(table_data, i, 4);     /* ACPI Processor ID */
1495dd3a714SBibo Mao         build_append_int_noprefix(table_data, arch_id, 4); /* Core ID */
150*25cdac98SBibo Mao         build_append_int_noprefix(table_data, flags, 4); /* Flags */
1515dd3a714SBibo Mao     }
1525dd3a714SBibo Mao 
1535dd3a714SBibo Mao     /* Extend I/O Interrupt Controller Structure */
1545dd3a714SBibo Mao     build_append_int_noprefix(table_data, 20, 1);        /* Type */
1555dd3a714SBibo Mao     build_append_int_noprefix(table_data, 13, 1);        /* Length */
1565dd3a714SBibo Mao     build_append_int_noprefix(table_data, 1, 1);         /* Version */
1575dd3a714SBibo Mao     build_append_int_noprefix(table_data, 3, 1);         /* Cascade */
1585dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0, 1);         /* Node */
1595dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0xffff, 8);    /* Node map */
1605dd3a714SBibo Mao 
1615dd3a714SBibo Mao     /* MSI Interrupt Controller Structure */
1625dd3a714SBibo Mao     build_append_int_noprefix(table_data, 21, 1);        /* Type */
1635dd3a714SBibo Mao     build_append_int_noprefix(table_data, 19, 1);        /* Length */
1645dd3a714SBibo Mao     build_append_int_noprefix(table_data, 1, 1);         /* Version */
1655dd3a714SBibo Mao     build_append_int_noprefix(table_data, VIRT_PCH_MSI_ADDR_LOW, 8);/* Address */
1665dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0x40, 4);      /* Start */
1675dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0xc0, 4);      /* Count */
1685dd3a714SBibo Mao 
1695dd3a714SBibo Mao     /* Bridge I/O Interrupt Controller Structure */
1705dd3a714SBibo Mao     build_append_int_noprefix(table_data, 22, 1);        /* Type */
1715dd3a714SBibo Mao     build_append_int_noprefix(table_data, 17, 1);        /* Length */
1725dd3a714SBibo Mao     build_append_int_noprefix(table_data, 1, 1);         /* Version */
1735dd3a714SBibo Mao     build_append_int_noprefix(table_data, VIRT_PCH_REG_BASE, 8);/* Address */
1745dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0x1000, 2);    /* Size */
1755dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0, 2);         /* Id */
1765dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0x40, 2);      /* Base */
1775dd3a714SBibo Mao 
1785dd3a714SBibo Mao     acpi_table_end(linker, &table);
1795dd3a714SBibo Mao }
1805dd3a714SBibo Mao 
1815dd3a714SBibo Mao /* build SRAT */
1825dd3a714SBibo Mao static void
build_srat(GArray * table_data,BIOSLinker * linker,MachineState * machine)1835dd3a714SBibo Mao build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
1845dd3a714SBibo Mao {
1855dd3a714SBibo Mao     int i, arch_id, node_id;
1865dd3a714SBibo Mao     hwaddr len, base, gap;
1875dd3a714SBibo Mao     NodeInfo *numa_info;
1885dd3a714SBibo Mao     int nodes, nb_numa_nodes = machine->numa_state->num_nodes;
1895dd3a714SBibo Mao     LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
1905dd3a714SBibo Mao     MachineClass *mc = MACHINE_GET_CLASS(lvms);
1915dd3a714SBibo Mao     const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
1925dd3a714SBibo Mao     AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lvms->oem_id,
1935dd3a714SBibo Mao                         .oem_table_id = lvms->oem_table_id };
1945dd3a714SBibo Mao 
1955dd3a714SBibo Mao     acpi_table_begin(&table, table_data);
1965dd3a714SBibo Mao     build_append_int_noprefix(table_data, 1, 4); /* Reserved */
1975dd3a714SBibo Mao     build_append_int_noprefix(table_data, 0, 8); /* Reserved */
1985dd3a714SBibo Mao 
1995dd3a714SBibo Mao     for (i = 0; i < arch_ids->len; ++i) {
2005dd3a714SBibo Mao         arch_id = arch_ids->cpus[i].arch_id;
2015dd3a714SBibo Mao         node_id = arch_ids->cpus[i].props.node_id;
2025dd3a714SBibo Mao 
2035dd3a714SBibo Mao         /* Processor Local APIC/SAPIC Affinity Structure */
2045dd3a714SBibo Mao         build_append_int_noprefix(table_data, 0, 1);  /* Type  */
2055dd3a714SBibo Mao         build_append_int_noprefix(table_data, 16, 1); /* Length */
2065dd3a714SBibo Mao         /* Proximity Domain [7:0] */
2075dd3a714SBibo Mao         build_append_int_noprefix(table_data, node_id, 1);
2085dd3a714SBibo Mao         build_append_int_noprefix(table_data, arch_id, 1); /* APIC ID */
2095dd3a714SBibo Mao         /* Flags, Table 5-36 */
2105dd3a714SBibo Mao         build_append_int_noprefix(table_data, 1, 4);
2115dd3a714SBibo Mao         build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */
2125dd3a714SBibo Mao         /* Proximity Domain [31:8] */
2135dd3a714SBibo Mao         build_append_int_noprefix(table_data, 0, 3);
2145dd3a714SBibo Mao         build_append_int_noprefix(table_data, 0, 4); /* Reserved */
2155dd3a714SBibo Mao     }
2165dd3a714SBibo Mao 
2175dd3a714SBibo Mao     base = VIRT_LOWMEM_BASE;
2185dd3a714SBibo Mao     gap = VIRT_LOWMEM_SIZE;
2195dd3a714SBibo Mao     numa_info = machine->numa_state->nodes;
2205dd3a714SBibo Mao     nodes = nb_numa_nodes;
2215dd3a714SBibo Mao     if (!nodes) {
2225dd3a714SBibo Mao         nodes = 1;
2235dd3a714SBibo Mao     }
2245dd3a714SBibo Mao 
2255dd3a714SBibo Mao     for (i = 0; i < nodes; i++) {
2265dd3a714SBibo Mao         if (nb_numa_nodes) {
2275dd3a714SBibo Mao             len = numa_info[i].node_mem;
2285dd3a714SBibo Mao         } else {
2295dd3a714SBibo Mao             len = machine->ram_size;
2305dd3a714SBibo Mao         }
2315dd3a714SBibo Mao 
2325dd3a714SBibo Mao         /*
2335dd3a714SBibo Mao          * memory for the node splited into two part
2345dd3a714SBibo Mao          *   lowram:  [base, +gap)
2355dd3a714SBibo Mao          *   highram: [VIRT_HIGHMEM_BASE, +(len - gap))
2365dd3a714SBibo Mao          */
2375dd3a714SBibo Mao         if (len >= gap) {
2385dd3a714SBibo Mao             build_srat_memory(table_data, base, gap, i, MEM_AFFINITY_ENABLED);
2395dd3a714SBibo Mao             len -= gap;
2405dd3a714SBibo Mao             base = VIRT_HIGHMEM_BASE;
2415dd3a714SBibo Mao             gap = machine->ram_size - VIRT_LOWMEM_SIZE;
2425dd3a714SBibo Mao         }
2435dd3a714SBibo Mao 
2445dd3a714SBibo Mao         if (len) {
2455dd3a714SBibo Mao             build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
2465dd3a714SBibo Mao             base += len;
2475dd3a714SBibo Mao             gap  -= len;
2485dd3a714SBibo Mao         }
2495dd3a714SBibo Mao     }
2505dd3a714SBibo Mao 
2515dd3a714SBibo Mao     if (machine->device_memory) {
2525dd3a714SBibo Mao         build_srat_memory(table_data, machine->device_memory->base,
2535dd3a714SBibo Mao                           memory_region_size(&machine->device_memory->mr),
2545dd3a714SBibo Mao                           nodes - 1,
2555dd3a714SBibo Mao                           MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
2565dd3a714SBibo Mao     }
2575dd3a714SBibo Mao 
2585dd3a714SBibo Mao     acpi_table_end(linker, &table);
2595dd3a714SBibo Mao }
2605dd3a714SBibo Mao 
2615dd3a714SBibo Mao /*
2625dd3a714SBibo Mao  * Serial Port Console Redirection Table (SPCR)
2635dd3a714SBibo Mao  * https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
2645dd3a714SBibo Mao  */
2655dd3a714SBibo Mao static void
spcr_setup(GArray * table_data,BIOSLinker * linker,MachineState * machine)2665dd3a714SBibo Mao spcr_setup(GArray *table_data, BIOSLinker *linker, MachineState *machine)
2675dd3a714SBibo Mao {
2685dd3a714SBibo Mao     LoongArchVirtMachineState *lvms;
2695dd3a714SBibo Mao     AcpiSpcrData serial = {
2705dd3a714SBibo Mao         .interface_type = 0,       /* 16550 compatible */
2715dd3a714SBibo Mao         .base_addr.id = AML_AS_SYSTEM_MEMORY,
2725dd3a714SBibo Mao         .base_addr.width = 32,
2735dd3a714SBibo Mao         .base_addr.offset = 0,
2745dd3a714SBibo Mao         .base_addr.size = 1,
2755dd3a714SBibo Mao         .base_addr.addr = VIRT_UART_BASE,
2765dd3a714SBibo Mao         .interrupt_type = 0,       /* Interrupt not supported */
2775dd3a714SBibo Mao         .pc_interrupt = 0,
2785dd3a714SBibo Mao         .interrupt = VIRT_UART_IRQ,
2795dd3a714SBibo Mao         .baud_rate = 7,            /* 115200 */
2805dd3a714SBibo Mao         .parity = 0,
2815dd3a714SBibo Mao         .stop_bits = 1,
2825dd3a714SBibo Mao         .flow_control = 0,
2835dd3a714SBibo Mao         .terminal_type = 3,        /* ANSI */
2845dd3a714SBibo Mao         .language = 0,             /* Language */
2855dd3a714SBibo Mao         .pci_device_id = 0xffff,   /* not a PCI device*/
2865dd3a714SBibo Mao         .pci_vendor_id = 0xffff,   /* not a PCI device*/
2875dd3a714SBibo Mao         .pci_bus = 0,
2885dd3a714SBibo Mao         .pci_device = 0,
2895dd3a714SBibo Mao         .pci_function = 0,
2905dd3a714SBibo Mao         .pci_flags = 0,
2915dd3a714SBibo Mao         .pci_segment = 0,
2925dd3a714SBibo Mao     };
2935dd3a714SBibo Mao 
2945dd3a714SBibo Mao     lvms = LOONGARCH_VIRT_MACHINE(machine);
2955dd3a714SBibo Mao     /*
2965dd3a714SBibo Mao      * Passing NULL as the SPCR Table for Revision 2 doesn't support
2975dd3a714SBibo Mao      * NameSpaceString.
2985dd3a714SBibo Mao      */
2995dd3a714SBibo Mao     build_spcr(table_data, linker, &serial, 2, lvms->oem_id,
3005dd3a714SBibo Mao                lvms->oem_table_id, NULL);
3015dd3a714SBibo Mao }
3025dd3a714SBibo Mao 
3035dd3a714SBibo Mao typedef
3045dd3a714SBibo Mao struct AcpiBuildState {
3055dd3a714SBibo Mao     /* Copy of table in RAM (for patching). */
3065dd3a714SBibo Mao     MemoryRegion *table_mr;
3075dd3a714SBibo Mao     /* Is table patched? */
3085dd3a714SBibo Mao     uint8_t patched;
3095dd3a714SBibo Mao     void *rsdp;
3105dd3a714SBibo Mao     MemoryRegion *rsdp_mr;
3115dd3a714SBibo Mao     MemoryRegion *linker_mr;
3125dd3a714SBibo Mao } AcpiBuildState;
3135dd3a714SBibo Mao 
build_uart_device_aml(Aml * table,int index)3145dd3a714SBibo Mao static void build_uart_device_aml(Aml *table, int index)
3155dd3a714SBibo Mao {
3165dd3a714SBibo Mao     Aml *dev;
3175dd3a714SBibo Mao     Aml *crs;
3185dd3a714SBibo Mao     Aml *pkg0, *pkg1, *pkg2;
3195dd3a714SBibo Mao     Aml *scope;
3205dd3a714SBibo Mao     uint32_t uart_irq;
3215dd3a714SBibo Mao     uint64_t base;
3225dd3a714SBibo Mao 
3235dd3a714SBibo Mao     uart_irq = VIRT_UART_IRQ + index;
3245dd3a714SBibo Mao     base = VIRT_UART_BASE + index * VIRT_UART_SIZE;
3255dd3a714SBibo Mao     scope = aml_scope("_SB");
3265dd3a714SBibo Mao     dev = aml_device("COM%d", index);
3275dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
3285dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_UID", aml_int(index)));
3295dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
3305dd3a714SBibo Mao     crs = aml_resource_template();
3315dd3a714SBibo Mao     aml_append(crs,
3325dd3a714SBibo Mao         aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
3335dd3a714SBibo Mao                          AML_NON_CACHEABLE, AML_READ_WRITE,
3345dd3a714SBibo Mao                          0, base, base + VIRT_UART_SIZE - 1,
3355dd3a714SBibo Mao                          0, VIRT_UART_SIZE));
3365dd3a714SBibo Mao     aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
3375dd3a714SBibo Mao                                   AML_SHARED, &uart_irq, 1));
3385dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_CRS", crs));
3395dd3a714SBibo Mao     pkg0 = aml_package(0x2);
3405dd3a714SBibo Mao     aml_append(pkg0, aml_int(0x05F5E100));
3415dd3a714SBibo Mao     aml_append(pkg0, aml_string("clock-frenquency"));
3425dd3a714SBibo Mao     pkg1 = aml_package(0x1);
3435dd3a714SBibo Mao     aml_append(pkg1, pkg0);
3445dd3a714SBibo Mao     pkg2 = aml_package(0x2);
3455dd3a714SBibo Mao     aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301"));
3465dd3a714SBibo Mao     aml_append(pkg2, pkg1);
3475dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_DSD", pkg2));
3485dd3a714SBibo Mao     aml_append(scope, dev);
3495dd3a714SBibo Mao     aml_append(table, scope);
3505dd3a714SBibo Mao }
3515dd3a714SBibo Mao 
3525dd3a714SBibo Mao static void
build_la_ged_aml(Aml * dsdt,MachineState * machine)3535dd3a714SBibo Mao build_la_ged_aml(Aml *dsdt, MachineState *machine)
3545dd3a714SBibo Mao {
3555dd3a714SBibo Mao     uint32_t event;
3565dd3a714SBibo Mao     LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
357*25cdac98SBibo Mao     CPUHotplugFeatures opts;
3585dd3a714SBibo Mao 
3595dd3a714SBibo Mao     build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
3605dd3a714SBibo Mao                   HOTPLUG_HANDLER(lvms->acpi_ged),
3615dd3a714SBibo Mao                   VIRT_SCI_IRQ, AML_SYSTEM_MEMORY,
3625dd3a714SBibo Mao                   VIRT_GED_EVT_ADDR);
3635dd3a714SBibo Mao     event = object_property_get_uint(OBJECT(lvms->acpi_ged),
3645dd3a714SBibo Mao                                      "ged-event", &error_abort);
3655dd3a714SBibo Mao     if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
3665dd3a714SBibo Mao         build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL,
3675dd3a714SBibo Mao                                  AML_SYSTEM_MEMORY,
3685dd3a714SBibo Mao                                  VIRT_GED_MEM_ADDR);
3695dd3a714SBibo Mao     }
370*25cdac98SBibo Mao 
371*25cdac98SBibo Mao     if (event & ACPI_GED_CPU_HOTPLUG_EVT) {
372*25cdac98SBibo Mao         opts.acpi_1_compatible = false;
373*25cdac98SBibo Mao         opts.has_legacy_cphp = false;
374*25cdac98SBibo Mao         opts.fw_unplugs_cpu = false;
375*25cdac98SBibo Mao         opts.smi_path = NULL;
376*25cdac98SBibo Mao 
377*25cdac98SBibo Mao         build_cpus_aml(dsdt, machine, opts, virt_madt_cpu_entry,
378*25cdac98SBibo Mao                        VIRT_GED_CPUHP_ADDR, "\\_SB",
379*25cdac98SBibo Mao                        AML_GED_EVT_CPU_SCAN_METHOD, AML_SYSTEM_MEMORY);
380*25cdac98SBibo Mao     }
381*25cdac98SBibo Mao 
3825dd3a714SBibo Mao     acpi_dsdt_add_power_button(dsdt);
3835dd3a714SBibo Mao }
3845dd3a714SBibo Mao 
build_pci_device_aml(Aml * scope,LoongArchVirtMachineState * lvms)3855dd3a714SBibo Mao static void build_pci_device_aml(Aml *scope, LoongArchVirtMachineState *lvms)
3865dd3a714SBibo Mao {
3875dd3a714SBibo Mao     struct GPEXConfig cfg = {
3885dd3a714SBibo Mao         .mmio64.base = VIRT_PCI_MEM_BASE,
3895dd3a714SBibo Mao         .mmio64.size = VIRT_PCI_MEM_SIZE,
3905dd3a714SBibo Mao         .pio.base    = VIRT_PCI_IO_BASE,
3915dd3a714SBibo Mao         .pio.size    = VIRT_PCI_IO_SIZE,
3925dd3a714SBibo Mao         .ecam.base   = VIRT_PCI_CFG_BASE,
3935dd3a714SBibo Mao         .ecam.size   = VIRT_PCI_CFG_SIZE,
3945dd3a714SBibo Mao         .irq         = VIRT_GSI_BASE + VIRT_DEVICE_IRQS,
3955dd3a714SBibo Mao         .bus         = lvms->pci_bus,
3965dd3a714SBibo Mao     };
3975dd3a714SBibo Mao 
3985dd3a714SBibo Mao     acpi_dsdt_add_gpex(scope, &cfg);
3995dd3a714SBibo Mao }
4005dd3a714SBibo Mao 
build_flash_aml(Aml * scope,LoongArchVirtMachineState * lvms)4015dd3a714SBibo Mao static void build_flash_aml(Aml *scope, LoongArchVirtMachineState *lvms)
4025dd3a714SBibo Mao {
4035dd3a714SBibo Mao     Aml *dev, *crs;
4045dd3a714SBibo Mao     MemoryRegion *flash_mem;
4055dd3a714SBibo Mao 
4065dd3a714SBibo Mao     hwaddr flash0_base;
4075dd3a714SBibo Mao     hwaddr flash0_size;
4085dd3a714SBibo Mao 
4095dd3a714SBibo Mao     hwaddr flash1_base;
4105dd3a714SBibo Mao     hwaddr flash1_size;
4115dd3a714SBibo Mao 
4125dd3a714SBibo Mao     flash_mem = pflash_cfi01_get_memory(lvms->flash[0]);
4135dd3a714SBibo Mao     flash0_base = flash_mem->addr;
4145dd3a714SBibo Mao     flash0_size = memory_region_size(flash_mem);
4155dd3a714SBibo Mao 
4165dd3a714SBibo Mao     flash_mem = pflash_cfi01_get_memory(lvms->flash[1]);
4175dd3a714SBibo Mao     flash1_base = flash_mem->addr;
4185dd3a714SBibo Mao     flash1_size = memory_region_size(flash_mem);
4195dd3a714SBibo Mao 
4205dd3a714SBibo Mao     dev = aml_device("FLS0");
4215dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
4225dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_UID", aml_int(0)));
4235dd3a714SBibo Mao 
4245dd3a714SBibo Mao     crs = aml_resource_template();
4255dd3a714SBibo Mao     aml_append(crs, aml_memory32_fixed(flash0_base, flash0_size,
4265dd3a714SBibo Mao                                        AML_READ_WRITE));
4275dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_CRS", crs));
4285dd3a714SBibo Mao     aml_append(scope, dev);
4295dd3a714SBibo Mao 
4305dd3a714SBibo Mao     dev = aml_device("FLS1");
4315dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
4325dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_UID", aml_int(1)));
4335dd3a714SBibo Mao 
4345dd3a714SBibo Mao     crs = aml_resource_template();
4355dd3a714SBibo Mao     aml_append(crs, aml_memory32_fixed(flash1_base, flash1_size,
4365dd3a714SBibo Mao                                        AML_READ_WRITE));
4375dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_CRS", crs));
4385dd3a714SBibo Mao     aml_append(scope, dev);
4395dd3a714SBibo Mao }
4405dd3a714SBibo Mao 
4415dd3a714SBibo Mao #ifdef CONFIG_TPM
acpi_dsdt_add_tpm(Aml * scope,LoongArchVirtMachineState * vms)4425dd3a714SBibo Mao static void acpi_dsdt_add_tpm(Aml *scope, LoongArchVirtMachineState *vms)
4435dd3a714SBibo Mao {
4445dd3a714SBibo Mao     PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
4455dd3a714SBibo Mao     hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS;
4465dd3a714SBibo Mao     SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find());
4475dd3a714SBibo Mao     MemoryRegion *sbdev_mr;
4485dd3a714SBibo Mao     hwaddr tpm_base;
4495dd3a714SBibo Mao 
4505dd3a714SBibo Mao     if (!sbdev) {
4515dd3a714SBibo Mao         return;
4525dd3a714SBibo Mao     }
4535dd3a714SBibo Mao 
4545dd3a714SBibo Mao     tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
4555dd3a714SBibo Mao     assert(tpm_base != -1);
4565dd3a714SBibo Mao 
4575dd3a714SBibo Mao     tpm_base += pbus_base;
4585dd3a714SBibo Mao 
4595dd3a714SBibo Mao     sbdev_mr = sysbus_mmio_get_region(sbdev, 0);
4605dd3a714SBibo Mao 
4615dd3a714SBibo Mao     Aml *dev = aml_device("TPM0");
4625dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
4635dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device")));
4645dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_UID", aml_int(0)));
4655dd3a714SBibo Mao 
4665dd3a714SBibo Mao     Aml *crs = aml_resource_template();
4675dd3a714SBibo Mao     aml_append(crs,
4685dd3a714SBibo Mao                aml_memory32_fixed(tpm_base,
4695dd3a714SBibo Mao                                   (uint32_t)memory_region_size(sbdev_mr),
4705dd3a714SBibo Mao                                   AML_READ_WRITE));
4715dd3a714SBibo Mao     aml_append(dev, aml_name_decl("_CRS", crs));
4725dd3a714SBibo Mao     aml_append(scope, dev);
4735dd3a714SBibo Mao }
4745dd3a714SBibo Mao #endif
4755dd3a714SBibo Mao 
4765dd3a714SBibo Mao /* build DSDT */
4775dd3a714SBibo Mao static void
build_dsdt(GArray * table_data,BIOSLinker * linker,MachineState * machine)4785dd3a714SBibo Mao build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
4795dd3a714SBibo Mao {
4805dd3a714SBibo Mao     int i;
4815dd3a714SBibo Mao     Aml *dsdt, *scope, *pkg;
4825dd3a714SBibo Mao     LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
4835dd3a714SBibo Mao     AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lvms->oem_id,
4845dd3a714SBibo Mao                         .oem_table_id = lvms->oem_table_id };
4855dd3a714SBibo Mao 
4865dd3a714SBibo Mao     acpi_table_begin(&table, table_data);
4875dd3a714SBibo Mao     dsdt = init_aml_allocator();
4885dd3a714SBibo Mao     for (i = 0; i < VIRT_UART_COUNT; i++) {
4895dd3a714SBibo Mao         build_uart_device_aml(dsdt, i);
4905dd3a714SBibo Mao     }
4915dd3a714SBibo Mao     build_pci_device_aml(dsdt, lvms);
4925dd3a714SBibo Mao     build_la_ged_aml(dsdt, machine);
4935dd3a714SBibo Mao     build_flash_aml(dsdt, lvms);
4945dd3a714SBibo Mao #ifdef CONFIG_TPM
4955dd3a714SBibo Mao     acpi_dsdt_add_tpm(dsdt, lvms);
4965dd3a714SBibo Mao #endif
4975dd3a714SBibo Mao     /* System State Package */
4985dd3a714SBibo Mao     scope = aml_scope("\\");
4995dd3a714SBibo Mao     pkg = aml_package(4);
5005dd3a714SBibo Mao     aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5));
5015dd3a714SBibo Mao     aml_append(pkg, aml_int(0)); /* ignored */
5025dd3a714SBibo Mao     aml_append(pkg, aml_int(0)); /* reserved */
5035dd3a714SBibo Mao     aml_append(pkg, aml_int(0)); /* reserved */
5045dd3a714SBibo Mao     aml_append(scope, aml_name_decl("_S5", pkg));
5055dd3a714SBibo Mao     aml_append(dsdt, scope);
5065dd3a714SBibo Mao     /* Copy AML table into ACPI tables blob and patch header there */
5075dd3a714SBibo Mao     g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
5085dd3a714SBibo Mao     acpi_table_end(linker, &table);
5095dd3a714SBibo Mao     free_aml_allocator();
5105dd3a714SBibo Mao }
5115dd3a714SBibo Mao 
acpi_build(AcpiBuildTables * tables,MachineState * machine)5125dd3a714SBibo Mao static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
5135dd3a714SBibo Mao {
5145dd3a714SBibo Mao     LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
5155dd3a714SBibo Mao     GArray *table_offsets;
5165dd3a714SBibo Mao     AcpiFadtData fadt_data;
5175dd3a714SBibo Mao     unsigned facs, rsdt, dsdt;
5185dd3a714SBibo Mao     uint8_t *u;
5195dd3a714SBibo Mao     GArray *tables_blob = tables->table_data;
5205dd3a714SBibo Mao 
5215dd3a714SBibo Mao     init_common_fadt_data(&fadt_data);
5225dd3a714SBibo Mao 
5235dd3a714SBibo Mao     table_offsets = g_array_new(false, true, sizeof(uint32_t));
5245dd3a714SBibo Mao     ACPI_BUILD_DPRINTF("init ACPI tables\n");
5255dd3a714SBibo Mao 
5265dd3a714SBibo Mao     bios_linker_loader_alloc(tables->linker,
5275dd3a714SBibo Mao                              ACPI_BUILD_TABLE_FILE, tables_blob,
5285dd3a714SBibo Mao                              64, false);
5295dd3a714SBibo Mao 
5305dd3a714SBibo Mao     /*
5315dd3a714SBibo Mao      * FACS is pointed to by FADT.
5325dd3a714SBibo Mao      * We place it first since it's the only table that has alignment
5335dd3a714SBibo Mao      * requirements.
5345dd3a714SBibo Mao      */
5355dd3a714SBibo Mao     facs = tables_blob->len;
5365dd3a714SBibo Mao     build_facs(tables_blob);
5375dd3a714SBibo Mao 
5385dd3a714SBibo Mao     /* DSDT is pointed to by FADT */
5395dd3a714SBibo Mao     dsdt = tables_blob->len;
5405dd3a714SBibo Mao     build_dsdt(tables_blob, tables->linker, machine);
5415dd3a714SBibo Mao 
5425dd3a714SBibo Mao     /* ACPI tables pointed to by RSDT */
5435dd3a714SBibo Mao     acpi_add_table(table_offsets, tables_blob);
5445dd3a714SBibo Mao     fadt_data.facs_tbl_offset = &facs;
5455dd3a714SBibo Mao     fadt_data.dsdt_tbl_offset = &dsdt;
5465dd3a714SBibo Mao     fadt_data.xdsdt_tbl_offset = &dsdt;
5475dd3a714SBibo Mao     build_fadt(tables_blob, tables->linker, &fadt_data,
5485dd3a714SBibo Mao                lvms->oem_id, lvms->oem_table_id);
5495dd3a714SBibo Mao 
5505dd3a714SBibo Mao     acpi_add_table(table_offsets, tables_blob);
5515dd3a714SBibo Mao     build_madt(tables_blob, tables->linker, lvms);
5525dd3a714SBibo Mao 
5535dd3a714SBibo Mao     acpi_add_table(table_offsets, tables_blob);
5545dd3a714SBibo Mao     build_pptt(tables_blob, tables->linker, machine,
5555dd3a714SBibo Mao                lvms->oem_id, lvms->oem_table_id);
5565dd3a714SBibo Mao 
5575dd3a714SBibo Mao     acpi_add_table(table_offsets, tables_blob);
5585dd3a714SBibo Mao     build_srat(tables_blob, tables->linker, machine);
5595dd3a714SBibo Mao     acpi_add_table(table_offsets, tables_blob);
5605dd3a714SBibo Mao     spcr_setup(tables_blob, tables->linker, machine);
5615dd3a714SBibo Mao 
5625dd3a714SBibo Mao     if (machine->numa_state->num_nodes) {
5635dd3a714SBibo Mao         if (machine->numa_state->have_numa_distance) {
5645dd3a714SBibo Mao             acpi_add_table(table_offsets, tables_blob);
5655dd3a714SBibo Mao             build_slit(tables_blob, tables->linker, machine, lvms->oem_id,
5665dd3a714SBibo Mao                        lvms->oem_table_id);
5675dd3a714SBibo Mao         }
5685dd3a714SBibo Mao         if (machine->numa_state->hmat_enabled) {
5695dd3a714SBibo Mao             acpi_add_table(table_offsets, tables_blob);
5705dd3a714SBibo Mao             build_hmat(tables_blob, tables->linker, machine->numa_state,
5715dd3a714SBibo Mao                        lvms->oem_id, lvms->oem_table_id);
5725dd3a714SBibo Mao         }
5735dd3a714SBibo Mao     }
5745dd3a714SBibo Mao 
5755dd3a714SBibo Mao     acpi_add_table(table_offsets, tables_blob);
5765dd3a714SBibo Mao     {
5775dd3a714SBibo Mao         AcpiMcfgInfo mcfg = {
5785dd3a714SBibo Mao            .base = cpu_to_le64(VIRT_PCI_CFG_BASE),
5795dd3a714SBibo Mao            .size = cpu_to_le64(VIRT_PCI_CFG_SIZE),
5805dd3a714SBibo Mao         };
5815dd3a714SBibo Mao         build_mcfg(tables_blob, tables->linker, &mcfg, lvms->oem_id,
5825dd3a714SBibo Mao                    lvms->oem_table_id);
5835dd3a714SBibo Mao     }
5845dd3a714SBibo Mao 
5855dd3a714SBibo Mao #ifdef CONFIG_TPM
5865dd3a714SBibo Mao     /* TPM info */
5875dd3a714SBibo Mao     if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) {
5885dd3a714SBibo Mao         acpi_add_table(table_offsets, tables_blob);
5895dd3a714SBibo Mao         build_tpm2(tables_blob, tables->linker,
5905dd3a714SBibo Mao                    tables->tcpalog, lvms->oem_id,
5915dd3a714SBibo Mao                    lvms->oem_table_id);
5925dd3a714SBibo Mao     }
5935dd3a714SBibo Mao #endif
5945dd3a714SBibo Mao     /* Add tables supplied by user (if any) */
5955dd3a714SBibo Mao     for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
5965dd3a714SBibo Mao         unsigned len = acpi_table_len(u);
5975dd3a714SBibo Mao 
5985dd3a714SBibo Mao         acpi_add_table(table_offsets, tables_blob);
5995dd3a714SBibo Mao         g_array_append_vals(tables_blob, u, len);
6005dd3a714SBibo Mao     }
6015dd3a714SBibo Mao 
6025dd3a714SBibo Mao     /* RSDT is pointed to by RSDP */
6035dd3a714SBibo Mao     rsdt = tables_blob->len;
6045dd3a714SBibo Mao     build_rsdt(tables_blob, tables->linker, table_offsets,
6055dd3a714SBibo Mao                lvms->oem_id, lvms->oem_table_id);
6065dd3a714SBibo Mao 
6075dd3a714SBibo Mao     /* RSDP is in FSEG memory, so allocate it separately */
6085dd3a714SBibo Mao     {
6095dd3a714SBibo Mao         AcpiRsdpData rsdp_data = {
6105dd3a714SBibo Mao             .revision = 0,
6115dd3a714SBibo Mao             .oem_id = lvms->oem_id,
6125dd3a714SBibo Mao             .xsdt_tbl_offset = NULL,
6135dd3a714SBibo Mao             .rsdt_tbl_offset = &rsdt,
6145dd3a714SBibo Mao         };
6155dd3a714SBibo Mao         build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
6165dd3a714SBibo Mao     }
6175dd3a714SBibo Mao 
6185dd3a714SBibo Mao     /*
6195dd3a714SBibo Mao      * The align size is 128, warn if 64k is not enough therefore
6205dd3a714SBibo Mao      * the align size could be resized.
6215dd3a714SBibo Mao      */
6225dd3a714SBibo Mao     if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
6235dd3a714SBibo Mao         warn_report("ACPI table size %u exceeds %d bytes,"
6245dd3a714SBibo Mao                     " migration may not work",
6255dd3a714SBibo Mao                     tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
6265dd3a714SBibo Mao         error_printf("Try removing CPUs, NUMA nodes, memory slots"
6275dd3a714SBibo Mao                      " or PCI bridges.\n");
6285dd3a714SBibo Mao     }
6295dd3a714SBibo Mao 
6305dd3a714SBibo Mao     acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
6315dd3a714SBibo Mao 
6325dd3a714SBibo Mao     /* Cleanup memory that's no longer used. */
6335dd3a714SBibo Mao     g_array_free(table_offsets, true);
6345dd3a714SBibo Mao }
6355dd3a714SBibo Mao 
acpi_ram_update(MemoryRegion * mr,GArray * data)6365dd3a714SBibo Mao static void acpi_ram_update(MemoryRegion *mr, GArray *data)
6375dd3a714SBibo Mao {
6385dd3a714SBibo Mao     uint32_t size = acpi_data_len(data);
6395dd3a714SBibo Mao 
6405dd3a714SBibo Mao     /*
6415dd3a714SBibo Mao      * Make sure RAM size is correct - in case it got changed
6425dd3a714SBibo Mao      * e.g. by migration
6435dd3a714SBibo Mao      */
6445dd3a714SBibo Mao     memory_region_ram_resize(mr, size, &error_abort);
6455dd3a714SBibo Mao 
6465dd3a714SBibo Mao     memcpy(memory_region_get_ram_ptr(mr), data->data, size);
6475dd3a714SBibo Mao     memory_region_set_dirty(mr, 0, size);
6485dd3a714SBibo Mao }
6495dd3a714SBibo Mao 
acpi_build_update(void * build_opaque)6505dd3a714SBibo Mao static void acpi_build_update(void *build_opaque)
6515dd3a714SBibo Mao {
6525dd3a714SBibo Mao     AcpiBuildState *build_state = build_opaque;
6535dd3a714SBibo Mao     AcpiBuildTables tables;
6545dd3a714SBibo Mao 
6555dd3a714SBibo Mao     /* No state to update or already patched? Nothing to do. */
6565dd3a714SBibo Mao     if (!build_state || build_state->patched) {
6575dd3a714SBibo Mao         return;
6585dd3a714SBibo Mao     }
6595dd3a714SBibo Mao     build_state->patched = 1;
6605dd3a714SBibo Mao 
6615dd3a714SBibo Mao     acpi_build_tables_init(&tables);
6625dd3a714SBibo Mao 
6635dd3a714SBibo Mao     acpi_build(&tables, MACHINE(qdev_get_machine()));
6645dd3a714SBibo Mao 
6655dd3a714SBibo Mao     acpi_ram_update(build_state->table_mr, tables.table_data);
6665dd3a714SBibo Mao     acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
6675dd3a714SBibo Mao     acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
6685dd3a714SBibo Mao 
6695dd3a714SBibo Mao     acpi_build_tables_cleanup(&tables, true);
6705dd3a714SBibo Mao }
6715dd3a714SBibo Mao 
acpi_build_reset(void * build_opaque)6725dd3a714SBibo Mao static void acpi_build_reset(void *build_opaque)
6735dd3a714SBibo Mao {
6745dd3a714SBibo Mao     AcpiBuildState *build_state = build_opaque;
6755dd3a714SBibo Mao     build_state->patched = 0;
6765dd3a714SBibo Mao }
6775dd3a714SBibo Mao 
6785dd3a714SBibo Mao static const VMStateDescription vmstate_acpi_build = {
6795dd3a714SBibo Mao     .name = "acpi_build",
6805dd3a714SBibo Mao     .version_id = 1,
6815dd3a714SBibo Mao     .minimum_version_id = 1,
6825dd3a714SBibo Mao     .fields = (const VMStateField[]) {
6835dd3a714SBibo Mao         VMSTATE_UINT8(patched, AcpiBuildState),
6845dd3a714SBibo Mao         VMSTATE_END_OF_LIST()
6855dd3a714SBibo Mao     },
6865dd3a714SBibo Mao };
6875dd3a714SBibo Mao 
virt_is_acpi_enabled(LoongArchVirtMachineState * lvms)688e733b473SBibo Mao static bool virt_is_acpi_enabled(LoongArchVirtMachineState *lvms)
6895dd3a714SBibo Mao {
6905dd3a714SBibo Mao     if (lvms->acpi == ON_OFF_AUTO_OFF) {
6915dd3a714SBibo Mao         return false;
6925dd3a714SBibo Mao     }
6935dd3a714SBibo Mao     return true;
6945dd3a714SBibo Mao }
6955dd3a714SBibo Mao 
virt_acpi_setup(LoongArchVirtMachineState * lvms)696e733b473SBibo Mao void virt_acpi_setup(LoongArchVirtMachineState *lvms)
6975dd3a714SBibo Mao {
6985dd3a714SBibo Mao     AcpiBuildTables tables;
6995dd3a714SBibo Mao     AcpiBuildState *build_state;
7005dd3a714SBibo Mao 
7015dd3a714SBibo Mao     if (!lvms->fw_cfg) {
7025dd3a714SBibo Mao         ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
7035dd3a714SBibo Mao         return;
7045dd3a714SBibo Mao     }
7055dd3a714SBibo Mao 
706e733b473SBibo Mao     if (!virt_is_acpi_enabled(lvms)) {
7075dd3a714SBibo Mao         ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
7085dd3a714SBibo Mao         return;
7095dd3a714SBibo Mao     }
7105dd3a714SBibo Mao 
7115dd3a714SBibo Mao     build_state = g_malloc0(sizeof *build_state);
7125dd3a714SBibo Mao 
7135dd3a714SBibo Mao     acpi_build_tables_init(&tables);
7145dd3a714SBibo Mao     acpi_build(&tables, MACHINE(lvms));
7155dd3a714SBibo Mao 
7165dd3a714SBibo Mao     /* Now expose it all to Guest */
7175dd3a714SBibo Mao     build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
7185dd3a714SBibo Mao                                               build_state, tables.table_data,
7195dd3a714SBibo Mao                                               ACPI_BUILD_TABLE_FILE);
7205dd3a714SBibo Mao     assert(build_state->table_mr != NULL);
7215dd3a714SBibo Mao 
7225dd3a714SBibo Mao     build_state->linker_mr =
7235dd3a714SBibo Mao         acpi_add_rom_blob(acpi_build_update, build_state,
7245dd3a714SBibo Mao                           tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
7255dd3a714SBibo Mao 
7265dd3a714SBibo Mao     build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
7275dd3a714SBibo Mao                                              build_state, tables.rsdp,
7285dd3a714SBibo Mao                                              ACPI_BUILD_RSDP_FILE);
7295dd3a714SBibo Mao 
7305dd3a714SBibo Mao     fw_cfg_add_file(lvms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data,
7315dd3a714SBibo Mao                     acpi_data_len(tables.tcpalog));
7325dd3a714SBibo Mao 
7335dd3a714SBibo Mao     qemu_register_reset(acpi_build_reset, build_state);
7345dd3a714SBibo Mao     acpi_build_reset(build_state);
7355dd3a714SBibo Mao     vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
7365dd3a714SBibo Mao 
7375dd3a714SBibo Mao     /*
7385dd3a714SBibo Mao      * Cleanup tables but don't free the memory: we track it
7395dd3a714SBibo Mao      * in build_state.
7405dd3a714SBibo Mao      */
7415dd3a714SBibo Mao     acpi_build_tables_cleanup(&tables, false);
7425dd3a714SBibo Mao }
743