LoongArch64 patch queue:

Add dockerfile for loongarch cross compile
 Add reference files for float tests.
 Add simple tests for div, mod, clo, fclass, fcmp, pcadd
 Add bios and kernel boot support.
 Add smbios, acpi, and fdt support.
 Fix pch-pic update-irq.
 Fix some errors identified by coverity.
 -----BEGIN PGP SIGNATURE-----
 
 iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmLW6SwdHHJpY2hhcmQu
 aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV88GAf8CzH7+dQD80UUI+IZ
 ydt43SgteEftoJJINQW9QwGOk22gSptFGqkKTARFg19yBlw13P/Qj2qnwJVpEE/1
 SoWKCkAMlnxgHKhqvmPqjH/opLSJ1eDuQq3Ok0taaCjJS0uAZiUoz+3k0H3Lf0Yj
 wEusXNqkiHPXmqgTFlJDhOfrOw0ZNU6fbhoSZJ0Wj6f5X11FjxuNn7+CzO0bkfuv
 u+4vJRNTmhcflJUwYFgbjjjvcZhBJhc15WEp+6u8As0v89oci1LjgRNFUgJuI0gh
 1DZh61b0FiDpTq/KsZ/aPdl4nuMoVRJTOOvyHlaVhjWvK0EGI144eKlqvRaA9cX5
 SoHHqA==
 =3mAr
 -----END PGP SIGNATURE-----

Merge tag 'pull-la-20220719' of https://gitlab.com/rth7680/qemu into staging

LoongArch64 patch queue:

Add dockerfile for loongarch cross compile
Add reference files for float tests.
Add simple tests for div, mod, clo, fclass, fcmp, pcadd
Add bios and kernel boot support.
Add smbios, acpi, and fdt support.
Fix pch-pic update-irq.
Fix some errors identified by coverity.

# gpg: Signature made Tue 19 Jul 2022 18:26:04 BST
# gpg:                using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg:                issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full]
# Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A  05C0 64DF 38E8 AF7E 215F

* tag 'pull-la-20220719' of https://gitlab.com/rth7680/qemu: (21 commits)
  hw/loongarch: Add fdt support
  hw/loongarch: Add acpi ged support
  hw/loongarch: Add smbios support
  hw/loongarch: Add linux kernel booting support
  hw/loongarch: Add uefi bios loading support
  hw/loongarch: Add fw_cfg table support
  tests/tcg/loongarch64: Add pcadd related instructions test
  tests/tcg/loongarch64: Add fp comparison instructions test
  tests/tcg/loongarch64: Add fclass test
  tests/tcg/loongarch64: Add div and mod related instructions test
  tests/tcg/loongarch64: Add clo related instructions test
  tests/tcg/loongarch64: Add float reference files
  target/loongarch: Fix float_convd/float_convs test failing
  fpu/softfloat: Add LoongArch specializations for pickNaN*
  target/loongarch/cpu: Fix cpucfg default value
  target/loongarch/op_helper: Fix coverity cond_at_most error
  target/loongarch/tlb_helper: Fix coverity integer overflow error
  target/loongarch/cpu: Fix coverity errors about excp_names
  hw/intc/loongarch_pch_pic: Fix bugs for update_irq function
  target/loongarch: Fix loongarch_cpu_class_by_name
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2022-07-19 22:54:43 +01:00
commit 68e26e1e81
28 changed files with 4147 additions and 101 deletions

View file

@ -15,21 +15,21 @@
static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
{
unsigned long val;
uint64_t val;
int irq;
if (level) {
val = mask & s->intirr & ~s->int_mask;
if (val) {
irq = find_first_bit(&val, 64);
s->intisr |= 0x1ULL << irq;
irq = ctz64(val);
s->intisr |= MAKE_64BIT_MASK(irq, 1);
qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
}
} else {
val = mask & s->intisr;
if (val) {
irq = find_first_bit(&val, 64);
s->intisr &= ~(0x1ULL << irq);
irq = ctz64(val);
s->intisr &= ~MAKE_64BIT_MASK(irq, 1);
qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
}
}

View file

@ -14,3 +14,6 @@ config LOONGARCH_VIRT
select LOONGARCH_PCH_MSI
select LOONGARCH_EXTIOI
select LS7A_RTC
select SMBIOS
select ACPI_PCI
select ACPI_HW_REDUCED

609
hw/loongarch/acpi-build.c Normal file
View file

@ -0,0 +1,609 @@
/* 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/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 "sysemu/reset.h"
/* Supported chipsets: */
#include "hw/pci-host/ls7a.h"
#include "hw/loongarch/virt.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/utils.h"
#include "hw/acpi/pci.h"
#include "qom/qom-qobject.h"
#include "hw/acpi/generic_event_device.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, LoongArchMachineState *lams)
{
MachineState *ms = MACHINE(lams);
int i;
AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id,
.oem_table_id = lams->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 < ms->smp.cpus; i++) {
/* Processor Core Interrupt Controller Structure */
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 + 1, 4); /* ACPI Processor ID */
build_append_int_noprefix(table_data, i, 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, LS7A_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, LS7A_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)
{
uint64_t i;
LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
MachineState *ms = MACHINE(lams);
AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
.oem_table_id = lams->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 < ms->smp.cpus; ++i) {
/* 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, 0, 1);
build_append_int_noprefix(table_data, i, 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 */
}
build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE,
0, MEM_AFFINITY_ENABLED);
build_srat_memory(table_data, VIRT_HIGHMEM_BASE, machine->ram_size - VIRT_LOWMEM_SIZE,
0, MEM_AFFINITY_ENABLED);
acpi_table_end(linker, &table);
}
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_gpex_pci0_int(Aml *table)
{
Aml *sb_scope = aml_scope("_SB");
Aml *pci0_scope = aml_scope("PCI0");
Aml *prt_pkg = aml_varpackage(128);
int slot, pin;
for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
for (pin = 0; pin < PCI_NUM_PINS; pin++) {
Aml *pkg = aml_package(4);
aml_append(pkg, aml_int((slot << 16) | 0xFFFF));
aml_append(pkg, aml_int(pin));
aml_append(pkg, aml_int(0));
aml_append(pkg, aml_int(80 + (slot + pin) % 4));
aml_append(prt_pkg, pkg);
}
}
aml_append(pci0_scope, aml_name_decl("_PRT", prt_pkg));
aml_append(sb_scope, pci0_scope);
aml_append(table, sb_scope);
}
static void build_dbg_aml(Aml *table)
{
Aml *field;
Aml *method;
Aml *while_ctx;
Aml *scope = aml_scope("\\");
Aml *buf = aml_local(0);
Aml *len = aml_local(1);
Aml *idx = aml_local(2);
aml_append(scope,
aml_operation_region("DBG", AML_SYSTEM_IO, aml_int(0x0402), 0x01));
field = aml_field("DBG", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
aml_append(field, aml_named_field("DBGB", 8));
aml_append(scope, field);
method = aml_method("DBUG", 1, AML_NOTSERIALIZED);
aml_append(method, aml_to_hexstring(aml_arg(0), buf));
aml_append(method, aml_to_buffer(buf, buf));
aml_append(method, aml_subtract(aml_sizeof(buf), aml_int(1), len));
aml_append(method, aml_store(aml_int(0), idx));
while_ctx = aml_while(aml_lless(idx, len));
aml_append(while_ctx,
aml_store(aml_derefof(aml_index(buf, idx)), aml_name("DBGB")));
aml_append(while_ctx, aml_increment(idx));
aml_append(method, while_ctx);
aml_append(method, aml_store(aml_int(0x0A), aml_name("DBGB")));
aml_append(scope, method);
aml_append(table, scope);
}
static Aml *build_osc_method(void)
{
Aml *if_ctx;
Aml *if_ctx2;
Aml *else_ctx;
Aml *method;
Aml *a_cwd1 = aml_name("CDW1");
Aml *a_ctrl = aml_local(0);
method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
if_ctx = aml_if(aml_equal(
aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")));
aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl));
/*
* Always allow native PME, AER (no dependencies)
* Allow SHPC (PCI bridges can have SHPC controller)
*/
aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl));
if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
/* Unknown revision */
aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1));
aml_append(if_ctx, if_ctx2);
if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
/* Capabilities bits were masked */
aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1));
aml_append(if_ctx, if_ctx2);
/* Update DWORD3 in the buffer */
aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3")));
aml_append(method, if_ctx);
else_ctx = aml_else();
/* Unrecognized UUID */
aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1));
aml_append(method, else_ctx);
aml_append(method, aml_return(aml_arg(3)));
return method;
}
static void build_uart_device_aml(Aml *table)
{
Aml *dev;
Aml *crs;
Aml *pkg0, *pkg1, *pkg2;
uint32_t uart_irq = LS7A_UART_IRQ;
Aml *scope = aml_scope("_SB");
dev = aml_device("COMA");
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
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, 0x1FE001E0, 0x1FE001E7, 0, 0x8));
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);
}
/* build DSDT */
static void
build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
{
Aml *dsdt, *sb_scope, *scope, *dev, *crs, *pkg;
int root_bus_limit = 0x7F;
LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
.oem_table_id = lams->oem_table_id };
acpi_table_begin(&table, table_data);
dsdt = init_aml_allocator();
build_dbg_aml(dsdt);
sb_scope = aml_scope("_SB");
dev = aml_device("PCI0");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
aml_append(dev, aml_name_decl("_BBN", aml_int(0)));
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
aml_append(dev, build_osc_method());
aml_append(sb_scope, dev);
aml_append(dsdt, sb_scope);
build_gpex_pci0_int(dsdt);
build_uart_device_aml(dsdt);
if (lams->acpi_ged) {
build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
HOTPLUG_HANDLER(lams->acpi_ged),
LS7A_SCI_IRQ - PCH_PIC_IRQ_OFFSET, AML_SYSTEM_MEMORY,
VIRT_GED_EVT_ADDR);
}
scope = aml_scope("\\_SB.PCI0");
/* Build PCI0._CRS */
crs = aml_resource_template();
aml_append(crs,
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
0x0000, 0x0, root_bus_limit,
0x0000, root_bus_limit + 1));
aml_append(crs,
aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED,
AML_POS_DECODE, AML_ENTIRE_RANGE,
0x0000, 0x0000, 0xFFFF, 0x18000000, 0x10000));
aml_append(crs,
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
AML_CACHEABLE, AML_READ_WRITE,
0, LS7A_PCI_MEM_BASE,
LS7A_PCI_MEM_BASE + LS7A_PCI_MEM_SIZE - 1,
0, LS7A_PCI_MEM_BASE));
aml_append(scope, aml_name_decl("_CRS", crs));
aml_append(dsdt, scope);
/* 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)
{
LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
GArray *table_offsets;
AcpiFadtData fadt_data;
unsigned facs, rsdt, fadt, dsdt;
uint8_t *u;
size_t aml_len = 0;
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);
/*
* Count the size of the DSDT, we will need it for
* legacy sizing of ACPI tables.
*/
aml_len += tables_blob->len - dsdt;
/* ACPI tables pointed to by RSDT */
fadt = tables_blob->len;
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,
lams->oem_id, lams->oem_table_id);
aml_len += tables_blob->len - fadt;
acpi_add_table(table_offsets, tables_blob);
build_madt(tables_blob, tables->linker, lams);
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, machine);
acpi_add_table(table_offsets, tables_blob);
{
AcpiMcfgInfo mcfg = {
.base = cpu_to_le64(LS_PCIECFG_BASE),
.size = cpu_to_le64(LS_PCIECFG_SIZE),
};
build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id,
lams->oem_table_id);
}
/* 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,
lams->oem_id, lams->oem_table_id);
/* RSDP is in FSEG memory, so allocate it separately */
{
AcpiRsdpData rsdp_data = {
.revision = 0,
.oem_id = lams->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.");
}
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 = (VMStateField[]) {
VMSTATE_UINT8(patched, AcpiBuildState),
VMSTATE_END_OF_LIST()
},
};
void loongarch_acpi_setup(LoongArchMachineState *lams)
{
AcpiBuildTables tables;
AcpiBuildState *build_state;
if (!lams->fw_cfg) {
ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
return;
}
if (!loongarch_is_acpi_enabled(lams)) {
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(lams));
/* 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);
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);
}

33
hw/loongarch/fw_cfg.c Normal file
View file

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* QEMU fw_cfg helpers (LoongArch specific)
*
* Copyright (C) 2021 Loongson Technology Corporation Limited
*/
#include "qemu/osdep.h"
#include "hw/loongarch/fw_cfg.h"
#include "hw/loongarch/virt.h"
#include "hw/nvram/fw_cfg.h"
#include "sysemu/sysemu.h"
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
Error **errp)
{
fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
}
FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms)
{
FWCfgState *fw_cfg;
int max_cpus = ms->smp.max_cpus;
int smp_cpus = ms->smp.cpus;
fw_cfg = fw_cfg_init_mem_wide(VIRT_FWCFG_BASE + 8, VIRT_FWCFG_BASE, 8, 0, NULL);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
return fw_cfg;
}

15
hw/loongarch/fw_cfg.h Normal file
View file

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* QEMU fw_cfg helpers (LoongArch specific)
*
* Copyright (C) 2021 Loongson Technology Corporation Limited
*/
#ifndef HW_LOONGARCH_FW_CFG_H
#define HW_LOONGARCH_FW_CFG_H
#include "hw/boards.h"
#include "hw/nvram/fw_cfg.h"
FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms);
#endif

View file

@ -28,13 +28,201 @@
#include "hw/pci-host/ls7a.h"
#include "hw/pci-host/gpex.h"
#include "hw/misc/unimp.h"
#include "hw/loongarch/fw_cfg.h"
#include "target/loongarch/cpu.h"
#include "hw/firmware/smbios.h"
#include "hw/acpi/aml-build.h"
#include "qapi/qapi-visit-common.h"
#include "hw/acpi/generic_event_device.h"
#include "hw/mem/nvdimm.h"
#include "sysemu/device_tree.h"
#include <libfdt.h>
static void create_fdt(LoongArchMachineState *lams)
{
MachineState *ms = MACHINE(lams);
ms->fdt = create_device_tree(&lams->fdt_size);
if (!ms->fdt) {
error_report("create_device_tree() failed");
exit(1);
}
/* Header */
qemu_fdt_setprop_string(ms->fdt, "/", "compatible",
"linux,dummy-loongson3");
qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
}
static void fdt_add_cpu_nodes(const LoongArchMachineState *lams)
{
int num;
const MachineState *ms = MACHINE(lams);
int smp_cpus = ms->smp.cpus;
qemu_fdt_add_subnode(ms->fdt, "/cpus");
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
/* cpu nodes */
for (num = smp_cpus - 1; num >= 0; num--) {
char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
LoongArchCPU *cpu = LOONGARCH_CPU(qemu_get_cpu(num));
qemu_fdt_add_subnode(ms->fdt, nodename);
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
cpu->dtb_compatible);
qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
qemu_fdt_alloc_phandle(ms->fdt));
g_free(nodename);
}
/*cpu map */
qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map");
for (num = smp_cpus - 1; num >= 0; num--) {
char *cpu_path = g_strdup_printf("/cpus/cpu@%d", num);
char *map_path;
if (ms->smp.threads > 1) {
map_path = g_strdup_printf(
"/cpus/cpu-map/socket%d/core%d/thread%d",
num / (ms->smp.cores * ms->smp.threads),
(num / ms->smp.threads) % ms->smp.cores,
num % ms->smp.threads);
} else {
map_path = g_strdup_printf(
"/cpus/cpu-map/socket%d/core%d",
num / ms->smp.cores,
num % ms->smp.cores);
}
qemu_fdt_add_path(ms->fdt, map_path);
qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", cpu_path);
g_free(map_path);
g_free(cpu_path);
}
}
static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams)
{
char *nodename;
hwaddr base = VIRT_FWCFG_BASE;
const MachineState *ms = MACHINE(lams);
nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base);
qemu_fdt_add_subnode(ms->fdt, nodename);
qemu_fdt_setprop_string(ms->fdt, nodename,
"compatible", "qemu,fw-cfg-mmio");
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
2, base, 2, 0x8);
qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
g_free(nodename);
}
static void fdt_add_pcie_node(const LoongArchMachineState *lams)
{
char *nodename;
hwaddr base_mmio = LS7A_PCI_MEM_BASE;
hwaddr size_mmio = LS7A_PCI_MEM_SIZE;
hwaddr base_pio = LS7A_PCI_IO_BASE;
hwaddr size_pio = LS7A_PCI_IO_SIZE;
hwaddr base_pcie = LS_PCIECFG_BASE;
hwaddr size_pcie = LS_PCIECFG_SIZE;
hwaddr base = base_pcie;
const MachineState *ms = MACHINE(lams);
nodename = g_strdup_printf("/pcie@%" PRIx64, base);
qemu_fdt_add_subnode(ms->fdt, nodename);
qemu_fdt_setprop_string(ms->fdt, nodename,
"compatible", "pci-host-ecam-generic");
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci");
qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3);
qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2);
qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0);
qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0,
PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1));
qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
2, base_pcie, 2, size_pcie);
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
1, FDT_PCI_RANGE_IOPORT, 2, LS7A_PCI_IO_OFFSET,
2, base_pio, 2, size_pio,
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
2, base_mmio, 2, size_mmio);
g_free(nodename);
qemu_fdt_dumpdtb(ms->fdt, lams->fdt_size);
}
#define PM_BASE 0x10080000
#define PM_SIZE 0x100
#define PM_CTRL 0x10
static void virt_build_smbios(LoongArchMachineState *lams)
{
MachineState *ms = MACHINE(lams);
MachineClass *mc = MACHINE_GET_CLASS(lams);
uint8_t *smbios_tables, *smbios_anchor;
size_t smbios_tables_len, smbios_anchor_len;
const char *product = "QEMU Virtual Machine";
if (!lams->fw_cfg) {
return;
}
smbios_set_defaults("QEMU", product, mc->name, false,
true, SMBIOS_ENTRY_POINT_TYPE_64);
smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len,
&smbios_anchor, &smbios_anchor_len, &error_fatal);
if (smbios_anchor) {
fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-tables",
smbios_tables, smbios_tables_len);
fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-anchor",
smbios_anchor, smbios_anchor_len);
}
}
static void virt_machine_done(Notifier *notifier, void *data)
{
LoongArchMachineState *lams = container_of(notifier,
LoongArchMachineState, machine_done);
virt_build_smbios(lams);
loongarch_acpi_setup(lams);
}
struct memmap_entry {
uint64_t address;
uint64_t length;
uint32_t type;
uint32_t reserved;
};
static struct memmap_entry *memmap_table;
static unsigned memmap_entries;
static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
{
/* Ensure there are no duplicate entries. */
for (unsigned i = 0; i < memmap_entries; i++) {
assert(memmap_table[i].address != address);
}
memmap_table = g_renew(struct memmap_entry, memmap_table,
memmap_entries + 1);
memmap_table[memmap_entries].address = cpu_to_le64(address);
memmap_table[memmap_entries].length = cpu_to_le64(length);
memmap_table[memmap_entries].type = cpu_to_le32(type);
memmap_table[memmap_entries].reserved = 0;
memmap_entries++;
}
/*
* This is a placeholder for missing ACPI,
* and will eventually be replaced.
@ -76,6 +264,8 @@ static const MemoryRegionOps loongarch_virt_pm_ops = {
static struct _loaderparams {
uint64_t ram_size;
const char *kernel_filename;
const char *kernel_cmdline;
const char *initrd_filename;
} loaderparams;
static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
@ -103,7 +293,32 @@ static int64_t load_kernel_info(void)
return kernel_entry;
}
static void loongarch_devices_init(DeviceState *pch_pic)
static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState *lams)
{
DeviceState *dev;
MachineState *ms = MACHINE(lams);
uint32_t event = ACPI_GED_PWR_DOWN_EVT;
if (ms->ram_slots) {
event |= ACPI_GED_MEM_HOTPLUG_EVT;
}
dev = qdev_new(TYPE_ACPI_GED);
qdev_prop_set_uint32(dev, "ged-event", event);
/* ged event */
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, VIRT_GED_EVT_ADDR);
/* memory hotplug */
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, VIRT_GED_MEM_ADDR);
/* ged regs used for reset and power down */
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_GED_REG_ADDR);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
qdev_get_gpio_in(pch_pic, LS7A_SCI_IRQ - PCH_PIC_IRQ_OFFSET));
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
return dev;
}
static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState *lams)
{
DeviceState *gpex_dev;
SysBusDevice *d;
@ -179,6 +394,8 @@ static void loongarch_devices_init(DeviceState *pch_pic)
memory_region_init_io(pm_mem, NULL, &loongarch_virt_pm_ops,
NULL, "loongarch_virt_pm", PM_SIZE);
memory_region_add_subregion(get_system_memory(), PM_BASE, pm_mem);
/* acpi ged */
lams->acpi_ged = create_acpi_ged(pch_pic, lams);
}
static void loongarch_irq_init(LoongArchMachineState *lams)
@ -280,7 +497,38 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
}
loongarch_devices_init(pch_pic);
loongarch_devices_init(pch_pic, lams);
}
static void loongarch_firmware_init(LoongArchMachineState *lams)
{
char *filename = MACHINE(lams)->firmware;
char *bios_name = NULL;
int bios_size;
lams->bios_loaded = false;
if (filename) {
bios_name = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename);
if (!bios_name) {
error_report("Could not find ROM image '%s'", filename);
exit(1);
}
bios_size = load_image_targphys(bios_name, VIRT_BIOS_BASE, VIRT_BIOS_SIZE);
if (bios_size < 0) {
error_report("Could not load ROM image '%s'", bios_name);
exit(1);
}
g_free(bios_name);
memory_region_init_ram(&lams->bios, NULL, "loongarch.bios",
VIRT_BIOS_SIZE, &error_fatal);
memory_region_set_readonly(&lams->bios, true);
memory_region_add_subregion(get_system_memory(), VIRT_BIOS_BASE, &lams->bios);
lams->bios_loaded = true;
}
}
static void reset_load_elf(void *opaque)
@ -294,18 +542,97 @@ static void reset_load_elf(void *opaque)
}
}
/* Load an image file into an fw_cfg entry identified by key. */
static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
uint16_t data_key, const char *image_name,
bool try_decompress)
{
size_t size = -1;
uint8_t *data;
if (image_name == NULL) {
return;
}
if (try_decompress) {
size = load_image_gzipped_buffer(image_name,
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
}
if (size == (size_t)-1) {
gchar *contents;
gsize length;
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
error_report("failed to load \"%s\"", image_name);
exit(1);
}
size = length;
data = (uint8_t *)contents;
}
fw_cfg_add_i32(fw_cfg, size_key, size);
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
}
static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg)
{
/*
* Expose the kernel, the command line, and the initrd in fw_cfg.
* We don't process them here at all, it's all left to the
* firmware.
*/
load_image_to_fw_cfg(fw_cfg,
FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
loaderparams.kernel_filename,
false);
if (loaderparams.initrd_filename) {
load_image_to_fw_cfg(fw_cfg,
FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
loaderparams.initrd_filename, false);
}
if (loaderparams.kernel_cmdline) {
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
strlen(loaderparams.kernel_cmdline) + 1);
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
loaderparams.kernel_cmdline);
}
}
static void loongarch_firmware_boot(LoongArchMachineState *lams)
{
fw_cfg_add_kernel_info(lams->fw_cfg);
}
static void loongarch_direct_kernel_boot(LoongArchMachineState *lams)
{
MachineState *machine = MACHINE(lams);
int64_t kernel_addr = 0;
LoongArchCPU *lacpu;
int i;
kernel_addr = load_kernel_info();
if (!machine->firmware) {
for (i = 0; i < machine->smp.cpus; i++) {
lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
lacpu->env.load_elf = true;
lacpu->env.elf_address = kernel_addr;
}
}
}
static void loongarch_init(MachineState *machine)
{
LoongArchCPU *lacpu;
const char *cpu_model = machine->cpu_type;
const char *kernel_filename = machine->kernel_filename;
ram_addr_t offset = 0;
ram_addr_t ram_size = machine->ram_size;
uint64_t highram_size = 0;
MemoryRegion *address_space_mem = get_system_memory();
LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
LoongArchCPU *lacpu;
int i;
int64_t kernel_addr = 0;
if (!cpu_model) {
cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
@ -320,41 +647,102 @@ static void loongarch_init(MachineState *machine)
error_report("ram_size must be greater than 1G.");
exit(1);
}
create_fdt(lams);
/* Init CPUs */
for (i = 0; i < machine->smp.cpus; i++) {
cpu_create(machine->cpu_type);
}
fdt_add_cpu_nodes(lams);
/* Add memory region */
memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
machine->ram, 0, 256 * MiB);
memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
offset += 256 * MiB;
memmap_add_entry(0, 256 * MiB, 1);
highram_size = ram_size - 256 * MiB;
memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
machine->ram, offset, highram_size);
memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
memmap_add_entry(0x90000000, highram_size, 1);
/* Add isa io region */
memory_region_init_alias(&lams->isa_io, NULL, "isa-io",
get_system_io(), 0, LOONGARCH_ISA_IO_SIZE);
memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE,
&lams->isa_io);
if (kernel_filename) {
loaderparams.ram_size = ram_size;
loaderparams.kernel_filename = kernel_filename;
kernel_addr = load_kernel_info();
if (!machine->firmware) {
for (i = 0; i < machine->smp.cpus; i++) {
lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
lacpu->env.load_elf = true;
lacpu->env.elf_address = kernel_addr;
qemu_register_reset(reset_load_elf, lacpu);
}
/* load the BIOS image. */
loongarch_firmware_init(lams);
/* fw_cfg init */
lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
rom_set_fw(lams->fw_cfg);
if (lams->fw_cfg != NULL) {
fw_cfg_add_file(lams->fw_cfg, "etc/memmap",
memmap_table,
sizeof(struct memmap_entry) * (memmap_entries));
}
fdt_add_fw_cfg_node(lams);
loaderparams.ram_size = ram_size;
loaderparams.kernel_filename = machine->kernel_filename;
loaderparams.kernel_cmdline = machine->kernel_cmdline;
loaderparams.initrd_filename = machine->initrd_filename;
/* load the kernel. */
if (loaderparams.kernel_filename) {
if (lams->bios_loaded) {
loongarch_firmware_boot(lams);
} else {
loongarch_direct_kernel_boot(lams);
}
}
/* register reset function */
for (i = 0; i < machine->smp.cpus; i++) {
lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
qemu_register_reset(reset_load_elf, lacpu);
}
/* Initialize the IO interrupt subsystem */
loongarch_irq_init(lams);
lams->machine_done.notify = virt_machine_done;
qemu_add_machine_init_done_notifier(&lams->machine_done);
fdt_add_pcie_node(lams);
/* load fdt */
MemoryRegion *fdt_rom = g_new(MemoryRegion, 1);
memory_region_init_rom(fdt_rom, NULL, "fdt", LA_FDT_SIZE, &error_fatal);
memory_region_add_subregion(get_system_memory(), LA_FDT_BASE, fdt_rom);
rom_add_blob_fixed("fdt", machine->fdt, lams->fdt_size, LA_FDT_BASE);
}
bool loongarch_is_acpi_enabled(LoongArchMachineState *lams)
{
if (lams->acpi == ON_OFF_AUTO_OFF) {
return false;
}
return true;
}
static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
OnOffAuto acpi = lams->acpi;
visit_type_OnOffAuto(v, name, &acpi, errp);
}
static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
visit_type_OnOffAuto(v, name, &lams->acpi, errp);
}
static void loongarch_machine_initfn(Object *obj)
{
LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
lams->acpi = ON_OFF_AUTO_AUTO;
lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
lams->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
}
static void loongarch_class_init(ObjectClass *oc, void *data)
@ -372,6 +760,12 @@ static void loongarch_class_init(ObjectClass *oc, void *data)
mc->block_default_type = IF_VIRTIO;
mc->default_boot_order = "c";
mc->no_cdrom = 1;
object_class_property_add(oc, "acpi", "OnOffAuto",
loongarch_get_acpi, loongarch_set_acpi,
NULL, NULL);
object_class_property_set_description(oc, "acpi",
"Enable ACPI");
}
static const TypeInfo loongarch_machine_types[] = {
@ -380,6 +774,7 @@ static const TypeInfo loongarch_machine_types[] = {
.parent = TYPE_MACHINE,
.instance_size = sizeof(LoongArchMachineState),
.class_init = loongarch_class_init,
.instance_init = loongarch_machine_initfn,
}
};

View file

@ -1,4 +1,8 @@
loongarch_ss = ss.source_set()
loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('loongson3.c'))
loongarch_ss.add(files(
'fw_cfg.c',
))
loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: [files('loongson3.c'), fdt])
loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c'))
hw_arch += {'loongarch': loongarch_ss}