diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 0a01746cea9f214c107721c24a0501751b35171c..e39e3275512945302c31249ebd530dfc1b5c80f0 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -579,6 +579,8 @@ build-tci: - make check-tcg # Check our reduced build configurations +# requires libfdt: aarch64, arm, i386, loongarch64, x86_64 +# does not build without boards: i386, loongarch64, x86_64 build-without-defaults: extends: .native_build_job_template needs: diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak index 928bc117ef781a5f64512b972b459751d08717ce..ffe705836fde47b47f82db9baa8d1b8073eec4df 100644 --- a/configs/devices/loongarch64-softmmu/default.mak +++ b/configs/devices/loongarch64-softmmu/default.mak @@ -1,3 +1,7 @@ # Default configuration for loongarch64-softmmu -CONFIG_LOONGARCH_VIRT=y +# Uncomment the following lines to disable these optional devices: +# CONFIG_PCI_DEVICES=n + +# Boards are selected by default, uncomment to keep out of the build. +# CONFIG_LOONGARCH_VIRT=n diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak index f23780fdd89945b82078b1680273bfa93d9f2ff1..0034c336200fb0629775e713982da70309464a54 100644 --- a/configs/targets/loongarch64-softmmu.mak +++ b/configs/targets/loongarch64-softmmu.mak @@ -1,5 +1,6 @@ TARGET_ARCH=loongarch64 TARGET_BASE_ARCH=loongarch +TARGET_KVM_HAVE_GUEST_DEBUG=y TARGET_SUPPORTS_MTTCG=y TARGET_XML_FILES= gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml TARGET_NEED_FDT=y diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index 9b687b4cb47552b0ef85aa2bfbfb5492015f3286..16c854c0d595f54aa4a9bcf194f19cbbbccd9331 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -1,5 +1,7 @@ config LOONGARCH_VIRT bool + default y + depends on LOONGARCH64 select PCI select PCI_EXPRESS_GENERIC_BRIDGE imply PCI_DEVICES diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c index cb668703bddd03c6beef87b401112df14f9cf36b..53dcefbb55a7a932b5cc0a5b26c9a32886fb07a6 100644 --- a/hw/loongarch/boot.c +++ b/hw/loongarch/boot.c @@ -216,7 +216,7 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) return kernel_entry; } -static void reset_load_elf(void *opaque) +void reset_load_elf(void *opaque) { LoongArchCPU *cpu = opaque; CPULoongArchState *env = &cpu->env; @@ -278,7 +278,7 @@ static void init_boot_rom(struct loongarch_boot_info *info, void *p) static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) { void *p, *bp; - int64_t kernel_addr = 0; + int64_t kernel_addr = VIRT_FLASH0_BASE; LoongArchCPU *lacpu; CPUState *cs; @@ -286,8 +286,7 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) kernel_addr = load_kernel_info(info); } else { if(!qtest_enabled()) { - error_report("Need kernel filename\n"); - exit(1); + warn_report("No kernel provided, booting from flash drive."); } } diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index c7492e565c238352fecaeb776ed16c8000b4ced2..556af5c6be7b0b5be766a48b34a0f74632549147 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -875,6 +875,10 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) lacpu = LOONGARCH_CPU(cpu_state); env = &(lacpu->env); env->address_space_iocsr = &lvms->as_iocsr; + + /* connect ipi irq to cpu irq */ + qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); + env->ipistate = ipi; } lvms->ipi = ipi; @@ -1511,7 +1515,7 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, env = &(cpu->env); env->address_space_iocsr = &lvms->as_iocsr; - + qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(cs->cpu_index))); env->ipistate = lvms->ipi; if (!(kvm_enabled() && kvm_irqchip_in_kernel())) { /* connect ipi irq to cpu irq, logic cpu index used here */ diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h index dce7c502fa75814eadecc6ba543ed98dd393aeb2..eb021e23381b9fc253e73db7143ca4344256ba1d 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -84,4 +84,5 @@ struct LoongArchVirtMachineState { #define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt") OBJECT_DECLARE_SIMPLE_TYPE(LoongArchVirtMachineState, LOONGARCH_VIRT_MACHINE) void loongarch_acpi_setup(LoongArchVirtMachineState *lvms); +void reset_load_elf(void *opaque); #endif diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 78f4a95cb9aced8e5553ba7d4e9c0e308a9b9abc..bfc7df3044c964bffaa1fa4f4ae0f6b37a185231 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -91,7 +91,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env, { CPUState *cs = env_cpu(env); - qemu_log_mask(CPU_LOG_INT, "%s: expection: %d (%s)\n", + qemu_log_mask(CPU_LOG_INT, "%s: exception: %d (%s)\n", __func__, exception, loongarch_exception_name(exception)); @@ -463,6 +463,18 @@ static void loongarch_la464_initfn(Object *obj) env->cpucfg[20] = data; env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); + + env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM, 8); + env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, TIMER_BITS, 0x2f); + env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, VSMAX, 7); + + env->CSR_PRCFG2 = 0x3ffff000; + + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); + loongarch_cpu_post_init(obj); } @@ -527,7 +539,9 @@ static void loongarch_cpu_reset_hold(Object *obj) lacc->parent_phases.hold(obj); } +#ifdef CONFIG_TCG env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3; +#endif env->fcsr0 = 0x0; int n; @@ -572,11 +586,6 @@ static void loongarch_cpu_reset_hold(Object *obj) env->CSR_TLBRENTRY = 0; env->CSR_MERRENTRY = 0; - env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); - env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); - env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); - env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); - for (n = 0; n < 4; n++) { env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0); env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0); @@ -586,7 +595,9 @@ static void loongarch_cpu_reset_hold(Object *obj) #ifndef CONFIG_USER_ONLY env->pc = 0x1c000000; +#ifdef CONFIG_TCG memset(env->tlb, 0, sizeof(env->tlb)); +#endif if (kvm_enabled()) { kvm_arch_reset_vcpu(cs); } @@ -776,8 +787,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) int i; qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); - qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0, - get_float_exception_flags(&env->fp_status)); + qemu_fprintf(f, " FCSR0 0x%08x\n", env->fcsr0); /* gpr */ for (i = 0; i < 32; i++) { @@ -800,7 +810,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY); qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 "," " PRCFG3=%016" PRIx64 "\n", - env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); + env->CSR_PRCFG1, env->CSR_PRCFG2, env->CSR_PRCFG3); qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY); qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV); qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA); diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 4a3ae6fad541ceb38998da9745fe730642e87712..9afa831e4529a9327c716052a5b3c37e0293764e 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -275,6 +275,7 @@ union fpr_t { VReg vreg; }; +#ifdef CONFIG_TCG struct LoongArchTLB { uint64_t tlb_misc; /* Fields corresponding to CSR_TLBELO0/1 */ @@ -282,6 +283,7 @@ struct LoongArchTLB { uint64_t tlb_entry1; }; typedef struct LoongArchTLB LoongArchTLB; +#endif enum loongarch_features { LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */ @@ -304,18 +306,13 @@ typedef struct CPUArchState { uint64_t pc; fpr_t fpr[32]; - float_status fp_status; bool cf[8]; uint32_t fcsr0; lbt_t lbt; - uint32_t fcsr0_mask; uint32_t cpucfg[21]; - uint64_t lladdr; /* LL virtual address compared against SC */ - uint64_t llval; - /* LoongArch CSRs */ uint64_t CSR_CRMD; uint64_t CSR_PRMD; @@ -375,8 +372,16 @@ typedef struct CPUArchState { uint64_t guest_addr; } stealtime; +#ifdef CONFIG_TCG + float_status fp_status; + uint32_t fcsr0_mask; + uint64_t lladdr; /* LL virtual address compared against SC */ + uint64_t llval; +#endif #ifndef CONFIG_USER_ONLY +#ifdef CONFIG_TCG LoongArchTLB tlb[LOONGARCH_TLB_MAX]; +#endif AddressSpace *address_space_iocsr; bool load_elf; diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index f68d63f466e38a28c02a14c0da156c9caea61d4d..39037eecb4bd566b838e808ad2aa3875f1eebd02 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -11,6 +11,7 @@ #include "internals.h" #include "cpu-csr.h" +#ifdef CONFIG_TCG static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, int *prot, target_ulong address, int access_type, int index, int mmu_idx) @@ -154,6 +155,14 @@ static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, return TLBRET_NOMATCH; } +#else +static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type, int mmu_idx) +{ + return TLBRET_NOMATCH; +} +#endif static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va, target_ulong dmw) diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c index 5fc2f19e965e101a269c923a101c9be05d2bd2ac..cc72680c38b282bdcc2889537fa902483510089b 100644 --- a/target/loongarch/gdbstub.c +++ b/target/loongarch/gdbstub.c @@ -33,28 +33,29 @@ void write_fcc(CPULoongArchState *env, uint64_t val) int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { - LoongArchCPU *cpu = LOONGARCH_CPU(cs); - CPULoongArchState *env = &cpu->env; - uint64_t val; - - if (0 <= n && n < 32) { - val = env->gpr[n]; - } else if (n == 32) { - /* orig_a0 */ - val = 0; - } else if (n == 33) { - val = env->pc; - } else if (n == 34) { - val = env->CSR_BADV; - } + CPULoongArchState *env = cpu_env(cs); if (0 <= n && n <= 34) { + uint64_t val; + + if (n < 32) { + val = env->gpr[n]; + } else if (n == 32) { + /* orig_a0 */ + val = 0; + } else if (n == 33) { + val = env->pc; + } else /* if (n == 34) */ { + val = env->CSR_BADV; + } + if (is_la64(env)) { return gdb_get_reg64(mem_buf, val); } else { return gdb_get_reg32(mem_buf, val); } } + return 0; } @@ -67,10 +68,10 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) int length = 0; if (is_la64(env)) { - tmp = ldq_p(mem_buf); + tmp = ldq_le_p(mem_buf); read_length = 8; } else { - tmp = ldl_p(mem_buf); + tmp = ldl_le_p(mem_buf); read_length = 4; } @@ -103,13 +104,13 @@ static int loongarch_gdb_set_fpu(CPULoongArchState *env, int length = 0; if (0 <= n && n < 32) { - env->fpr[n].vreg.D(0) = ldq_p(mem_buf); + env->fpr[n].vreg.D(0) = ldq_le_p(mem_buf); length = 8; } else if (32 <= n && n < 40) { env->cf[n - 32] = ldub_p(mem_buf); length = 1; } else if (n == 40) { - env->fcsr0 = ldl_p(mem_buf); + env->fcsr0 = ldl_le_p(mem_buf); length = 4; } return length; diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 0ab1ee803d4c283769ebe2e6777d4968361763d5..213cf6a8ce61b2ee593cdc7d5cf3a2ed5da92deb 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -716,6 +716,11 @@ int kvm_arch_get_registers(CPUState *cs) return ret; } + ret = kvm_loongarch_get_cpucfg(cs); + if (ret) { + return ret; + } + ret = kvm_loongarch_get_csr(cs); if (ret) { return ret; @@ -737,11 +742,6 @@ int kvm_arch_get_registers(CPUState *cs) } ret = kvm_loongarch_get_mpstate(cs); - if (ret) { - return ret; - } - - ret = kvm_loongarch_get_cpucfg(cs); return ret; } @@ -754,6 +754,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } + ret = kvm_loongarch_put_cpucfg(cs); + if (ret) { + return ret; + } + ret = kvm_loongarch_put_csr(cs, level); if (ret) { return ret; @@ -781,11 +786,6 @@ int kvm_arch_put_registers(CPUState *cs, int level) } ret = kvm_loongarch_put_mpstate(cs); - if (ret) { - return ret; - } - - ret = kvm_loongarch_put_cpucfg(cs); return ret; } diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c index dc768453583f11440a480b126369f3792dd6fd81..818aa71a8b591b49eefb4509d0970202545bfd7d 100644 --- a/target/loongarch/machine.c +++ b/target/loongarch/machine.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "migration/cpu.h" +#include "sysemu/tcg.h" #include "vec.h" static const VMStateDescription vmstate_fpu_reg = { @@ -133,9 +134,15 @@ static const VMStateDescription vmstate_lbt = { }; +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) +static bool tlb_needed(void *opaque) +{ + return tcg_enabled(); +} + /* TLB state */ -const VMStateDescription vmstate_tlb = { - .name = "cpu/tlb", +static const VMStateDescription vmstate_tlb_entry = { + .name = "cpu/tlb_entry", .version_id = 0, .minimum_version_id = 0, .fields = (VMStateField[]) { @@ -146,6 +153,19 @@ const VMStateDescription vmstate_tlb = { } }; +static const VMStateDescription vmstate_tlb = { + .name = "cpu/tlb", + .version_id = 0, + .minimum_version_id = 0, + .needed = tlb_needed, + .fields = (const VMStateField[]) { + VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, + 0, vmstate_tlb_entry, LoongArchTLB), + VMSTATE_END_OF_LIST() + } +}; +#endif + /* LoongArch CPU state */ const VMStateDescription vmstate_loongarch_cpu = { .name = "cpu", @@ -211,9 +231,6 @@ const VMStateDescription vmstate_loongarch_cpu = { VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU), VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU), VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU), - /* TLB */ - VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, - 0, vmstate_tlb, LoongArchTLB), VMSTATE_UINT64(kvm_state_counter, LoongArchCPU), /* PV steal time */ @@ -225,6 +242,9 @@ const VMStateDescription vmstate_loongarch_cpu = { &vmstate_fpu, &vmstate_lsx, &vmstate_lasx, +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) + &vmstate_tlb, +#endif &vmstate_lbt, NULL } diff --git a/target/loongarch/tcg/insn_trans/trans_shift.c.inc b/target/loongarch/tcg/insn_trans/trans_shift.c.inc index 2f4bd6ff28819eb4c665a3775e6867f37294e6a7..377307785aab4837bc181f1691632e7970a9889d 100644 --- a/target/loongarch/tcg/insn_trans/trans_shift.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_shift.c.inc @@ -67,19 +67,9 @@ static void gen_rotr_d(TCGv dest, TCGv src1, TCGv src2) tcg_gen_rotr_tl(dest, src1, t0); } -static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) +static void gen_sari_w(TCGv dest, TCGv src1, target_long imm) { - TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); - TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO); - - if (!avail_64(ctx)) { - return false; - } - - tcg_gen_sextract_tl(dest, src1, a->imm, 32 - a->imm); - gen_set_gpr(a->rd, dest, EXT_NONE); - - return true; + tcg_gen_sextract_tl(dest, src1, imm, 32 - imm); } TRANS(sll_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) @@ -94,6 +84,7 @@ TRANS(slli_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) TRANS(slli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) TRANS(srli_w, ALL, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) TRANS(srli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) +TRANS(srai_w, ALL, gen_rri_c, EXT_NONE, EXT_NONE, gen_sari_w) TRANS(srai_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) TRANS(rotri_w, 64, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) TRANS(rotri_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) diff --git a/tests/qtest/libqos/loongarch-virt-machine.c b/tests/qtest/libqos/loongarch-virt-machine.c new file mode 100644 index 0000000000000000000000000000000000000000..c12089c015df6d7f18144e3fe99b588354e45329 --- /dev/null +++ b/tests/qtest/libqos/loongarch-virt-machine.c @@ -0,0 +1,114 @@ +/* + * libqos driver framework + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "../libqtest.h" +#include "qemu/module.h" +#include "libqos-malloc.h" +#include "qgraph.h" +#include "virtio-mmio.h" +#include "generic-pcihost.h" +#include "hw/pci/pci_regs.h" + +#define LOONGARCH_PAGE_SIZE 0x1000 +#define LOONGARCH_VIRT_RAM_ADDR 0x100000 +#define LOONGARCH_VIRT_RAM_SIZE 0xFF00000 + +#define LOONGARCH_VIRT_PIO_BASE 0x18000000 +#define LOONGARCH_VIRT_PCIE_PIO_OFFSET 0x4000 +#define LOONGARCH_VIRT_PCIE_PIO_LIMIT 0x10000 +#define LOONGARCH_VIRT_PCIE_ECAM_BASE 0x20000000 +#define LOONGARCH_VIRT_PCIE_MMIO32_BASE 0x40000000 +#define LOONGARCH_VIRT_PCIE_MMIO32_LIMIT 0x80000000 + +typedef struct QVirtMachine QVirtMachine; + +struct QVirtMachine { + QOSGraphObject obj; + QGuestAllocator alloc; + QVirtioMMIODevice virtio_mmio; + QGenericPCIHost bridge; +}; + +static void virt_destructor(QOSGraphObject *obj) +{ + QVirtMachine *machine = (QVirtMachine *) obj; + alloc_destroy(&machine->alloc); +} + +static void *virt_get_driver(void *object, const char *interface) +{ + QVirtMachine *machine = object; + if (!g_strcmp0(interface, "memory")) { + return &machine->alloc; + } + + fprintf(stderr, "%s not present in loongarch/virtio\n", interface); + g_assert_not_reached(); +} + +static QOSGraphObject *virt_get_device(void *obj, const char *device) +{ + QVirtMachine *machine = obj; + if (!g_strcmp0(device, "generic-pcihost")) { + return &machine->bridge.obj; + } else if (!g_strcmp0(device, "virtio-mmio")) { + return &machine->virtio_mmio.obj; + } + + fprintf(stderr, "%s not present in loongarch/virt\n", device); + g_assert_not_reached(); +} + +static void loongarch_config_qpci_bus(QGenericPCIBus *qpci) +{ + qpci->gpex_pio_base = LOONGARCH_VIRT_PIO_BASE; + qpci->bus.pio_alloc_ptr = LOONGARCH_VIRT_PCIE_PIO_OFFSET; + qpci->bus.pio_limit = LOONGARCH_VIRT_PCIE_PIO_LIMIT; + qpci->bus.mmio_alloc_ptr = LOONGARCH_VIRT_PCIE_MMIO32_BASE; + qpci->bus.mmio_limit = LOONGARCH_VIRT_PCIE_MMIO32_LIMIT; + qpci->ecam_alloc_ptr = LOONGARCH_VIRT_PCIE_ECAM_BASE; +} + +static void *qos_create_machine_loongarch_virt(QTestState *qts) +{ + QVirtMachine *machine = g_new0(QVirtMachine, 1); + + alloc_init(&machine->alloc, 0, + LOONGARCH_VIRT_RAM_ADDR, + LOONGARCH_VIRT_RAM_ADDR + LOONGARCH_VIRT_RAM_SIZE, + LOONGARCH_PAGE_SIZE); + + qos_create_generic_pcihost(&machine->bridge, qts, &machine->alloc); + loongarch_config_qpci_bus(&machine->bridge.pci); + + machine->obj.get_device = virt_get_device; + machine->obj.get_driver = virt_get_driver; + machine->obj.destructor = virt_destructor; + return machine; +} + +static void virt_machine_register_nodes(void) +{ + qos_node_create_machine_args("loongarch64/virt", + qos_create_machine_loongarch_virt, + " -cpu la464"); + qos_node_contains("loongarch64/virt", "generic-pcihost", NULL); +} + +libqos_init(virt_machine_register_nodes); diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build index 90aae42a22535f0dd8fe2fe7f9a615dd1b9a805b..482c9b2aab99dc0ef0dc4d1c7a2ce6468ecb640a 100644 --- a/tests/qtest/libqos/meson.build +++ b/tests/qtest/libqos/meson.build @@ -60,6 +60,7 @@ libqos_srcs = files( 'arm-xilinx-zynq-a9-machine.c', 'ppc64_pseries-machine.c', 'x86_64_pc-machine.c', + 'loongarch-virt-machine.c', ) if have_virtfs