diff --git a/hw-intc-loongarch_extioi-Add-virt-extension-support.patch b/hw-intc-loongarch_extioi-Add-virt-extension-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..e02d5afcf8f7bf23790de1713829abbdd9b51d73 --- /dev/null +++ b/hw-intc-loongarch_extioi-Add-virt-extension-support.patch @@ -0,0 +1,434 @@ +From 04aef27ede108edd63d288dd3bb395e22a603f42 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Mon, 11 Mar 2024 15:01:31 +0800 +Subject: [PATCH] hw/intc/loongarch_extioi: Add virt extension support + +With hardware extioi, irq can be routed to four vcpus with hardware +extioi. This patch adds virt extension support, sot that irq can +be routed to 256 vcpus. + +Signed-off-by: Song Gao +Signed-off-by: Bibo Mao +--- + hw/intc/loongarch_extioi.c | 88 ++++++++++++++++++++- + hw/loongarch/virt.c | 122 ++++++++++++++++++++++++++--- + include/hw/intc/loongarch_extioi.h | 21 +++++ + include/hw/loongarch/virt.h | 3 + + target/loongarch/cpu.h | 1 + + 5 files changed, 220 insertions(+), 15 deletions(-) + +diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c +index bdfa3b481e..fa23e247ca 100644 +--- a/hw/intc/loongarch_extioi.c ++++ b/hw/intc/loongarch_extioi.c +@@ -143,15 +143,17 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq, + + for (i = 0; i < 4; i++) { + cpu = val & 0xff; +- cpu = ctz32(cpu); +- cpu = (cpu >= 4) ? 0 : cpu; ++ if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) { ++ cpu = ctz32(cpu); ++ cpu = (cpu >= 4) ? 0 : cpu; ++ } + val = val >> 8; + + if (s->sw_coremap[irq + i] == cpu) { + continue; + } + +- if (notify && test_bit(irq, (unsigned long *)s->isr)) { ++ if (notify && test_bit(irq + i, (unsigned long *)s->isr)) { + /* + * lower irq at old cpu and raise irq at new cpu + */ +@@ -265,6 +267,61 @@ static const MemoryRegionOps extioi_ops = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + ++static MemTxResult extioi_virt_readw(void *opaque, hwaddr addr, uint64_t *data, ++ unsigned size, MemTxAttrs attrs) ++{ ++ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); ++ ++ switch (addr) { ++ case EXTIOI_VIRT_FEATURES: ++ *data = s->features; ++ break; ++ case EXTIOI_VIRT_CONFIG: ++ *data = s->status; ++ break; ++ default: ++ break; ++ } ++ ++ return MEMTX_OK; ++} ++ ++static MemTxResult extioi_virt_writew(void *opaque, hwaddr addr, ++ uint64_t val, unsigned size, ++ MemTxAttrs attrs) ++{ ++ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); ++ ++ switch (addr) { ++ case EXTIOI_VIRT_FEATURES: ++ return MEMTX_ACCESS_ERROR; ++ ++ case EXTIOI_VIRT_CONFIG: ++ /* ++ * extioi features can only be set at disabled status ++ */ ++ if ((s->status & BIT(EXTIOI_ENABLE)) && val) { ++ return MEMTX_ACCESS_ERROR; ++ } ++ ++ s->status = val & s->features; ++ break; ++ default: ++ break; ++ } ++ return MEMTX_OK; ++} ++ ++static const MemoryRegionOps extioi_virt_ops = { ++ .read_with_attrs = extioi_virt_readw, ++ .write_with_attrs = extioi_virt_writew, ++ .impl.min_access_size = 4, ++ .impl.max_access_size = 4, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 8, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ + static void loongarch_extioi_realize(DeviceState *dev, Error **errp) + { + LoongArchExtIOI *s = LOONGARCH_EXTIOI(dev); +@@ -284,6 +341,16 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp) + memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops, + s, "extioi_system_mem", 0x900); + sysbus_init_mmio(sbd, &s->extioi_system_mem); ++ ++ if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) { ++ memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops, ++ s, "extioi_virt", EXTIOI_VIRT_SIZE); ++ sysbus_init_mmio(sbd, &s->virt_extend); ++ s->features |= EXTIOI_VIRT_HAS_FEATURES; ++ } else { ++ s->status |= BIT(EXTIOI_ENABLE); ++ } ++ + s->cpu = g_new0(ExtIOICore, s->num_cpu); + if (s->cpu == NULL) { + error_setg(errp, "Memory allocation for ExtIOICore faile"); +@@ -304,6 +371,16 @@ static void loongarch_extioi_finalize(Object *obj) + g_free(s->cpu); + } + ++static void loongarch_extioi_reset(DeviceState *d) ++{ ++ LoongArchExtIOI *s = LOONGARCH_EXTIOI(d); ++ ++ /* use legacy interrupt routing method by default */ ++ if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) { ++ s->status = 0; ++ } ++} ++ + static int vmstate_extioi_post_load(void *opaque, int version_id) + { + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); +@@ -347,12 +424,16 @@ static const VMStateDescription vmstate_loongarch_extioi = { + + VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOI, num_cpu, + vmstate_extioi_core, ExtIOICore), ++ VMSTATE_UINT32(features, LoongArchExtIOI), ++ VMSTATE_UINT32(status, LoongArchExtIOI), + VMSTATE_END_OF_LIST() + } + }; + + static Property extioi_properties[] = { + DEFINE_PROP_UINT32("num-cpu", LoongArchExtIOI, num_cpu, 1), ++ DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOI, features, ++ EXTIOI_HAS_VIRT_EXTENSION, 0), + DEFINE_PROP_END_OF_LIST(), + }; + +@@ -361,6 +442,7 @@ static void loongarch_extioi_class_init(ObjectClass *klass, void *data) + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = loongarch_extioi_realize; ++ dc->reset = loongarch_extioi_reset; + device_class_set_props(dc, extioi_properties); + dc->vmsd = &vmstate_loongarch_extioi; + } +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 6ef40fa24a..01e59f3a95 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -15,6 +15,8 @@ + #include "sysemu/runstate.h" + #include "sysemu/reset.h" + #include "sysemu/rtc.h" ++#include "sysemu/tcg.h" ++#include "sysemu/kvm.h" + #include "hw/loongarch/virt.h" + #include "exec/address-spaces.h" + #include "hw/irq.h" +@@ -54,6 +56,31 @@ struct loaderparams { + const char *initrd_filename; + }; + ++static bool virt_is_veiointc_enabled(LoongArchMachineState *lams) ++{ ++ if (lams->veiointc == ON_OFF_AUTO_OFF) { ++ return false; ++ } ++ return true; ++} ++ ++static void virt_get_veiointc(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); ++ OnOffAuto veiointc = lams->veiointc; ++ ++ visit_type_OnOffAuto(v, name, &veiointc, errp); ++} ++ ++static void virt_set_veiointc(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); ++ ++ visit_type_OnOffAuto(v, name, &lams->veiointc, errp); ++} ++ + static PFlashCFI01 *virt_flash_create1(LoongArchMachineState *lams, + const char *name, + const char *alias_prop_name) +@@ -618,9 +645,18 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + /* Create EXTIOI device */ + extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); + qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus); ++ if (virt_is_veiointc_enabled(lams)) { ++ qdev_prop_set_bit(extioi, "has-virtualization-extension", true); ++ } + sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); ++ + memory_region_add_subregion(&lams->system_iocsr, APIC_BASE, + sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0)); ++ if (virt_is_veiointc_enabled(lams)) { ++ memory_region_add_subregion(&lams->system_iocsr, EXTIOI_VIRT_BASE, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1)); ++ } ++ lams->extioi = extioi; + + /* + * connect ext irq to the cpu irq +@@ -780,32 +816,87 @@ static void loongarch_direct_kernel_boot(LoongArchMachineState *lams, + } + } + +-static void loongarch_qemu_write(void *opaque, hwaddr addr, +- uint64_t val, unsigned size) ++static MemTxResult loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size, MemTxAttrs attrs) + { ++ LoongArchMachineState *lams = LOONGARCH_MACHINE(opaque); ++ uint64_t features; ++ ++ switch (addr) { ++ case MISC_FUNC_REG: ++ if (!virt_is_veiointc_enabled(lams)) { ++ return MEMTX_OK; ++ } ++ ++ features = address_space_ldl(&lams->as_iocsr, ++ EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, ++ attrs, NULL); ++ if (val & BIT_ULL(IOCSRM_EXTIOI_EN)) { ++ features |= BIT(EXTIOI_ENABLE); ++ } ++ if (val & BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE)) { ++ features |= BIT(EXTIOI_ENABLE_INT_ENCODE); ++ } ++ ++ address_space_stl(&lams->as_iocsr, ++ EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, ++ features, attrs, NULL); ++ } ++ ++ return MEMTX_OK; + } + +-static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size) ++static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, ++ uint64_t *data, ++ unsigned size, MemTxAttrs attrs) + { ++ LoongArchMachineState *lams = LOONGARCH_MACHINE(opaque); ++ uint64_t ret = 0; ++ int features; ++ + switch (addr) { + case VERSION_REG: +- return 0x11ULL; ++ ret = 0x11ULL; ++ break; + case FEATURE_REG: +- return 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI | +- 1ULL << IOCSRF_CSRIPI; ++ ret = 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI | ++ 1ULL << IOCSRF_CSRIPI; ++ if (kvm_enabled()) { ++ ret |= 1ULL << IOCSRF_VM; ++ } ++ break; + case VENDOR_REG: +- return 0x6e6f73676e6f6f4cULL; /* "Loongson" */ ++ ret = 0x6e6f73676e6f6f4cULL; /* "Loongson" */ ++ break; + case CPUNAME_REG: +- return 0x303030354133ULL; /* "3A5000" */ ++ ret = 0x303030354133ULL; /* "3A5000" */ ++ break; + case MISC_FUNC_REG: +- return 1ULL << IOCSRM_EXTIOI_EN; ++ if (!virt_is_veiointc_enabled(lams)) { ++ ret |= BIT_ULL(IOCSRM_EXTIOI_EN); ++ break; ++ } ++ ++ features = address_space_ldl(&lams->as_iocsr, ++ EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, ++ attrs, NULL); ++ if (features & BIT(EXTIOI_ENABLE)) { ++ ret |= BIT_ULL(IOCSRM_EXTIOI_EN); ++ } ++ ++ if (features & BIT(EXTIOI_ENABLE_INT_ENCODE)) { ++ ret |= BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE); ++ } ++ break; + } +- return 0ULL; ++ ++ *data = ret; ++ return MEMTX_OK; + } + + static const MemoryRegionOps loongarch_qemu_ops = { +- .read = loongarch_qemu_read, +- .write = loongarch_qemu_write, ++ .read_with_attrs = loongarch_qemu_read, ++ .write_with_attrs = loongarch_qemu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, +@@ -1010,6 +1101,9 @@ static void loongarch_machine_initfn(Object *obj) + { + LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); + ++ if (tcg_enabled()) { ++ lams->veiointc = ON_OFF_AUTO_OFF; ++ } + 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); +@@ -1197,6 +1291,10 @@ static void loongarch_class_init(ObjectClass *oc, void *data) + NULL, NULL); + object_class_property_set_description(oc, "acpi", + "Enable ACPI"); ++ object_class_property_add(oc, "v-eiointc", "OnOffAuto", ++ virt_get_veiointc, virt_set_veiointc, NULL, NULL); ++ object_class_property_set_description(oc, "v-eiointc", ++ "Enable Virt Extend I/O Interrupt Controller"); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); + #ifdef CONFIG_TPM + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); +diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h +index a0a46b888c..98f348c49d 100644 +--- a/include/hw/intc/loongarch_extioi.h ++++ b/include/hw/intc/loongarch_extioi.h +@@ -40,6 +40,24 @@ + #define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET) + #define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET) + ++#define EXTIOI_VIRT_BASE (0x40000000) ++#define EXTIOI_VIRT_SIZE (0x1000) ++#define EXTIOI_VIRT_FEATURES (0x0) ++#define EXTIOI_HAS_VIRT_EXTENSION (0) ++#define EXTIOI_HAS_ENABLE_OPTION (1) ++#define EXTIOI_HAS_INT_ENCODE (2) ++#define EXTIOI_HAS_CPU_ENCODE (3) ++#define EXTIOI_VIRT_HAS_FEATURES (BIT(EXTIOI_HAS_VIRT_EXTENSION) \ ++ | BIT(EXTIOI_HAS_ENABLE_OPTION)\ ++ | BIT(EXTIOI_HAS_INT_ENCODE) \ ++ | BIT(EXTIOI_HAS_CPU_ENCODE)) ++#define EXTIOI_VIRT_CONFIG (0x4) ++#define EXTIOI_ENABLE (1) ++#define EXTIOI_ENABLE_INT_ENCODE (2) ++#define EXTIOI_ENABLE_CPU_ENCODE (3) ++#define EXTIOI_VIRT_COREMAP_START (0x40) ++#define EXTIOI_VIRT_COREMAP_END (0x240) ++ + typedef struct ExtIOICore { + uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT]; + DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS); +@@ -51,6 +69,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI) + struct LoongArchExtIOI { + SysBusDevice parent_obj; + uint32_t num_cpu; ++ uint32_t features; ++ uint32_t status; + /* hardware state */ + uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2]; + uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT]; +@@ -64,5 +84,6 @@ struct LoongArchExtIOI { + qemu_irq irq[EXTIOI_IRQS]; + ExtIOICore *cpu; + MemoryRegion extioi_system_mem; ++ MemoryRegion virt_extend; + }; + #endif /* LOONGARCH_EXTIOI_H */ +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 252f7df7f4..99447fd1d6 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -45,16 +45,19 @@ struct LoongArchMachineState { + Notifier machine_done; + Notifier powerdown_notifier; + OnOffAuto acpi; ++ OnOffAuto veiointc; + char *oem_id; + char *oem_table_id; + DeviceState *acpi_ged; + int fdt_size; + DeviceState *platform_bus_dev; ++ DeviceState *extioi; + PCIBus *pci_bus; + PFlashCFI01 *flash[2]; + MemoryRegion system_iocsr; + MemoryRegion iocsr_mem; + AddressSpace as_iocsr; ++ int features; + }; + + #define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 4aba8aba4c..4749d41c8c 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -36,6 +36,7 @@ + #define CPUNAME_REG 0x20 + #define MISC_FUNC_REG 0x420 + #define IOCSRM_EXTIOI_EN 48 ++#define IOCSRM_EXTIOI_INT_ENCODE 49 + + #define IOCSR_MEM_SIZE 0x428 + +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index cec3ffccd00dda9eb7ef4dc8ad69059df3807519..e1b8fbed4c3dcfb30edae17f69b43fea46c32349 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 12 +Release: 13 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -259,6 +259,16 @@ Patch0242: hw-isa-vt82c686-Keep-track-of-PIRQ-PINT-pins-separat.patch Patch0243: target-i386-Introduce-Icelake-Server-v7-to-enable-TS.patch Patch0244: target-i386-Add-new-CPU-model-SierraForest.patch Patch0245: target-i386-Export-RFDS-bit-to-guests.patch +Patch0246: target-loongarch-Fix-qemu-system-loongarch64-assert-.patch +Patch0247: target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch +Patch0248: target-loongarch-Fix-tlb-huge-page-loading-issue.patch +Patch0249: target-loongarch-kvm-Add-software-breakpoint-support.patch +Patch0250: target-loongarch-kvm-sync-kernel-header-files.patch +Patch0251: hw-intc-loongarch_extioi-Add-virt-extension-support.patch +Patch0252: target-loongarch-kvm-Add-pmu-support.patch +Patch0253: target-loongarch-kvm-Fix-vm-restore-failed.patch +Patch0254: target-loongarch-kvm-Add-pv-steal-time-support.patch +Patch0255: target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch BuildRequires: flex BuildRequires: gcc @@ -856,7 +866,19 @@ getent passwd qemu >/dev/null || \ %endif %changelog -* Thu May 10 2024 zhangxianting - 11:8.2.0-12 +* Mon May 20 2024 Song Gao - 11:8.2.0-13 +- target/loongarch: Fix qemu-system-loongarch64 assert +- target/loongarch: Fix qemu-loongarch64 hang when executing 'll.d $t0, $t0, 0' +- target/loongarch: Fix tlb huge page loading issue +- target/loongarch/kvm: Add software breakpoint support +- target/loongarch/kvm: sync kernel header files +- hw/intc/loongarch_extioi: Add virt extension support +- target/loongarch/kvm: Add pmu support +- target/loongarch/kvm: Fix vm restore failed +- target/loongarch/kvm: Add pv steal time support +- target/loongarch/kvm: fpu save the vreg registers high + +* Fri May 10 2024 zhangxianting - 11:8.2.0-12 - target/i386: Export RFDS bit to guests - target/i386: Add new CPU model SierraForest - target/i386: Introduce Icelake-Server-v7 to enable TSX @@ -867,10 +889,7 @@ getent passwd qemu >/dev/null || \ - arm/virt: Don't modify smp.max_cpus when vcpu hotplug disabled - acpi/cpu: Fix detection of present cpu -* Wed Apr 17 2024 zhangxianting - 11:8.2.0-11 -- remove chrpath - -* Mon Apr 22 2024 Jiabo Feng - 11:8.2.0-10 +* Mon Apr 22 2024 Jiabo Feng - 11:8.2.0-11 - hw/sd/sdhci: Do not update TRNMOD when Command Inhibit (DAT) is set(CVE-2024-3447) - hw/virtio/virtio-crypto: Protect from DMA re-entrancy bugs(CVE-2024-3446) - hw/char/virtio-serial-bus: Protect from DMA re-entrancy bugs(CVE-2024-3446) @@ -883,9 +902,12 @@ getent passwd qemu >/dev/null || \ - hw/scsi/scsi-generic: Fix io_timeout property not applying - tests: bios-tables-test: Rename smbios type 4 related test functions -* Thu Apr 18 2024 Tao Yang - 11:8.2.0-9 +* Thu Apr 18 2024 Tao Yang - 11:8.2.0-10 - add '--enable-slirp' compilation options +* Wed Apr 17 2024 zhangxianting - 11:8.2.0-9 +- remove chrpath + * Wed Apr 17 2024 Jiabo Feng - 11:8.2.0-8 - include/ui/rect.h: fix qemu_rect_init() mis-assignment diff --git a/target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch b/target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch new file mode 100644 index 0000000000000000000000000000000000000000..f94c68bba1a2e09e031cb55c27a219eb9a392f49 --- /dev/null +++ b/target-loongarch-Fix-qemu-loongarch64-hang-when-exec.patch @@ -0,0 +1,45 @@ +From 6d175f9d5d5b9f46ee2f1a6fe00249bb817b5dc6 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Wed, 20 Mar 2024 09:39:55 +0800 +Subject: [PATCH] target/loongarch: Fix qemu-loongarch64 hang when + executing 'll.d $t0, $t0, 0' + +On gen_ll, if a->imm is zero, make_address_x return src1, +but the load to destination may clobber src1. We use a new +destination to fix this problem. + +Fixes: c5af6628f4be (target/loongarch: Extract make_address_i() helper) +Reviewed-by: Richard Henderson +Suggested-by: Richard Henderson +Signed-off-by: Song Gao +Message-Id: <20240320013955.1561311-1-gaosong@loongson.cn> +--- + target/loongarch/tcg/insn_trans/trans_atomic.c.inc | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/target/loongarch/tcg/insn_trans/trans_atomic.c.inc b/target/loongarch/tcg/insn_trans/trans_atomic.c.inc +index 80c2e286fd..974bc2a70f 100644 +--- a/target/loongarch/tcg/insn_trans/trans_atomic.c.inc ++++ b/target/loongarch/tcg/insn_trans/trans_atomic.c.inc +@@ -5,14 +5,14 @@ + + static bool gen_ll(DisasContext *ctx, arg_rr_i *a, MemOp mop) + { +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); ++ TCGv t1 = tcg_temp_new(); + TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + TCGv t0 = make_address_i(ctx, src1, a->imm); + +- tcg_gen_qemu_ld_i64(dest, t0, ctx->mem_idx, mop); ++ tcg_gen_qemu_ld_i64(t1, t0, ctx->mem_idx, mop); + tcg_gen_st_tl(t0, tcg_env, offsetof(CPULoongArchState, lladdr)); +- tcg_gen_st_tl(dest, tcg_env, offsetof(CPULoongArchState, llval)); +- gen_set_gpr(a->rd, dest, EXT_NONE); ++ tcg_gen_st_tl(t1, tcg_env, offsetof(CPULoongArchState, llval)); ++ gen_set_gpr(a->rd, t1, EXT_NONE); + + return true; + } +-- +2.33.0 + diff --git a/target-loongarch-Fix-qemu-system-loongarch64-assert-.patch b/target-loongarch-Fix-qemu-system-loongarch64-assert-.patch new file mode 100644 index 0000000000000000000000000000000000000000..d7c39f0f16831c3351599a41a08e1e6f95c67272 --- /dev/null +++ b/target-loongarch-Fix-qemu-system-loongarch64-assert-.patch @@ -0,0 +1,136 @@ +From 3db0118d3663c5d56841dac30e4bf95ccfff21bd Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Tue, 2 Apr 2024 09:39:36 +0800 +Subject: [PATCH] target/loongarch: Fix qemu-system-loongarch64 assert + failed with the option '-d int' +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +qemu-system-loongarch64 assert failed with the option '-d int', +the helper_idle() raise an exception EXCP_HLT, but the exception name is undefined. + +----- +merge patch: + +0cbb322f70e8a87e4acbffecef5ea8f9448f3513(target/loongarch/cpu.c: typo fix: expection) + +Signed-off-by: Song Gao +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20240321123606.1704900-1-gaosong@loongson.cn> +--- + target/loongarch/cpu.c | 74 +++++++++++++++++++++++------------------- + 1 file changed, 40 insertions(+), 34 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index b098b1c6f3..0b3f954b64 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -43,33 +43,45 @@ const char * const fregnames[32] = { + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + }; + +-static const char * const excp_names[] = { +- [EXCCODE_INT] = "Interrupt", +- [EXCCODE_PIL] = "Page invalid exception for load", +- [EXCCODE_PIS] = "Page invalid exception for store", +- [EXCCODE_PIF] = "Page invalid exception for fetch", +- [EXCCODE_PME] = "Page modified exception", +- [EXCCODE_PNR] = "Page Not Readable exception", +- [EXCCODE_PNX] = "Page Not Executable exception", +- [EXCCODE_PPI] = "Page Privilege error", +- [EXCCODE_ADEF] = "Address error for instruction fetch", +- [EXCCODE_ADEM] = "Address error for Memory access", +- [EXCCODE_SYS] = "Syscall", +- [EXCCODE_BRK] = "Break", +- [EXCCODE_INE] = "Instruction Non-Existent", +- [EXCCODE_IPE] = "Instruction privilege error", +- [EXCCODE_FPD] = "Floating Point Disabled", +- [EXCCODE_FPE] = "Floating Point Exception", +- [EXCCODE_DBP] = "Debug breakpoint", +- [EXCCODE_BCE] = "Bound Check Exception", +- [EXCCODE_SXD] = "128 bit vector instructions Disable exception", +- [EXCCODE_ASXD] = "256 bit vector instructions Disable exception", ++struct TypeExcp { ++ int32_t exccode; ++ const char * const name; ++}; ++ ++static const struct TypeExcp excp_names[] = { ++ {EXCCODE_INT, "Interrupt"}, ++ {EXCCODE_PIL, "Page invalid exception for load"}, ++ {EXCCODE_PIS, "Page invalid exception for store"}, ++ {EXCCODE_PIF, "Page invalid exception for fetch"}, ++ {EXCCODE_PME, "Page modified exception"}, ++ {EXCCODE_PNR, "Page Not Readable exception"}, ++ {EXCCODE_PNX, "Page Not Executable exception"}, ++ {EXCCODE_PPI, "Page Privilege error"}, ++ {EXCCODE_ADEF, "Address error for instruction fetch"}, ++ {EXCCODE_ADEM, "Address error for Memory access"}, ++ {EXCCODE_SYS, "Syscall"}, ++ {EXCCODE_BRK, "Break"}, ++ {EXCCODE_INE, "Instruction Non-Existent"}, ++ {EXCCODE_IPE, "Instruction privilege error"}, ++ {EXCCODE_FPD, "Floating Point Disabled"}, ++ {EXCCODE_FPE, "Floating Point Exception"}, ++ {EXCCODE_DBP, "Debug breakpoint"}, ++ {EXCCODE_BCE, "Bound Check Exception"}, ++ {EXCCODE_SXD, "128 bit vector instructions Disable exception"}, ++ {EXCCODE_ASXD, "256 bit vector instructions Disable exception"}, ++ {EXCP_HLT, "EXCP_HLT"}, + }; + + const char *loongarch_exception_name(int32_t exception) + { +- assert(excp_names[exception]); +- return excp_names[exception]; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(excp_names); i++) { ++ if (excp_names[i].exccode == exception) { ++ return excp_names[i].name; ++ } ++ } ++ return "Unknown"; + } + + void G_NORETURN do_raise_exception(CPULoongArchState *env, +@@ -78,7 +90,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env, + { + CPUState *cs = env_cpu(env); + +- qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n", ++ qemu_log_mask(CPU_LOG_INT, "%s: exception: %d (%s)\n", + __func__, + exception, + loongarch_exception_name(exception)); +@@ -159,22 +171,16 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) + CPULoongArchState *env = &cpu->env; + bool update_badinstr = 1; + int cause = -1; +- const char *name; + bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR); + uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS); + + if (cs->exception_index != EXCCODE_INT) { +- if (cs->exception_index < 0 || +- cs->exception_index >= ARRAY_SIZE(excp_names)) { +- name = "unknown"; +- } else { +- name = excp_names[cs->exception_index]; +- } +- + qemu_log_mask(CPU_LOG_INT, + "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx +- " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__, +- env->pc, env->CSR_ERA, env->CSR_TLBRERA, name); ++ " TLBRERA " TARGET_FMT_lx " exception: %d (%s)\n", ++ __func__, env->pc, env->CSR_ERA, env->CSR_TLBRERA, ++ cs->exception_index, ++ loongarch_exception_name(cs->exception_index)); + } + + switch (cs->exception_index) { +-- +2.33.0 + diff --git a/target-loongarch-Fix-tlb-huge-page-loading-issue.patch b/target-loongarch-Fix-tlb-huge-page-loading-issue.patch new file mode 100644 index 0000000000000000000000000000000000000000..467e6d745444102b0eefc14e2d06c01bba6115b2 --- /dev/null +++ b/target-loongarch-Fix-tlb-huge-page-loading-issue.patch @@ -0,0 +1,208 @@ +From c5938b5f858ee8904893e08999df1af1ae13b063 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Mon, 18 Mar 2024 15:03:32 +0800 +Subject: [PATCH] target/loongarch: Fix tlb huge page loading issue + +When we use qemu tcg simulation, the page size of bios is 4KB. +When using the level 2 super huge page (page size is 1G) to create the page table, +it is found that the content of the corresponding address space is abnormal, +resulting in the bios can not start the operating system and graphical interface normally. + +The lddir and ldpte instruction emulation has +a problem with the use of super huge page processing above level 2. +The page size is not correctly calculated, +resulting in the wrong page size of the table entry found by tlb. + +Signed-off-by: Xianglai Li +Reviewed-by: Richard Henderson +Signed-off-by: Song Gao +Message-Id: <20240318070332.1273939-1-lixianglai@loongson.cn> +--- + target/loongarch/cpu-csr.h | 3 + + target/loongarch/internals.h | 5 -- + target/loongarch/tcg/tlb_helper.c | 113 +++++++++++++++++++++--------- + 3 files changed, 82 insertions(+), 39 deletions(-) + +diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h +index c59d7a9fcb..0834e91f30 100644 +--- a/target/loongarch/cpu-csr.h ++++ b/target/loongarch/cpu-csr.h +@@ -67,6 +67,9 @@ FIELD(TLBENTRY, D, 1, 1) + FIELD(TLBENTRY, PLV, 2, 2) + FIELD(TLBENTRY, MAT, 4, 2) + FIELD(TLBENTRY, G, 6, 1) ++FIELD(TLBENTRY, HUGE, 6, 1) ++FIELD(TLBENTRY, HGLOBAL, 12, 1) ++FIELD(TLBENTRY, LEVEL, 13, 2) + FIELD(TLBENTRY_32, PPN, 8, 24) + FIELD(TLBENTRY_64, PPN, 12, 36) + FIELD(TLBENTRY_64, NR, 61, 1) +diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h +index a2fc54c8a7..944153b180 100644 +--- a/target/loongarch/internals.h ++++ b/target/loongarch/internals.h +@@ -16,11 +16,6 @@ + #define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS) + #define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS) + +-/* Global bit used for lddir/ldpte */ +-#define LOONGARCH_PAGE_HUGE_SHIFT 6 +-/* Global bit for huge page */ +-#define LOONGARCH_HGLOBAL_SHIFT 12 +- + void loongarch_translate_init(void); + + void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); +diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c +index 804ab7a263..eedd1ac376 100644 +--- a/target/loongarch/tcg/tlb_helper.c ++++ b/target/loongarch/tcg/tlb_helper.c +@@ -17,6 +17,34 @@ + #include "exec/log.h" + #include "cpu-csr.h" + ++static void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, ++ uint64_t *dir_width, target_ulong level) ++{ ++ switch (level) { ++ case 1: ++ *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE); ++ *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH); ++ break; ++ case 2: ++ *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE); ++ *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH); ++ break; ++ case 3: ++ *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE); ++ *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH); ++ break; ++ case 4: ++ *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE); ++ *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH); ++ break; ++ default: ++ /* level may be zero for ldpte */ ++ *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); ++ *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); ++ break; ++ } ++} ++ + static void raise_mmu_exception(CPULoongArchState *env, target_ulong address, + MMUAccessType access_type, int tlb_error) + { +@@ -486,7 +514,25 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base, + target_ulong badvaddr, index, phys, ret; + int shift; + uint64_t dir_base, dir_width; +- bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; ++ ++ if (unlikely((level == 0) || (level > 4))) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Attepted LDDIR with level %"PRId64"\n", level); ++ return base; ++ } ++ ++ if (FIELD_EX64(base, TLBENTRY, HUGE)) { ++ if (unlikely(level == 4)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Attempted use of level 4 huge page\n"); ++ } ++ ++ if (FIELD_EX64(base, TLBENTRY, LEVEL)) { ++ return base; ++ } else { ++ return FIELD_DP64(base, TLBENTRY, LEVEL, level); ++ } ++ } + + badvaddr = env->CSR_TLBRBADV; + base = base & TARGET_PHYS_MASK; +@@ -495,30 +541,7 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base, + shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); + shift = (shift + 1) * 3; + +- if (huge) { +- return base; +- } +- switch (level) { +- case 1: +- dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE); +- dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH); +- break; +- case 2: +- dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE); +- dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH); +- break; +- case 3: +- dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE); +- dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH); +- break; +- case 4: +- dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE); +- dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH); +- break; +- default: +- do_raise_exception(env, EXCCODE_INE, GETPC()); +- return 0; +- } ++ get_dir_base_width(env, &dir_base, &dir_width, level); + index = (badvaddr >> dir_base) & ((1 << dir_width) - 1); + phys = base | index << shift; + ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; +@@ -531,20 +554,42 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd, + CPUState *cs = env_cpu(env); + target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv; + int shift; +- bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1; + uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); + uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); ++ uint64_t dir_base, dir_width; + ++ /* ++ * The parameter "base" has only two types, ++ * one is the page table base address, ++ * whose bit 6 should be 0, ++ * and the other is the huge page entry, ++ * whose bit 6 should be 1. ++ */ + base = base & TARGET_PHYS_MASK; ++ if (FIELD_EX64(base, TLBENTRY, HUGE)) { ++ /* ++ * Gets the huge page level and Gets huge page size. ++ * Clears the huge page level information in the entry. ++ * Clears huge page bit. ++ * Move HGLOBAL bit to GLOBAL bit. ++ */ ++ get_dir_base_width(env, &dir_base, &dir_width, ++ FIELD_EX64(base, TLBENTRY, LEVEL)); ++ ++ base = FIELD_DP64(base, TLBENTRY, LEVEL, 0); ++ base = FIELD_DP64(base, TLBENTRY, HUGE, 0); ++ if (FIELD_EX64(base, TLBENTRY, HGLOBAL)) { ++ base = FIELD_DP64(base, TLBENTRY, HGLOBAL, 0); ++ base = FIELD_DP64(base, TLBENTRY, G, 1); ++ } + +- if (huge) { +- /* Huge Page. base is paddr */ +- tmp0 = base ^ (1 << LOONGARCH_PAGE_HUGE_SHIFT); +- /* Move Global bit */ +- tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT)) >> +- LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT | +- (tmp0 & (~(1 << LOONGARCH_HGLOBAL_SHIFT))); +- ps = ptbase + ptwidth - 1; ++ ps = dir_base + dir_width - 1; ++ /* ++ * Huge pages are evenly split into parity pages ++ * when loaded into the tlb, ++ * so the tlb page size needs to be divided by 2. ++ */ ++ tmp0 = base; + if (odd) { + tmp0 += MAKE_64BIT_MASK(ps, 1); + } +-- +2.33.0 + diff --git a/target-loongarch-kvm-Add-pmu-support.patch b/target-loongarch-kvm-Add-pmu-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..5a5650a903c670138079db6e2d1bb6902e81a4ff --- /dev/null +++ b/target-loongarch-kvm-Add-pmu-support.patch @@ -0,0 +1,224 @@ +From 57db061a63243c64c07624740fc039ddcc4777a2 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 22 Mar 2024 19:26:35 +0800 +Subject: [PATCH] target/loongarch/kvm: Add pmu support + +This patch adds PMU support + e.g + '... -cpu max,pmu=on,pmnum=[1-16]'; + '... -cpu max,pmu=on' (default pmnum = 4); + '... -cpu max,pmu=off' (disable PMU) + +Signed-off-by: Song Gao +--- + target/loongarch/cpu.c | 64 +++++++++++++++++++++++++++ + target/loongarch/cpu.h | 2 + + target/loongarch/kvm/kvm.c | 55 ++++++++++++++++++++++- + target/loongarch/loongarch-qmp-cmds.c | 2 +- + 4 files changed, 121 insertions(+), 2 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index fdb819c2cf..bc557f207b 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -8,6 +8,7 @@ + #include "qemu/osdep.h" + #include "qemu/log.h" + #include "qemu/qemu-print.h" ++#include "qemu/error-report.h" + #include "qapi/error.h" + #include "qemu/module.h" + #include "sysemu/qtest.h" +@@ -19,6 +20,7 @@ + #include "internals.h" + #include "fpu/softfloat-helpers.h" + #include "cpu-csr.h" ++#include "qapi/visitor.h" + #include "sysemu/reset.h" + #include "vec.h" + #ifdef CONFIG_KVM +@@ -426,6 +428,14 @@ static void loongarch_la464_initfn(Object *obj) + data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1); + env->cpucfg[5] = data; + ++ if (kvm_enabled()) { ++ data = 0; ++ data = FIELD_DP32(data, CPUCFG6, PMP, 1); ++ data = FIELD_DP32(data, CPUCFG6, PMNUM, 3); ++ data = FIELD_DP32(data, CPUCFG6, PMBITS, 63); ++ env->cpucfg[6] = data; ++ } ++ + data = 0; + data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1); + data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1); +@@ -660,6 +670,48 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp) + } + } + ++static bool loongarch_get_pmu(Object *obj, Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(obj); ++ ++ return !!(FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP)); ++} ++ ++static void loongarch_set_pmu(Object *obj, bool value, Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(obj); ++ ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, value); ++} ++ ++static void loongarch_get_pmnum(Object *obj, Visitor *v, ++ const char *name, void *opaque, ++ Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(obj); ++ uint32_t value = FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMNUM); ++ ++ visit_type_uint32(v, name, &value, errp); ++} ++ ++static void loongarch_set_pmnum(Object *obj, Visitor *v, ++ const char *name, void *opaque, ++ Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(obj); ++ uint32_t *value= opaque; ++ ++ if (!visit_type_uint32(v, name, value, errp)) { ++ return; ++ } ++ if ((*value <= PMNUM_MAX) && (*value > 0)) { ++ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMNUM, *value -1); ++ } else { ++ error_report("Performance counter number need be in [1- %d]\n", PMNUM_MAX); ++ exit(EXIT_FAILURE); ++ } ++} ++ + void loongarch_cpu_post_init(Object *obj) + { + LoongArchCPU *cpu = LOONGARCH_CPU(obj); +@@ -672,6 +724,18 @@ void loongarch_cpu_post_init(Object *obj) + object_property_add_bool(obj, "lasx", loongarch_get_lasx, + loongarch_set_lasx); + } ++ ++ if (kvm_enabled()) { ++ object_property_add_bool(obj, "pmu", loongarch_get_pmu, ++ loongarch_set_pmu); ++ if (FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP)) { ++ uint32_t value = 4; ++ object_property_add(obj, "pmnum", "uint32", ++ loongarch_get_pmnum, ++ loongarch_set_pmnum, NULL, ++ (void *)&value); ++ } ++ } + } + + static void loongarch_cpu_init(Object *obj) +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 4749d41c8c..80cad24fa1 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -186,6 +186,8 @@ FIELD(CPUCFG6, PMNUM, 4, 4) + FIELD(CPUCFG6, PMBITS, 8, 6) + FIELD(CPUCFG6, UPM, 14, 1) + ++#define PMNUM_MAX 16 ++ + /* cpucfg[16] bits */ + FIELD(CPUCFG16, L1_IUPRE, 0, 1) + FIELD(CPUCFG16, L1_IUUNIFY, 1, 1) +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 49d02076ad..5dda631b2b 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -573,6 +573,53 @@ static int kvm_check_cpucfg2(CPUState *cs) + return ret; + } + ++static int kvm_check_cpucfg6(CPUState *cs) ++{ ++ int ret; ++ uint64_t val; ++ struct kvm_device_attr attr = { ++ .group = KVM_LOONGARCH_VCPU_CPUCFG, ++ .attr = 6, ++ .addr = (uint64_t)&val, ++ }; ++ LoongArchCPU *cpu = LOONGARCH_CPU(cs); ++ CPULoongArchState *env = &cpu->env; ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); ++ if (!ret) { ++ kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr); ++ ++ if (FIELD_EX32(env->cpucfg[6], CPUCFG6, PMP)) { ++ /* Check PMP */ ++ if (!FIELD_EX32(val, CPUCFG6, PMP)) { ++ error_report("'pmu' feature not supported by KVM on this host" ++ " Please disable 'pmu' with " ++ "'... -cpu XXX,pmu=off ...'\n"); ++ exit(EXIT_FAILURE); ++ } ++ /* Check PMNUM */ ++ int guest_pmnum = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMNUM); ++ int host_pmnum = FIELD_EX32(val, CPUCFG6, PMNUM); ++ if (guest_pmnum > host_pmnum){ ++ warn_report("The guest pmnum %d larger than KVM support %d\n", ++ guest_pmnum, host_pmnum); ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, ++ PMNUM, host_pmnum); ++ } ++ /* Check PMBITS */ ++ int guest_pmbits = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMBITS); ++ int host_pmbits = FIELD_EX32(val, CPUCFG6, PMBITS); ++ if (guest_pmbits != host_pmbits) { ++ warn_report("The host not support PMBITS %d\n", guest_pmbits); ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, ++ PMBITS, host_pmbits); ++ } ++ } ++ } ++ ++ return ret; ++} ++ + static int kvm_loongarch_put_cpucfg(CPUState *cs) + { + int i, ret = 0; +@@ -586,7 +633,13 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs) + if (ret) { + return ret; + } +- } ++ } ++ if (i == 6) { ++ ret = kvm_check_cpucfg6(cs); ++ if (ret) { ++ return ret; ++ } ++ } + val = env->cpucfg[i]; + ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val); + if (ret < 0) { +diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c +index 645672ff59..2612f43de9 100644 +--- a/target/loongarch/loongarch-qmp-cmds.c ++++ b/target/loongarch/loongarch-qmp-cmds.c +@@ -42,7 +42,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) + } + + static const char *cpu_model_advertised_features[] = { +- "lsx", "lasx", NULL ++ "lsx", "lasx", "pmu", "pmnum", NULL + }; + + CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, +-- +2.33.0 + diff --git a/target-loongarch-kvm-Add-pv-steal-time-support.patch b/target-loongarch-kvm-Add-pv-steal-time-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..19fbcad65ec05a5ea70e7df913889faccff344fa --- /dev/null +++ b/target-loongarch-kvm-Add-pv-steal-time-support.patch @@ -0,0 +1,169 @@ +From 8b69a1b340da95cacdff252927ca8aef9d43c33a Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Wed, 24 Apr 2024 16:06:33 +0800 +Subject: [PATCH] target/loongarch/kvm: Add pv steal time support + +Signed-off-by: Song Gao +--- + linux-headers/asm-loongarch/kvm.h | 2 ++ + target/loongarch/cpu.h | 3 ++ + target/loongarch/kvm/kvm.c | 50 ++++++++++++++++++++++++++++ + target/loongarch/kvm/kvm_loongarch.h | 2 ++ + target/loongarch/machine.c | 25 ++++++++++++++ + 5 files changed, 82 insertions(+) + +diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h +index 4cec8c1601..81fec85f0a 100644 +--- a/linux-headers/asm-loongarch/kvm.h ++++ b/linux-headers/asm-loongarch/kvm.h +@@ -84,6 +84,8 @@ struct kvm_fpu { + #define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG) + #define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG) + #define KVM_LOONGARCH_VCPU_CPUCFG 0 ++#define KVM_LOONGARCH_VCPU_PVTIME_CTRL 1 ++#define KVM_LOONGARCH_VCPU_PVTIME_GPA 0 + + struct kvm_debug_exit_arch { + }; +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 80cad24fa1..0ed24051af 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -365,6 +365,9 @@ typedef struct CPUArchState { + /* Store ipistate to access from this struct */ + DeviceState *ipistate; + #endif ++ struct { ++ uint64_t guest_addr; ++ } st; + } CPULoongArchState; + + /** +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 5dda631b2b..e1d521a1de 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -649,6 +649,56 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs) + return ret; + } + ++int kvm_loongarch_put_pvtime(LoongArchCPU *cpu) ++{ ++ CPULoongArchState *env = &cpu->env; ++ int err; ++ struct kvm_device_attr attr = { ++ .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, ++ .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, ++ .addr = (uint64_t)&env->st.guest_addr, ++ }; ++ ++ err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr); ++ if (err != 0) { ++ /* It's ok even though kvm has not such attr */ ++ return 0; ++ } ++ ++ err = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_DEVICE_ATTR, attr); ++ if (err != 0) { ++ error_report("PVTIME IPA: KVM_SET_DEVICE_ATTR: %s", strerror(-err)); ++ return err; ++ } ++ ++ return 0; ++} ++ ++int kvm_loongarch_get_pvtime(LoongArchCPU *cpu) ++{ ++ CPULoongArchState *env = &cpu->env; ++ int err; ++ struct kvm_device_attr attr = { ++ .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, ++ .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, ++ .addr = (uint64_t)&env->st.guest_addr, ++ }; ++ ++ err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr); ++ if (err != 0) { ++ /* It's ok even though kvm has not such attr */ ++ return 0; ++ } ++ ++ err = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_DEVICE_ATTR, attr); ++ if (err != 0) { ++ error_report("PVTIME IPA: KVM_GET_DEVICE_ATTR: %s", strerror(-err)); ++ return err; ++ } ++ ++ return 0; ++} ++ + int kvm_arch_get_registers(CPUState *cs) + { + int ret; +diff --git a/target/loongarch/kvm/kvm_loongarch.h b/target/loongarch/kvm/kvm_loongarch.h +index d945b6bb82..551878a725 100644 +--- a/target/loongarch/kvm/kvm_loongarch.h ++++ b/target/loongarch/kvm/kvm_loongarch.h +@@ -12,5 +12,7 @@ + + int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level); + void kvm_arch_reset_vcpu(CPULoongArchState *env); ++int kvm_loongarch_put_pvtime(LoongArchCPU *cpu); ++int kvm_loongarch_get_pvtime(LoongArchCPU *cpu); + + #endif +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index 4443caed2d..ec5abe56db 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -9,6 +9,8 @@ + #include "cpu.h" + #include "migration/cpu.h" + #include "vec.h" ++#include "kvm/kvm_loongarch.h" ++#include "sysemu/kvm.h" + + static const VMStateDescription vmstate_fpu_reg = { + .name = "fpu_reg", +@@ -122,15 +124,38 @@ const VMStateDescription vmstate_tlb = { + } + }; + ++static int cpu_post_load(void *opaque, int version_id) ++{ ++#ifdef CONFIG_KVM ++ LoongArchCPU *cpu = opaque; ++ kvm_loongarch_put_pvtime(cpu); ++#endif ++ return 0; ++} ++ ++static int cpu_pre_save(void *opaque) ++{ ++#ifdef CONFIG_KVM ++ LoongArchCPU *cpu = opaque; ++ kvm_loongarch_get_pvtime(cpu); ++#endif ++ return 0; ++} ++ + /* LoongArch CPU state */ + const VMStateDescription vmstate_loongarch_cpu = { + .name = "cpu", + .version_id = 1, + .minimum_version_id = 1, ++ .post_load = cpu_post_load, ++ .pre_save = cpu_pre_save, + .fields = (VMStateField[]) { + VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32), + VMSTATE_UINTTL(env.pc, LoongArchCPU), + ++ /* PV time */ ++ VMSTATE_UINT64(env.st.guest_addr, LoongArchCPU), ++ + /* Remaining CSRs */ + VMSTATE_UINT64(env.CSR_CRMD, LoongArchCPU), + VMSTATE_UINT64(env.CSR_PRMD, LoongArchCPU), +-- +2.33.0 + diff --git a/target-loongarch-kvm-Add-software-breakpoint-support.patch b/target-loongarch-kvm-Add-software-breakpoint-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..d3981d62e76171605008311379cfa6929f1b221e --- /dev/null +++ b/target-loongarch-kvm-Add-software-breakpoint-support.patch @@ -0,0 +1,132 @@ +From 6a301af275fd684c197cf7a2e73fc265993478da Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 18 Feb 2024 15:00:25 +0800 +Subject: [PATCH] target/loongarch/kvm: Add software breakpoint support + +With KVM virtualization, debug exception is passthrough to +to guest kernel rather than host mode. Here hypercall +instruction with special hypercall code is used for sw +breakpoint usage. + +Now only software breakpoint is supported, and itt is allowed +to insert/remove software breakpoint. Later hardware breakpoint +will be added. + +Signed-off-by: Bibo Mao +--- + target/loongarch/kvm/kvm.c | 77 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 77 insertions(+) + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index c19978a970..49d02076ad 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -29,6 +29,7 @@ + #include "trace.h" + + static bool cap_has_mp_state; ++static unsigned int brk_insn; + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO + }; +@@ -675,7 +676,14 @@ static void kvm_loongarch_vm_stage_change(void *opaque, bool running, + + int kvm_arch_init_vcpu(CPUState *cs) + { ++ uint64_t val; ++ + qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs); ++ ++ if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) { ++ brk_insn = val; ++ } ++ + return 0; + } + +@@ -755,6 +763,68 @@ bool kvm_arch_cpu_check_are_resettable(void) + return true; + } + ++ ++void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) ++{ ++ if (kvm_sw_breakpoints_active(cpu)) { ++ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; ++ } ++} ++ ++int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) ++{ ++ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || ++ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) { ++ error_report("%s failed", __func__); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) ++{ ++ static uint32_t brk; ++ ++ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) || ++ brk != brk_insn || ++ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) { ++ error_report("%s failed", __func__); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) ++{ ++ return -ENOSYS; ++} ++ ++int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) ++{ ++ return -ENOSYS; ++} ++ ++void kvm_arch_remove_all_hw_breakpoints(void) ++{ ++} ++ ++static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(cs); ++ CPULoongArchState *env = &cpu->env; ++ ++ kvm_cpu_synchronize_state(cs); ++ if (cs->singlestep_enabled) { ++ return true; ++ } ++ ++ if (kvm_find_sw_breakpoint(cs, env->pc)) { ++ return true; ++ } ++ ++ return false; ++} ++ + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + { + int ret = 0; +@@ -774,6 +844,13 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + run->iocsr_io.len, + run->iocsr_io.is_write); + break; ++ ++ case KVM_EXIT_DEBUG: ++ if (kvm_loongarch_handle_debug(cs, run)) { ++ ret = EXCP_DEBUG; ++ } ++ break; ++ + default: + ret = -1; + warn_report("KVM: unknown exit reason %d", run->exit_reason); +-- +2.33.0 + diff --git a/target-loongarch-kvm-Fix-vm-restore-failed.patch b/target-loongarch-kvm-Fix-vm-restore-failed.patch new file mode 100644 index 0000000000000000000000000000000000000000..36cd4cb417fdbc3a62e618574e79800ba5fda743 --- /dev/null +++ b/target-loongarch-kvm-Fix-vm-restore-failed.patch @@ -0,0 +1,28 @@ +From 7cf9ed3844ed3340165121e5fd7dcb959ee80d15 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Wed, 24 Apr 2024 14:18:46 +0800 +Subject: [PATCH] target/loongarch/kvm: Fix vm restore failed + +The vmstate_loongarch_cpu need kvm_state_counter. + +Signed-off-by: Song Gao +--- + target/loongarch/machine.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index 1c4e01d076..4443caed2d 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -191,6 +191,8 @@ const VMStateDescription vmstate_loongarch_cpu = { + VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, + 0, vmstate_tlb, LoongArchTLB), + ++ VMSTATE_UINT64(kvm_state_counter, LoongArchCPU), ++ + VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { +-- +2.33.0 + diff --git a/target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch b/target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch new file mode 100644 index 0000000000000000000000000000000000000000..cdd2e4957e54ddfa954cae7818eae2e85f11a7e7 --- /dev/null +++ b/target-loongarch-kvm-fpu-save-the-vreg-registers-hig.patch @@ -0,0 +1,43 @@ +From 7a3573ce009afa271168829da86e2c70c63fa58a Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Tue, 14 May 2024 19:07:52 +0800 +Subject: [PATCH] target/loongarch/kvm: fpu save the vreg registers high + 192bit + +On kvm side, get_fpu/set_fpu save the vreg registers high 192bits, +but QEMU missing. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240514110752.989572-1-gaosong@loongson.cn> +--- + target/loongarch/kvm/kvm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index e1d521a1de..5c88270132 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -444,6 +444,9 @@ static int kvm_loongarch_get_regs_fp(CPUState *cs) + env->fcsr0 = fpu.fcsr; + for (i = 0; i < 32; i++) { + env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0]; ++ env->fpr[i].vreg.UD[1] = fpu.fpr[i].val64[1]; ++ env->fpr[i].vreg.UD[2] = fpu.fpr[i].val64[2]; ++ env->fpr[i].vreg.UD[3] = fpu.fpr[i].val64[3]; + } + for (i = 0; i < 8; i++) { + env->cf[i] = fpu.fcc & 0xFF; +@@ -465,6 +468,9 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs) + fpu.fcc = 0; + for (i = 0; i < 32; i++) { + fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0]; ++ fpu.fpr[i].val64[1] = env->fpr[i].vreg.UD[1]; ++ fpu.fpr[i].val64[2] = env->fpr[i].vreg.UD[2]; ++ fpu.fpr[i].val64[3] = env->fpr[i].vreg.UD[3]; + } + + for (i = 0; i < 8; i++) { +-- +2.33.0 + diff --git a/target-loongarch-kvm-sync-kernel-header-files.patch b/target-loongarch-kvm-sync-kernel-header-files.patch new file mode 100644 index 0000000000000000000000000000000000000000..4d621d7f30f2a0d6296992b697b390f8b67fb82c --- /dev/null +++ b/target-loongarch-kvm-sync-kernel-header-files.patch @@ -0,0 +1,41 @@ +From b7e49ac3b4e7dbfc9ba4645a85962294883c251a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 13 Mar 2024 10:04:33 +0800 +Subject: [PATCH] target/loongarch/kvm: sync kernel header files + +sync kernel header files. + +Signed-off-by: Bibo Mao +--- + linux-headers/asm-loongarch/kvm.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h +index 923d0bd382..4cec8c1601 100644 +--- a/linux-headers/asm-loongarch/kvm.h ++++ b/linux-headers/asm-loongarch/kvm.h +@@ -15,10 +15,12 @@ + */ + + #define __KVM_HAVE_READONLY_MEM ++#define __KVM_HAVE_GUEST_DEBUG + + #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 + #define KVM_DIRTY_LOG_PAGE_OFFSET 64 + ++#define KVM_GUESTDBG_USE_SW_BP 0x00010000 + /* + * for KVM_GET_REGS and KVM_SET_REGS + */ +@@ -74,6 +76,8 @@ struct kvm_fpu { + + #define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 1) + #define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 2) ++/* Debugging: Special instruction for software breakpoint */ ++#define KVM_REG_LOONGARCH_DEBUG_INST (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3) + + #define LOONGARCH_REG_SHIFT 3 + #define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT)) +-- +2.33.0 +