mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 08:43:55 -06:00
hw/loongarch/virt: Rename filename acpi-build with virt-acpi-build
File acpi-build.c is relative with virt machine type, rename it with virt-acpi-build.c Signed-off-by: Bibo Mao <maobibo@loongson.cn> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
This commit is contained in:
parent
ffaf7f0376
commit
5dd3a714d5
2 changed files with 1 additions and 1 deletions
713
hw/loongarch/virt-acpi-build.c
Normal file
713
hw/loongarch/virt-acpi-build.c
Normal file
|
@ -0,0 +1,713 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Support for generating ACPI tables and passing them to Guests
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/core/cpu.h"
|
||||
#include "target/loongarch/cpu.h"
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
#include "hw/acpi/bios-linker-loader.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/mem/memory-device.h"
|
||||
#include "system/reset.h"
|
||||
|
||||
/* Supported chipsets: */
|
||||
#include "hw/pci-host/ls7a.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
|
||||
#include "hw/acpi/utils.h"
|
||||
#include "hw/acpi/pci.h"
|
||||
|
||||
#include "qom/qom-qobject.h"
|
||||
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
#include "hw/pci-host/gpex.h"
|
||||
#include "system/system.h"
|
||||
#include "system/tpm.h"
|
||||
#include "hw/platform-bus.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/acpi/hmat.h"
|
||||
|
||||
#define ACPI_BUILD_ALIGN_SIZE 0x1000
|
||||
#define ACPI_BUILD_TABLE_SIZE 0x20000
|
||||
|
||||
#ifdef DEBUG_ACPI_BUILD
|
||||
#define ACPI_BUILD_DPRINTF(fmt, ...) \
|
||||
do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define ACPI_BUILD_DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* build FADT */
|
||||
static void init_common_fadt_data(AcpiFadtData *data)
|
||||
{
|
||||
AcpiFadtData fadt = {
|
||||
/* ACPI 5.0: 4.1 Hardware-Reduced ACPI */
|
||||
.rev = 5,
|
||||
.flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
|
||||
(1 << ACPI_FADT_F_RESET_REG_SUP)),
|
||||
|
||||
/* ACPI 5.0: 4.8.3.7 Sleep Control and Status Registers */
|
||||
.sleep_ctl = {
|
||||
.space_id = AML_AS_SYSTEM_MEMORY,
|
||||
.bit_width = 8,
|
||||
.address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_CTL,
|
||||
},
|
||||
.sleep_sts = {
|
||||
.space_id = AML_AS_SYSTEM_MEMORY,
|
||||
.bit_width = 8,
|
||||
.address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_STS,
|
||||
},
|
||||
|
||||
/* ACPI 5.0: 4.8.3.6 Reset Register */
|
||||
.reset_reg = {
|
||||
.space_id = AML_AS_SYSTEM_MEMORY,
|
||||
.bit_width = 8,
|
||||
.address = VIRT_GED_REG_ADDR + ACPI_GED_REG_RESET,
|
||||
},
|
||||
.reset_val = ACPI_GED_RESET_VALUE,
|
||||
};
|
||||
*data = fadt;
|
||||
}
|
||||
|
||||
static void acpi_align_size(GArray *blob, unsigned align)
|
||||
{
|
||||
/*
|
||||
* Align size to multiple of given size. This reduces the chance
|
||||
* we need to change size in the future (breaking cross version migration).
|
||||
*/
|
||||
g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
|
||||
}
|
||||
|
||||
/* build FACS */
|
||||
static void
|
||||
build_facs(GArray *table_data)
|
||||
{
|
||||
const char *sig = "FACS";
|
||||
const uint8_t reserved[40] = {};
|
||||
|
||||
g_array_append_vals(table_data, sig, 4); /* Signature */
|
||||
build_append_int_noprefix(table_data, 64, 4); /* Length */
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Global Lock */
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Flags */
|
||||
g_array_append_vals(table_data, reserved, 40); /* Reserved */
|
||||
}
|
||||
|
||||
/* build MADT */
|
||||
static void
|
||||
build_madt(GArray *table_data, BIOSLinker *linker,
|
||||
LoongArchVirtMachineState *lvms)
|
||||
{
|
||||
MachineState *ms = MACHINE(lvms);
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
|
||||
int i, arch_id;
|
||||
AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lvms->oem_id,
|
||||
.oem_table_id = lvms->oem_table_id };
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
|
||||
/* Local APIC Address */
|
||||
build_append_int_noprefix(table_data, 0, 4);
|
||||
build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
|
||||
|
||||
for (i = 0; i < arch_ids->len; i++) {
|
||||
/* Processor Core Interrupt Controller Structure */
|
||||
arch_id = arch_ids->cpus[i].arch_id;
|
||||
|
||||
build_append_int_noprefix(table_data, 17, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 15, 1); /* Length */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Version */
|
||||
build_append_int_noprefix(table_data, i, 4); /* ACPI Processor ID */
|
||||
build_append_int_noprefix(table_data, arch_id, 4); /* Core ID */
|
||||
build_append_int_noprefix(table_data, 1, 4); /* Flags */
|
||||
}
|
||||
|
||||
/* Extend I/O Interrupt Controller Structure */
|
||||
build_append_int_noprefix(table_data, 20, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 13, 1); /* Length */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Version */
|
||||
build_append_int_noprefix(table_data, 3, 1); /* Cascade */
|
||||
build_append_int_noprefix(table_data, 0, 1); /* Node */
|
||||
build_append_int_noprefix(table_data, 0xffff, 8); /* Node map */
|
||||
|
||||
/* MSI Interrupt Controller Structure */
|
||||
build_append_int_noprefix(table_data, 21, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 19, 1); /* Length */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Version */
|
||||
build_append_int_noprefix(table_data, VIRT_PCH_MSI_ADDR_LOW, 8);/* Address */
|
||||
build_append_int_noprefix(table_data, 0x40, 4); /* Start */
|
||||
build_append_int_noprefix(table_data, 0xc0, 4); /* Count */
|
||||
|
||||
/* Bridge I/O Interrupt Controller Structure */
|
||||
build_append_int_noprefix(table_data, 22, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 17, 1); /* Length */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Version */
|
||||
build_append_int_noprefix(table_data, VIRT_PCH_REG_BASE, 8);/* Address */
|
||||
build_append_int_noprefix(table_data, 0x1000, 2); /* Size */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* Id */
|
||||
build_append_int_noprefix(table_data, 0x40, 2); /* Base */
|
||||
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
/* build SRAT */
|
||||
static void
|
||||
build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
|
||||
{
|
||||
int i, arch_id, node_id;
|
||||
hwaddr len, base, gap;
|
||||
NodeInfo *numa_info;
|
||||
int nodes, nb_numa_nodes = machine->numa_state->num_nodes;
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
|
||||
MachineClass *mc = MACHINE_GET_CLASS(lvms);
|
||||
const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
|
||||
AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lvms->oem_id,
|
||||
.oem_table_id = lvms->oem_table_id };
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
build_append_int_noprefix(table_data, 1, 4); /* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 8); /* Reserved */
|
||||
|
||||
for (i = 0; i < arch_ids->len; ++i) {
|
||||
arch_id = arch_ids->cpus[i].arch_id;
|
||||
node_id = arch_ids->cpus[i].props.node_id;
|
||||
|
||||
/* Processor Local APIC/SAPIC Affinity Structure */
|
||||
build_append_int_noprefix(table_data, 0, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 16, 1); /* Length */
|
||||
/* Proximity Domain [7:0] */
|
||||
build_append_int_noprefix(table_data, node_id, 1);
|
||||
build_append_int_noprefix(table_data, arch_id, 1); /* APIC ID */
|
||||
/* Flags, Table 5-36 */
|
||||
build_append_int_noprefix(table_data, 1, 4);
|
||||
build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */
|
||||
/* Proximity Domain [31:8] */
|
||||
build_append_int_noprefix(table_data, 0, 3);
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
|
||||
}
|
||||
|
||||
base = VIRT_LOWMEM_BASE;
|
||||
gap = VIRT_LOWMEM_SIZE;
|
||||
numa_info = machine->numa_state->nodes;
|
||||
nodes = nb_numa_nodes;
|
||||
if (!nodes) {
|
||||
nodes = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nodes; i++) {
|
||||
if (nb_numa_nodes) {
|
||||
len = numa_info[i].node_mem;
|
||||
} else {
|
||||
len = machine->ram_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* memory for the node splited into two part
|
||||
* lowram: [base, +gap)
|
||||
* highram: [VIRT_HIGHMEM_BASE, +(len - gap))
|
||||
*/
|
||||
if (len >= gap) {
|
||||
build_srat_memory(table_data, base, gap, i, MEM_AFFINITY_ENABLED);
|
||||
len -= gap;
|
||||
base = VIRT_HIGHMEM_BASE;
|
||||
gap = machine->ram_size - VIRT_LOWMEM_SIZE;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
|
||||
base += len;
|
||||
gap -= len;
|
||||
}
|
||||
}
|
||||
|
||||
if (machine->device_memory) {
|
||||
build_srat_memory(table_data, machine->device_memory->base,
|
||||
memory_region_size(&machine->device_memory->mr),
|
||||
nodes - 1,
|
||||
MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
|
||||
}
|
||||
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serial Port Console Redirection Table (SPCR)
|
||||
* https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
|
||||
*/
|
||||
static void
|
||||
spcr_setup(GArray *table_data, BIOSLinker *linker, MachineState *machine)
|
||||
{
|
||||
LoongArchVirtMachineState *lvms;
|
||||
AcpiSpcrData serial = {
|
||||
.interface_type = 0, /* 16550 compatible */
|
||||
.base_addr.id = AML_AS_SYSTEM_MEMORY,
|
||||
.base_addr.width = 32,
|
||||
.base_addr.offset = 0,
|
||||
.base_addr.size = 1,
|
||||
.base_addr.addr = VIRT_UART_BASE,
|
||||
.interrupt_type = 0, /* Interrupt not supported */
|
||||
.pc_interrupt = 0,
|
||||
.interrupt = VIRT_UART_IRQ,
|
||||
.baud_rate = 7, /* 115200 */
|
||||
.parity = 0,
|
||||
.stop_bits = 1,
|
||||
.flow_control = 0,
|
||||
.terminal_type = 3, /* ANSI */
|
||||
.language = 0, /* Language */
|
||||
.pci_device_id = 0xffff, /* not a PCI device*/
|
||||
.pci_vendor_id = 0xffff, /* not a PCI device*/
|
||||
.pci_bus = 0,
|
||||
.pci_device = 0,
|
||||
.pci_function = 0,
|
||||
.pci_flags = 0,
|
||||
.pci_segment = 0,
|
||||
};
|
||||
|
||||
lvms = LOONGARCH_VIRT_MACHINE(machine);
|
||||
/*
|
||||
* Passing NULL as the SPCR Table for Revision 2 doesn't support
|
||||
* NameSpaceString.
|
||||
*/
|
||||
build_spcr(table_data, linker, &serial, 2, lvms->oem_id,
|
||||
lvms->oem_table_id, NULL);
|
||||
}
|
||||
|
||||
typedef
|
||||
struct AcpiBuildState {
|
||||
/* Copy of table in RAM (for patching). */
|
||||
MemoryRegion *table_mr;
|
||||
/* Is table patched? */
|
||||
uint8_t patched;
|
||||
void *rsdp;
|
||||
MemoryRegion *rsdp_mr;
|
||||
MemoryRegion *linker_mr;
|
||||
} AcpiBuildState;
|
||||
|
||||
static void build_uart_device_aml(Aml *table, int index)
|
||||
{
|
||||
Aml *dev;
|
||||
Aml *crs;
|
||||
Aml *pkg0, *pkg1, *pkg2;
|
||||
Aml *scope;
|
||||
uint32_t uart_irq;
|
||||
uint64_t base;
|
||||
|
||||
uart_irq = VIRT_UART_IRQ + index;
|
||||
base = VIRT_UART_BASE + index * VIRT_UART_SIZE;
|
||||
scope = aml_scope("_SB");
|
||||
dev = aml_device("COM%d", index);
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(index)));
|
||||
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_NON_CACHEABLE, AML_READ_WRITE,
|
||||
0, base, base + VIRT_UART_SIZE - 1,
|
||||
0, VIRT_UART_SIZE));
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||
AML_SHARED, &uart_irq, 1));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
pkg0 = aml_package(0x2);
|
||||
aml_append(pkg0, aml_int(0x05F5E100));
|
||||
aml_append(pkg0, aml_string("clock-frenquency"));
|
||||
pkg1 = aml_package(0x1);
|
||||
aml_append(pkg1, pkg0);
|
||||
pkg2 = aml_package(0x2);
|
||||
aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301"));
|
||||
aml_append(pkg2, pkg1);
|
||||
aml_append(dev, aml_name_decl("_DSD", pkg2));
|
||||
aml_append(scope, dev);
|
||||
aml_append(table, scope);
|
||||
}
|
||||
|
||||
static void
|
||||
build_la_ged_aml(Aml *dsdt, MachineState *machine)
|
||||
{
|
||||
uint32_t event;
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
|
||||
|
||||
build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
|
||||
HOTPLUG_HANDLER(lvms->acpi_ged),
|
||||
VIRT_SCI_IRQ, AML_SYSTEM_MEMORY,
|
||||
VIRT_GED_EVT_ADDR);
|
||||
event = object_property_get_uint(OBJECT(lvms->acpi_ged),
|
||||
"ged-event", &error_abort);
|
||||
if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
|
||||
build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL,
|
||||
AML_SYSTEM_MEMORY,
|
||||
VIRT_GED_MEM_ADDR);
|
||||
}
|
||||
acpi_dsdt_add_power_button(dsdt);
|
||||
}
|
||||
|
||||
static void build_pci_device_aml(Aml *scope, LoongArchVirtMachineState *lvms)
|
||||
{
|
||||
struct GPEXConfig cfg = {
|
||||
.mmio64.base = VIRT_PCI_MEM_BASE,
|
||||
.mmio64.size = VIRT_PCI_MEM_SIZE,
|
||||
.pio.base = VIRT_PCI_IO_BASE,
|
||||
.pio.size = VIRT_PCI_IO_SIZE,
|
||||
.ecam.base = VIRT_PCI_CFG_BASE,
|
||||
.ecam.size = VIRT_PCI_CFG_SIZE,
|
||||
.irq = VIRT_GSI_BASE + VIRT_DEVICE_IRQS,
|
||||
.bus = lvms->pci_bus,
|
||||
};
|
||||
|
||||
acpi_dsdt_add_gpex(scope, &cfg);
|
||||
}
|
||||
|
||||
static void build_flash_aml(Aml *scope, LoongArchVirtMachineState *lvms)
|
||||
{
|
||||
Aml *dev, *crs;
|
||||
MemoryRegion *flash_mem;
|
||||
|
||||
hwaddr flash0_base;
|
||||
hwaddr flash0_size;
|
||||
|
||||
hwaddr flash1_base;
|
||||
hwaddr flash1_size;
|
||||
|
||||
flash_mem = pflash_cfi01_get_memory(lvms->flash[0]);
|
||||
flash0_base = flash_mem->addr;
|
||||
flash0_size = memory_region_size(flash_mem);
|
||||
|
||||
flash_mem = pflash_cfi01_get_memory(lvms->flash[1]);
|
||||
flash1_base = flash_mem->addr;
|
||||
flash1_size = memory_region_size(flash_mem);
|
||||
|
||||
dev = aml_device("FLS0");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(flash0_base, flash0_size,
|
||||
AML_READ_WRITE));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
|
||||
dev = aml_device("FLS1");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(flash1_base, flash1_size,
|
||||
AML_READ_WRITE));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TPM
|
||||
static void acpi_dsdt_add_tpm(Aml *scope, LoongArchVirtMachineState *vms)
|
||||
{
|
||||
PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
|
||||
hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS;
|
||||
SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find());
|
||||
MemoryRegion *sbdev_mr;
|
||||
hwaddr tpm_base;
|
||||
|
||||
if (!sbdev) {
|
||||
return;
|
||||
}
|
||||
|
||||
tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
|
||||
assert(tpm_base != -1);
|
||||
|
||||
tpm_base += pbus_base;
|
||||
|
||||
sbdev_mr = sysbus_mmio_get_region(sbdev, 0);
|
||||
|
||||
Aml *dev = aml_device("TPM0");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
|
||||
aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||
|
||||
Aml *crs = aml_resource_template();
|
||||
aml_append(crs,
|
||||
aml_memory32_fixed(tpm_base,
|
||||
(uint32_t)memory_region_size(sbdev_mr),
|
||||
AML_READ_WRITE));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* build DSDT */
|
||||
static void
|
||||
build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
|
||||
{
|
||||
int i;
|
||||
Aml *dsdt, *scope, *pkg;
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
|
||||
AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lvms->oem_id,
|
||||
.oem_table_id = lvms->oem_table_id };
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
dsdt = init_aml_allocator();
|
||||
for (i = 0; i < VIRT_UART_COUNT; i++) {
|
||||
build_uart_device_aml(dsdt, i);
|
||||
}
|
||||
build_pci_device_aml(dsdt, lvms);
|
||||
build_la_ged_aml(dsdt, machine);
|
||||
build_flash_aml(dsdt, lvms);
|
||||
#ifdef CONFIG_TPM
|
||||
acpi_dsdt_add_tpm(dsdt, lvms);
|
||||
#endif
|
||||
/* System State Package */
|
||||
scope = aml_scope("\\");
|
||||
pkg = aml_package(4);
|
||||
aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5));
|
||||
aml_append(pkg, aml_int(0)); /* ignored */
|
||||
aml_append(pkg, aml_int(0)); /* reserved */
|
||||
aml_append(pkg, aml_int(0)); /* reserved */
|
||||
aml_append(scope, aml_name_decl("_S5", pkg));
|
||||
aml_append(dsdt, scope);
|
||||
/* Copy AML table into ACPI tables blob and patch header there */
|
||||
g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
|
||||
acpi_table_end(linker, &table);
|
||||
free_aml_allocator();
|
||||
}
|
||||
|
||||
static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
|
||||
{
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
|
||||
GArray *table_offsets;
|
||||
AcpiFadtData fadt_data;
|
||||
unsigned facs, rsdt, dsdt;
|
||||
uint8_t *u;
|
||||
GArray *tables_blob = tables->table_data;
|
||||
|
||||
init_common_fadt_data(&fadt_data);
|
||||
|
||||
table_offsets = g_array_new(false, true, sizeof(uint32_t));
|
||||
ACPI_BUILD_DPRINTF("init ACPI tables\n");
|
||||
|
||||
bios_linker_loader_alloc(tables->linker,
|
||||
ACPI_BUILD_TABLE_FILE, tables_blob,
|
||||
64, false);
|
||||
|
||||
/*
|
||||
* FACS is pointed to by FADT.
|
||||
* We place it first since it's the only table that has alignment
|
||||
* requirements.
|
||||
*/
|
||||
facs = tables_blob->len;
|
||||
build_facs(tables_blob);
|
||||
|
||||
/* DSDT is pointed to by FADT */
|
||||
dsdt = tables_blob->len;
|
||||
build_dsdt(tables_blob, tables->linker, machine);
|
||||
|
||||
/* ACPI tables pointed to by RSDT */
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
fadt_data.facs_tbl_offset = &facs;
|
||||
fadt_data.dsdt_tbl_offset = &dsdt;
|
||||
fadt_data.xdsdt_tbl_offset = &dsdt;
|
||||
build_fadt(tables_blob, tables->linker, &fadt_data,
|
||||
lvms->oem_id, lvms->oem_table_id);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_madt(tables_blob, tables->linker, lvms);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_pptt(tables_blob, tables->linker, machine,
|
||||
lvms->oem_id, lvms->oem_table_id);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_srat(tables_blob, tables->linker, machine);
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
spcr_setup(tables_blob, tables->linker, machine);
|
||||
|
||||
if (machine->numa_state->num_nodes) {
|
||||
if (machine->numa_state->have_numa_distance) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_slit(tables_blob, tables->linker, machine, lvms->oem_id,
|
||||
lvms->oem_table_id);
|
||||
}
|
||||
if (machine->numa_state->hmat_enabled) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_hmat(tables_blob, tables->linker, machine->numa_state,
|
||||
lvms->oem_id, lvms->oem_table_id);
|
||||
}
|
||||
}
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
{
|
||||
AcpiMcfgInfo mcfg = {
|
||||
.base = cpu_to_le64(VIRT_PCI_CFG_BASE),
|
||||
.size = cpu_to_le64(VIRT_PCI_CFG_SIZE),
|
||||
};
|
||||
build_mcfg(tables_blob, tables->linker, &mcfg, lvms->oem_id,
|
||||
lvms->oem_table_id);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TPM
|
||||
/* TPM info */
|
||||
if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_tpm2(tables_blob, tables->linker,
|
||||
tables->tcpalog, lvms->oem_id,
|
||||
lvms->oem_table_id);
|
||||
}
|
||||
#endif
|
||||
/* Add tables supplied by user (if any) */
|
||||
for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
|
||||
unsigned len = acpi_table_len(u);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
g_array_append_vals(tables_blob, u, len);
|
||||
}
|
||||
|
||||
/* RSDT is pointed to by RSDP */
|
||||
rsdt = tables_blob->len;
|
||||
build_rsdt(tables_blob, tables->linker, table_offsets,
|
||||
lvms->oem_id, lvms->oem_table_id);
|
||||
|
||||
/* RSDP is in FSEG memory, so allocate it separately */
|
||||
{
|
||||
AcpiRsdpData rsdp_data = {
|
||||
.revision = 0,
|
||||
.oem_id = lvms->oem_id,
|
||||
.xsdt_tbl_offset = NULL,
|
||||
.rsdt_tbl_offset = &rsdt,
|
||||
};
|
||||
build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* The align size is 128, warn if 64k is not enough therefore
|
||||
* the align size could be resized.
|
||||
*/
|
||||
if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
|
||||
warn_report("ACPI table size %u exceeds %d bytes,"
|
||||
" migration may not work",
|
||||
tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
|
||||
error_printf("Try removing CPUs, NUMA nodes, memory slots"
|
||||
" or PCI bridges.\n");
|
||||
}
|
||||
|
||||
acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
|
||||
|
||||
/* Cleanup memory that's no longer used. */
|
||||
g_array_free(table_offsets, true);
|
||||
}
|
||||
|
||||
static void acpi_ram_update(MemoryRegion *mr, GArray *data)
|
||||
{
|
||||
uint32_t size = acpi_data_len(data);
|
||||
|
||||
/*
|
||||
* Make sure RAM size is correct - in case it got changed
|
||||
* e.g. by migration
|
||||
*/
|
||||
memory_region_ram_resize(mr, size, &error_abort);
|
||||
|
||||
memcpy(memory_region_get_ram_ptr(mr), data->data, size);
|
||||
memory_region_set_dirty(mr, 0, size);
|
||||
}
|
||||
|
||||
static void acpi_build_update(void *build_opaque)
|
||||
{
|
||||
AcpiBuildState *build_state = build_opaque;
|
||||
AcpiBuildTables tables;
|
||||
|
||||
/* No state to update or already patched? Nothing to do. */
|
||||
if (!build_state || build_state->patched) {
|
||||
return;
|
||||
}
|
||||
build_state->patched = 1;
|
||||
|
||||
acpi_build_tables_init(&tables);
|
||||
|
||||
acpi_build(&tables, MACHINE(qdev_get_machine()));
|
||||
|
||||
acpi_ram_update(build_state->table_mr, tables.table_data);
|
||||
acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
|
||||
acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
|
||||
|
||||
acpi_build_tables_cleanup(&tables, true);
|
||||
}
|
||||
|
||||
static void acpi_build_reset(void *build_opaque)
|
||||
{
|
||||
AcpiBuildState *build_state = build_opaque;
|
||||
build_state->patched = 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_acpi_build = {
|
||||
.name = "acpi_build",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT8(patched, AcpiBuildState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static bool loongarch_is_acpi_enabled(LoongArchVirtMachineState *lvms)
|
||||
{
|
||||
if (lvms->acpi == ON_OFF_AUTO_OFF) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void loongarch_acpi_setup(LoongArchVirtMachineState *lvms)
|
||||
{
|
||||
AcpiBuildTables tables;
|
||||
AcpiBuildState *build_state;
|
||||
|
||||
if (!lvms->fw_cfg) {
|
||||
ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!loongarch_is_acpi_enabled(lvms)) {
|
||||
ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
build_state = g_malloc0(sizeof *build_state);
|
||||
|
||||
acpi_build_tables_init(&tables);
|
||||
acpi_build(&tables, MACHINE(lvms));
|
||||
|
||||
/* Now expose it all to Guest */
|
||||
build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
|
||||
build_state, tables.table_data,
|
||||
ACPI_BUILD_TABLE_FILE);
|
||||
assert(build_state->table_mr != NULL);
|
||||
|
||||
build_state->linker_mr =
|
||||
acpi_add_rom_blob(acpi_build_update, build_state,
|
||||
tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
|
||||
|
||||
build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
|
||||
build_state, tables.rsdp,
|
||||
ACPI_BUILD_RSDP_FILE);
|
||||
|
||||
fw_cfg_add_file(lvms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data,
|
||||
acpi_data_len(tables.tcpalog));
|
||||
|
||||
qemu_register_reset(acpi_build_reset, build_state);
|
||||
acpi_build_reset(build_state);
|
||||
vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
|
||||
|
||||
/*
|
||||
* Cleanup tables but don't free the memory: we track it
|
||||
* in build_state.
|
||||
*/
|
||||
acpi_build_tables_cleanup(&tables, false);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue