From a32af0ef2b3671fa428d1cfc168d4534879e6a2b Mon Sep 17 00:00:00 2001 From: Jacob Wang Date: Wed, 25 Sep 2024 15:47:41 +0800 Subject: [PATCH] update to qemu-kvm-6.2.0-53.src.rpm Signed-off-by: Jacob Wang --- 0001-Add-Acpi-support.patch | 1348 -- 0001-anolis-csv-i386-add-CSV-context.patch | 205 - 0002-Support-rtc.patch | 370 - ...add-command-to-initialize-CSV-contex.patch | 204 - 0003-Add-loongarch-machine.patch | 5752 ------ ...add-command-to-load-data-to-guest-me.patch | 164 - 0004-Add-target-loongarch64.patch | 15917 ---------------- ...add-command-to-load-vmcb-to-guest-me.patch | 107 - 0005-Add-linux-headers-and-linux-user.patch | 1663 -- ...populate-CPUID-0x8000_001F-when-CSV-.patch | 41 - 0006-Add-disas-gdb.patch | 3183 --- ...CSV-guest-do-not-need-register-unreg.patch | 35 - 0007-Modify-kvm-cpu-vga-qapi.patch | 477 - ...86-csv-load-initial-image-to-private.patch | 44 - 0008-Modify-compile-script.patch | 36 - ...-vga-force-full-update-for-CSV-guest.patch | 47 - 0009-Add-loongarch64-rh-devices.mak.patch | 3227 ---- ...D-SEV-to-include-Live-migration-flow.patch | 69 - ...dd-AMD-SEV-specific-migration-parame.patch | 253 - ...st-support-introduce-ConfidentialGue.patch | 67 - ...provide-callback-to-setup-outgoing-c.patch | 135 - ...do-not-create-launch-context-for-an-.patch | 48 - ...add-support-to-encrypt-the-outgoing-.patch | 324 - ...add-support-to-load-incoming-encrypt.patch | 224 - ...for-SEV-shared-regions-list-and-KVM_.patch | 293 - ...pport-to-migrate-shared-regions-list.patch | 103 - ...-add-support-to-send-encrypted-pages.patch | 338 - ...rce-encrypted-status-for-flash0-flas.patch | 44 - ...V-live-migration-bump-downtime-limit.patch | 64 - ...86-kvm-Add-support-for-MSR-filtering.patch | 201 - ...for-userspace-MSR-filtering-and-hand.patch | 118 - ...-ram-Force-encrypted-status-for-VGA-.patch | 33 - ...86-sev-Clear-shared_regions_list-whe.patch | 58 - ...-ram-Fix-calculation-of-gfn-correpon.patch | 57 - ...86-csv-Move-is_hygon_cpu-to-header-f.patch | 85 - ...86-csv-Read-cert-chain-from-file-whe.patch | 131 - ...86-csv-add-support-to-queue-the-outg.patch | 270 - ...86-csv-add-support-to-encrypt-the-ou.patch | 204 - ...86-csv-add-support-to-queue-the-inco.patch | 171 - ...86-csv-add-support-to-load-incoming-.patch | 108 - ...-ram-Accelerate-the-transmission-of-.patch | 229 - ...-ram-Accelerate-the-loading-of-CSV-g.patch | 37 - ...86-csv-Add-support-for-migrate-VMSA-.patch | 416 - ...rget-i386-get-set-migrate-GHCB-state.patch | 175 - ...86-kvm-Return-resettable-when-emulat.patch | 39 - ...olis-kvm-Add-support-for-CSV2-reboot.patch | 170 - ...-map-shared-region-for-CSV-virtual-m.patch | 384 - ...ders-update-kernel-headers-to-includ.patch | 79 - ...add-support-to-migrate-the-outgoing-.patch | 453 - ...add-support-to-migrate-the-incoming-.patch | 204 - ...add-support-to-migrate-the-outgoing-.patch | 137 - ...add-support-to-migrate-the-incoming-.patch | 109 - ...86-sev-Add-support-for-reuse-ASID-fo.patch | 192 - 1074-newfeature-support-vpsp.patch | 190 - ...t-i386-Add-Hygon-Dhyana-v3-CPU-model.patch | 43 - ...-i386-Add-new-Hygon-Dharma-CPU-model.patch | 133 - 1077-target-i386-add-FSRM-to-TCG.patch | 35 - 1078-target-i386-add-FZRM-FSRS-FSRC.patch | 67 - ...386-Add-new-CPU-model-SapphireRapids.patch | 226 - ...support-for-CMPCCXADD-in-CPUID-enume.patch | 59 - ...support-for-AMX-FP16-in-CPUID-enumer.patch | 60 - ...support-for-AVX-IFMA-in-CPUID-enumer.patch | 58 - ...support-for-AVX-VNNI-INT8-in-CPUID-e.patch | 108 - ...support-for-AVX-NE-CONVERT-in-CPUID-.patch | 59 - ...support-for-PREFETCHIT0-1-in-CPUID-e.patch | 58 - ...st-feature-level-according-to-FEAT_7.patch | 43 - ...new-bit-definitions-of-MSR_IA32_ARCH.patch | 40 - ...support-for-MCDT_NO-in-CPUID-enumera.patch | 110 - ...i386-Add-new-CPU-model-GraniteRapids.patch | 181 - ...support-for-AMX-COMPLEX-in-CPUID-enu.patch | 57 - ...-i386-Add-new-CPU-model-SierraForest.patch | 207 - ...arget-i386-Export-RFDS-bit-to-guests.patch | 45 - ...few-security-fix-bits-in-ARCH_CAPABI.patch | 50 - ...oduce-SapphireRapids-v3-to-add-missi.patch | 45 - ...recated-bpf_program__set_socket_filt.patch | 37 - ...rt-MSR_ARCH_CAPABILITIES-bits-to-gue.patch | 45 - 81-kvm-anolis.rules => 81-kvm-rhel.rules | 0 Add-lbt-support-for-kvm.patch | 154 - ...to-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch | 28 - Add-usb-storage-config-for-loongarch.patch | 26 - Fix-LoongArch-KVM-header-macros.patch | 32 - ...cture-macro-of-LoongArch-to-HOST_LOO.patch | 27 - ...and-fpu-option-to-compat-with-kernel.patch | 31 - Fix-smp.cores-value.patch | 35 - ...-where-qemu-specifies-the-boot-order.patch | 140 - ...tion-lack-and-Modify-the-maximum-num.patch | 44 - Modify-the-ioctl-command-of-kvm.patch | 32 - Support-TPM.patch | 518 - Support-vfio-config.patch | 47 - ...pace-code-cleanup-on-7A-virt-machine.patch | 276 - code-cleanup-for-loongarch-kvm.patch | 34 - fix-smbios-type4-info-for-numa-support.patch | 44 - fixup-can-t-find-cpu-type.patch | 34 - kvm-csr-save-and-restore-optimization.patch | 599 - kvm-iotests-test-NBD-TLS-iothread.patch | 277 + ...024-7409-Avoid-use-after-free-when-c.patch | 101 + ...-qemu_aio_context-over-iohandler-con.patch | 161 + ...iofsd-Adjust-limit-for-minor-version.patch | 41 - loongarch_bios.bin | Bin 4190208 -> 0 bytes loongarch_vars.bin | Bin 389120 -> 0 bytes pass-to-make-check.patch | 164 - qemu-kvm.spec | 249 +- rename-kvm_msr_buf-with-kvm_csr_buf.patch | 638 - 103 files changed, 559 insertions(+), 43971 deletions(-) delete mode 100644 0001-Add-Acpi-support.patch delete mode 100644 0001-anolis-csv-i386-add-CSV-context.patch delete mode 100644 0002-Support-rtc.patch delete mode 100644 0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch delete mode 100644 0003-Add-loongarch-machine.patch delete mode 100644 0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch delete mode 100644 0004-Add-target-loongarch64.patch delete mode 100644 0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch delete mode 100644 0005-Add-linux-headers-and-linux-user.patch delete mode 100644 0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch delete mode 100644 0006-Add-disas-gdb.patch delete mode 100644 0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch delete mode 100644 0007-Modify-kvm-cpu-vga-qapi.patch delete mode 100644 0007-anolis-target-i386-csv-load-initial-image-to-private.patch delete mode 100644 0008-Modify-compile-script.patch delete mode 100644 0008-anolis-vga-force-full-update-for-CSV-guest.patch delete mode 100644 0009-Add-loongarch64-rh-devices.mak.patch delete mode 100644 1038-doc-update-AMD-SEV-to-include-Live-migration-flow.patch delete mode 100644 1039-migration.json-add-AMD-SEV-specific-migration-parame.patch delete mode 100644 1040-confidential-guest-support-introduce-ConfidentialGue.patch delete mode 100644 1041-target-i386-sev-provide-callback-to-setup-outgoing-c.patch delete mode 100644 1042-target-i386-sev-do-not-create-launch-context-for-an-.patch delete mode 100644 1043-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch delete mode 100644 1044-target-i386-sev-add-support-to-load-incoming-encrypt.patch delete mode 100644 1045-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch delete mode 100644 1046-migration-add-support-to-migrate-shared-regions-list.patch delete mode 100644 1047-migration-ram-add-support-to-send-encrypted-pages.patch delete mode 100644 1048-migration-ram-Force-encrypted-status-for-flash0-flas.patch delete mode 100644 1049-migration-for-SEV-live-migration-bump-downtime-limit.patch delete mode 100644 1050-i386-kvm-Add-support-for-MSR-filtering.patch delete mode 100644 1051-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch delete mode 100644 1052-anolis-migration-ram-Force-encrypted-status-for-VGA-.patch delete mode 100644 1053-anolis-target-i386-sev-Clear-shared_regions_list-whe.patch delete mode 100644 1054-anolis-migration-ram-Fix-calculation-of-gfn-correpon.patch delete mode 100644 1055-anolis-target-i386-csv-Move-is_hygon_cpu-to-header-f.patch delete mode 100644 1056-anolis-target-i386-csv-Read-cert-chain-from-file-whe.patch delete mode 100644 1057-anolis-target-i386-csv-add-support-to-queue-the-outg.patch delete mode 100644 1058-anolis-target-i386-csv-add-support-to-encrypt-the-ou.patch delete mode 100644 1059-anolis-target-i386-csv-add-support-to-queue-the-inco.patch delete mode 100644 1060-anolis-target-i386-csv-add-support-to-load-incoming-.patch delete mode 100644 1061-anolis-migration-ram-Accelerate-the-transmission-of-.patch delete mode 100644 1062-anolis-migration-ram-Accelerate-the-loading-of-CSV-g.patch delete mode 100644 1063-anolis-target-i386-csv-Add-support-for-migrate-VMSA-.patch delete mode 100644 1064-anolis-target-i386-get-set-migrate-GHCB-state.patch delete mode 100644 1065-anolis-target-i386-kvm-Return-resettable-when-emulat.patch delete mode 100644 1066-anolis-kvm-Add-support-for-CSV2-reboot.patch delete mode 100644 1067-anolis-vfio-only-map-shared-region-for-CSV-virtual-m.patch delete mode 100644 1068-anolis-linux-headers-update-kernel-headers-to-includ.patch delete mode 100644 1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch delete mode 100644 1070-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch delete mode 100644 1071-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch delete mode 100644 1072-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch delete mode 100644 1073-anolis-target-i386-sev-Add-support-for-reuse-ASID-fo.patch delete mode 100644 1074-newfeature-support-vpsp.patch delete mode 100644 1075-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch delete mode 100644 1076-target-i386-Add-new-Hygon-Dharma-CPU-model.patch delete mode 100644 1077-target-i386-add-FSRM-to-TCG.patch delete mode 100644 1078-target-i386-add-FZRM-FSRS-FSRC.patch delete mode 100644 1079-i386-Add-new-CPU-model-SapphireRapids.patch delete mode 100644 1080-target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch delete mode 100644 1081-target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch delete mode 100644 1082-target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch delete mode 100644 1083-target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch delete mode 100644 1084-target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch delete mode 100644 1085-target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch delete mode 100644 1086-target-i386-Adjust-feature-level-according-to-FEAT_7.patch delete mode 100644 1087-target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch delete mode 100644 1088-target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch delete mode 100644 1089-target-i386-Add-new-CPU-model-GraniteRapids.patch delete mode 100644 1090-target-i386-Add-support-for-AMX-COMPLEX-in-CPUID-enu.patch delete mode 100644 1091-target-i386-Add-new-CPU-model-SierraForest.patch delete mode 100644 1092-target-i386-Export-RFDS-bit-to-guests.patch delete mode 100644 1093-target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch delete mode 100644 1094-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch delete mode 100644 1095-ebpf-replace-deprecated-bpf_program__set_socket_filt.patch delete mode 100644 1096-target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch rename 81-kvm-anolis.rules => 81-kvm-rhel.rules (100%) delete mode 100644 Add-lbt-support-for-kvm.patch delete mode 100644 Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch delete mode 100644 Add-usb-storage-config-for-loongarch.patch delete mode 100644 Fix-LoongArch-KVM-header-macros.patch delete mode 100644 Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch delete mode 100644 Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch delete mode 100644 Fix-smp.cores-value.patch delete mode 100644 Fixed-the-issue-where-qemu-specifies-the-boot-order.patch delete mode 100644 Modify-smbios-option-lack-and-Modify-the-maximum-num.patch delete mode 100644 Modify-the-ioctl-command-of-kvm.patch delete mode 100644 Support-TPM.patch delete mode 100644 Support-vfio-config.patch delete mode 100644 address-space-code-cleanup-on-7A-virt-machine.patch delete mode 100644 code-cleanup-for-loongarch-kvm.patch delete mode 100644 fix-smbios-type4-info-for-numa-support.patch delete mode 100644 fixup-can-t-find-cpu-type.patch delete mode 100644 kvm-csr-save-and-restore-optimization.patch create mode 100644 kvm-iotests-test-NBD-TLS-iothread.patch create mode 100644 kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch create mode 100644 kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch delete mode 100644 kvm-virtiofsd-Adjust-limit-for-minor-version.patch delete mode 100644 loongarch_bios.bin delete mode 100644 loongarch_vars.bin delete mode 100644 pass-to-make-check.patch delete mode 100644 rename-kvm_msr_buf-with-kvm_csr_buf.patch diff --git a/0001-Add-Acpi-support.patch b/0001-Add-Acpi-support.patch deleted file mode 100644 index 101c3a4..0000000 --- a/0001-Add-Acpi-support.patch +++ /dev/null @@ -1,1348 +0,0 @@ -From 935f85c0025bbaaed976940ed0d57c23bfc68f94 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:11:23 -0400 -Subject: [PATCH 01/28] Add Acpi support. - -Change-Id: I208228b2178cddf365e97c6faf6111ef40e795eb -Signed-off-by: lixianglai ---- - hw/acpi/Kconfig | 8 + - hw/acpi/larch_7a.c | 600 +++++++++++++++++++++++++++++++++++++++++ - hw/acpi/ls7a.c | 598 ++++++++++++++++++++++++++++++++++++++++ - hw/acpi/meson.build | 1 + - include/hw/acpi/ls7a.h | 80 ++++++ - 5 files changed, 1287 insertions(+) - create mode 100644 hw/acpi/larch_7a.c - create mode 100644 hw/acpi/ls7a.c - create mode 100644 include/hw/acpi/ls7a.h - -diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig -index 622b0b50b..2f2fb33a7 100644 ---- a/hw/acpi/Kconfig -+++ b/hw/acpi/Kconfig -@@ -15,6 +15,14 @@ config ACPI_X86_ICH - bool - select ACPI_X86 - -+config ACPI_LOONGARCH -+ bool -+ select ACPI -+ select ACPI_CPU_HOTPLUG -+ select ACPI_MEMORY_HOTPLUG -+ select ACPI_PIIX4 -+ select ACPI_PCIHP -+ - config ACPI_CPU_HOTPLUG - bool - -diff --git a/hw/acpi/larch_7a.c b/hw/acpi/larch_7a.c -new file mode 100644 -index 000000000..35d4a7526 ---- /dev/null -+++ b/hw/acpi/larch_7a.c -@@ -0,0 +1,600 @@ -+#include "qemu/osdep.h" -+#include "sysemu/sysemu.h" -+#include "sysemu/runstate.h" -+#include "sysemu/reset.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/ls7a.h" -+#include "hw/nvram/fw_cfg.h" -+#include "qemu/config-file.h" -+#include "qapi/opts-visitor.h" -+#include "qapi/qapi-events-run-state.h" -+#include "qapi/error.h" -+#include "hw/loongarch/ls7a.h" -+#include "hw/mem/pc-dimm.h" -+#include "hw/mem/nvdimm.h" -+#include "migration/vmstate.h" -+ -+static void ls7a_pm_update_sci_fn(ACPIREGS *regs) -+{ -+ LS7APCIPMRegs *pm = container_of(regs, LS7APCIPMRegs, acpi_regs); -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static uint64_t ls7a_gpe_readb(void *opaque, hwaddr addr, unsigned width) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ return acpi_gpe_ioport_readb(&pm->acpi_regs, addr); -+} -+ -+static void ls7a_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static const MemoryRegionOps ls7a_gpe_ops = { -+ .read = ls7a_gpe_readb, -+ .write = ls7a_gpe_writeb, -+ .valid.min_access_size = 1, -+ .valid.max_access_size = 8, -+ .impl.min_access_size = 1, -+ .impl.max_access_size = 1, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+#define VMSTATE_GPE_ARRAY(_field, _state) \ -+ { \ -+ .name = (stringify(_field)), \ -+ .version_id = 0, \ -+ .num = ACPI_GPE0_LEN, \ -+ .info = &vmstate_info_uint8, \ -+ .size = sizeof(uint8_t), \ -+ .flags = VMS_ARRAY | VMS_POINTER, \ -+ .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ -+ } -+ -+static uint64_t ls7a_reset_readw(void *opaque, hwaddr addr, unsigned width) -+{ -+ return 0; -+} -+ -+static void ls7a_reset_writew(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ if (val & 1) { -+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); -+ return; -+ } -+} -+ -+static const MemoryRegionOps ls7a_reset_ops = { -+ .read = ls7a_reset_readw, -+ .write = ls7a_reset_writew, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static bool vmstate_test_use_memhp(void *opaque) -+{ -+ LS7APCIPMRegs *s = opaque; -+ return s->acpi_memory_hotplug.is_enabled; -+} -+ -+static const VMStateDescription vmstate_memhp_state = { -+ .name = "ls7a_pm/memhp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .needed = vmstate_test_use_memhp, -+ .fields = (VMStateField[]) { -+ VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const VMStateDescription vmstate_cpuhp_state = { -+ .name = "ls7a_pm/cpuhp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_CPU_HOTPLUG(cpuhp_state, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+const VMStateDescription vmstate_ls7a_pm = { -+ .name = "ls7a_pm", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT16(acpi_regs.pm1.evt.sts, LS7APCIPMRegs), -+ VMSTATE_UINT16(acpi_regs.pm1.evt.en, LS7APCIPMRegs), -+ VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, LS7APCIPMRegs), -+ VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, LS7APCIPMRegs), -+ VMSTATE_INT64(acpi_regs.tmr.overflow_time, LS7APCIPMRegs), -+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, LS7APCIPMRegs), -+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ }, -+ .subsections = (const VMStateDescription * []) { -+ &vmstate_memhp_state, -+ &vmstate_cpuhp_state, -+ NULL -+ } -+}; -+ -+static inline int64_t acpi_pm_tmr_get_clock(void) -+{ -+ return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY, -+ NANOSECONDS_PER_SECOND); -+} -+ -+static uint32_t acpi_pm_tmr_get(ACPIREGS *ar) -+{ -+ uint32_t d = acpi_pm_tmr_get_clock(); -+ return d & 0xffffff; -+} -+ -+static void acpi_pm_tmr_timer(void *opaque) -+{ -+ ACPIREGS *ar = opaque; -+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL); -+ ar->tmr.update_sci(ar); -+} -+ -+static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ return acpi_pm_tmr_get(opaque); -+} -+ -+static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ /* nothing */ -+} -+ -+static const MemoryRegionOps acpi_pm_tmr_ops = { -+ .read = acpi_pm_tmr_read, -+ .write = acpi_pm_tmr_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void ls7a_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, -+ MemoryRegion *parent, uint64_t offset) -+{ -+ ar->tmr.update_sci = update_sci; -+ ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar); -+ memory_region_init_io(&ar->tmr.io, memory_region_owner(parent), -+ &acpi_pm_tmr_ops, ar, "acpi-tmr", 4); -+ memory_region_add_subregion(parent, offset, &ar->tmr.io); -+} -+ -+static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) -+{ -+ uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar); -+ if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { -+ /* if TMRSTS is reset, then compute the new overflow time */ -+ acpi_pm_tmr_calc_overflow_time(ar); -+ } -+ ar->pm1.evt.sts &= ~val; -+} -+ -+static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ switch (addr) { -+ case 0: -+ return acpi_pm1_evt_get_sts(ar); -+ case 4: -+ return ar->pm1.evt.en; -+ default: -+ return 0; -+ } -+} -+ -+static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) -+{ -+ ar->pm1.evt.en = val; -+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, -+ val & ACPI_BITMASK_RT_CLOCK_ENABLE); -+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, -+ val & ACPI_BITMASK_TIMER_ENABLE); -+} -+ -+static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ switch (addr) { -+ case 0: -+ acpi_pm1_evt_write_sts(ar, val); -+ ar->pm1.evt.update_sci(ar); -+ break; -+ case 4: -+ acpi_pm1_evt_write_en(ar, val); -+ ar->pm1.evt.update_sci(ar); -+ break; -+ } -+} -+ -+static const MemoryRegionOps acpi_pm_evt_ops = { -+ .read = acpi_pm_evt_read, -+ .write = acpi_pm_evt_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void ls7a_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, -+ MemoryRegion *parent, uint64_t offset) -+{ -+ ar->pm1.evt.update_sci = update_sci; -+ memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent), -+ &acpi_pm_evt_ops, ar, "acpi-evt", 8); -+ memory_region_add_subregion(parent, offset, &ar->pm1.evt.io); -+} -+ -+static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ return ar->pm1.cnt.cnt; -+} -+ -+/* ACPI PM1aCNT */ -+static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) -+{ -+ ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); -+ if (val & ACPI_BITMASK_SLEEP_ENABLE) { -+ /* change suspend type */ -+ uint16_t sus_typ = (val >> 10) & 7; -+ switch (sus_typ) { -+ /* s3,s4 not support */ -+ case 5: -+ case 6: -+ warn_report("acpi s3,s4 state not support"); -+ break; -+ /* s5: soft off */ -+ case 7: -+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); -+ break; -+ default: -+ break; -+ } -+ } -+} -+ -+static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ acpi_pm1_cnt_write(opaque, val); -+} -+ -+static const MemoryRegionOps acpi_pm_cnt_ops = { -+ .read = acpi_pm_cnt_read, -+ .write = acpi_pm_cnt_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void acpi_notify_wakeup(Notifier *notifier, void *data) -+{ -+ ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup); -+ WakeupReason *reason = data; -+ -+ switch (*reason) { -+ case QEMU_WAKEUP_REASON_RTC: -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS); -+ break; -+ case QEMU_WAKEUP_REASON_PMTIMER: -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS); -+ break; -+ case QEMU_WAKEUP_REASON_OTHER: -+ /* ACPI_BITMASK_WAKE_STATUS should be set on resume. -+ * Pretend that resume was caused by power button */ -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void ls7a_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, -+ bool disable_s3, bool disable_s4, uint8_t s4_val, uint64_t offset) -+{ -+ FWCfgState *fw_cfg; -+ -+ ar->pm1.cnt.s4_val = s4_val; -+ ar->wakeup.notify = acpi_notify_wakeup; -+ qemu_register_wakeup_notifier(&ar->wakeup); -+ memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent), -+ &acpi_pm_cnt_ops, ar, "acpi-cnt", 4); -+ memory_region_add_subregion(parent, offset, &ar->pm1.cnt.io); -+ -+ fw_cfg = fw_cfg_find(); -+ if (fw_cfg) { -+ uint8_t suspend[6] = {128, 0, 0, 129, 128, 128}; -+ suspend[3] = 1 | ((!disable_s3) << 7); -+ suspend[4] = s4_val | ((!disable_s4) << 7); -+ fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6); -+ } -+} -+ -+static void ls7a_pm_reset(void *opaque) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ -+ acpi_pm1_evt_reset(&pm->acpi_regs); -+ acpi_pm1_cnt_reset(&pm->acpi_regs); -+ acpi_pm_tmr_reset(&pm->acpi_regs); -+ acpi_gpe_reset(&pm->acpi_regs); -+ -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static void pm_powerdown_req(Notifier *n, void *opaque) -+{ -+ LS7APCIPMRegs *pm = container_of(n, LS7APCIPMRegs, powerdown_notifier); -+ -+ acpi_pm1_evt_power_down(&pm->acpi_regs); -+} -+ -+void ls7a_pm_init(LS7APCIPMRegs *pm, qemu_irq *pic) -+{ -+ unsigned long base, gpe_len, acpi_aci_irq; -+ -+ /* ls7a board acpi hardware info, including -+ * acpi system io base address -+ * acpi gpe length -+ * acpi sci irq number -+ */ -+ base = ACPI_IO_BASE; -+ gpe_len = ACPI_GPE0_LEN; -+ acpi_aci_irq = ACPI_SCI_IRQ; -+ -+ pm->irq = pic[acpi_aci_irq - 64]; -+ memory_region_init(&pm->iomem, NULL, "ls7a_pm", ACPI_IO_SIZE); -+ memory_region_add_subregion(get_system_memory(), base, &pm->iomem); -+ -+ cpu_hotplug_hw_init(get_system_memory(), NULL, -+ &pm->cpuhp_state, CPU_HOTPLUG_BASE); -+ -+ ls7a_pm_tmr_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, LS7A_PM_TMR_BLK); -+ ls7a_pm1_evt_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, LS7A_PM_EVT_BLK); -+ ls7a_pm1_cnt_init(&pm->acpi_regs, &pm->iomem, false, false, 2, LS7A_PM_CNT_BLK); -+ -+ acpi_gpe_init(&pm->acpi_regs, gpe_len); -+ memory_region_init_io(&pm->iomem_gpe, NULL, &ls7a_gpe_ops, pm, -+ "acpi-gpe0", gpe_len); -+ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_STS_REG, &pm->iomem_gpe); -+ -+ memory_region_init_io(&pm->iomem_reset, NULL, &ls7a_reset_ops, pm, -+ "acpi-reset", 4); -+ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_RESET_REG, &pm->iomem_reset); -+ -+ qemu_register_reset(ls7a_pm_reset, pm); -+ -+ pm->powerdown_notifier.notify = pm_powerdown_req; -+ qemu_register_powerdown_notifier(&pm->powerdown_notifier); -+ -+ if (pm->acpi_memory_hotplug.is_enabled) { -+ acpi_memory_hotplug_init(get_system_memory(), NULL, -+ &pm->acpi_memory_hotplug, MEMORY_HOTPLUG_BASE); -+ } -+} -+ -+ -+static void ls7a_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ uint64_t value = ACPI_IO_BASE + LS7A_GPE0_STS_REG; -+ -+ visit_type_uint64(v, name, &value, errp); -+} -+ -+static bool ls7a_pm_get_memory_hotplug_support(Object *obj, Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ return ls7a->pm.acpi_memory_hotplug.is_enabled; -+} -+ -+static void ls7a_pm_set_memory_hotplug_support(Object *obj, bool value, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ ls7a->pm.acpi_memory_hotplug.is_enabled = value; -+} -+ -+static void ls7a_pm_get_disable_s3(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->disable_s3; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_disable_s3(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->disable_s3 = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void ls7a_pm_get_disable_s4(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->disable_s4; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_disable_s4(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->disable_s4 = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void ls7a_pm_get_s4_val(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->s4_val; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_s4_val(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->s4_val = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+void ls7a_pm_add_properties(Object *obj, LS7APCIPMRegs *pm, Error **errp) -+{ -+ static const uint32_t gpe0_len = ACPI_GPE0_LEN; -+ pm->acpi_memory_hotplug.is_enabled = true; -+ pm->disable_s3 = 0; -+ pm->disable_s4 = 0; -+ pm->s4_val = 2; -+ -+ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, -+ &pm->pm_io_base, OBJ_PROP_FLAG_READ); -+ object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", -+ ls7a_pm_get_gpe0_blk, -+ NULL, NULL, pm); -+ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, -+ &gpe0_len, OBJ_PROP_FLAG_READ); -+ object_property_add_bool(obj, "memory-hotplug-support", -+ ls7a_pm_get_memory_hotplug_support, -+ ls7a_pm_set_memory_hotplug_support); -+ object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8", -+ ls7a_pm_get_disable_s3, -+ ls7a_pm_set_disable_s3, -+ NULL, pm); -+ object_property_add(obj, ACPI_PM_PROP_S4_DISABLED, "uint8", -+ ls7a_pm_get_disable_s4, -+ ls7a_pm_set_disable_s4, -+ NULL, pm); -+ object_property_add(obj, ACPI_PM_PROP_S4_VAL, "uint8", -+ ls7a_pm_get_s4_val, -+ ls7a_pm_set_s4_val, -+ NULL, pm); -+} -+ -+void ls7a_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { -+ nvdimm_acpi_plug_cb(hotplug_dev, dev); -+ } else { -+ acpi_memory_plug_cb(hotplug_dev, &ls7a->pm.acpi_memory_hotplug, -+ dev, errp); -+ } -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_plug_cb(hotplug_dev, &ls7a->pm.cpuhp_state, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device plug request for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ acpi_memory_unplug_request_cb(hotplug_dev, -+ &ls7a->pm.acpi_memory_hotplug, dev, -+ errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_unplug_request_cb(hotplug_dev, &ls7a->pm.cpuhp_state, -+ dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug request for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ acpi_memory_unplug_cb(&ls7a->pm.acpi_memory_hotplug, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_unplug_cb(&ls7a->pm.cpuhp_state, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); -+ -+ acpi_memory_ospm_status(&ls7a->pm.acpi_memory_hotplug, list); -+ acpi_cpu_ospm_status(&ls7a->pm.cpuhp_state, list); -+} -+ -+void ls7a_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); -+ -+ acpi_send_gpe_event(&ls7a->pm.acpi_regs, ls7a->pm.irq, ev); -+} -+ -+ -+ -diff --git a/hw/acpi/ls7a.c b/hw/acpi/ls7a.c -new file mode 100644 -index 000000000..2de50ccb9 ---- /dev/null -+++ b/hw/acpi/ls7a.c -@@ -0,0 +1,598 @@ -+#include "qemu/osdep.h" -+#include "sysemu/sysemu.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/ls7a.h" -+#include "hw/nvram/fw_cfg.h" -+#include "qemu/config-file.h" -+#include "qapi/opts-visitor.h" -+#include "qapi/qapi-events-run-state.h" -+#include "qapi/error.h" -+#include "hw/mips/ls7a.h" -+#include "hw/mem/pc-dimm.h" -+#include "hw/mem/nvdimm.h" -+ -+static void ls7a_pm_update_sci_fn(ACPIREGS *regs) -+{ -+ LS7APCIPMRegs *pm = container_of(regs, LS7APCIPMRegs, acpi_regs); -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static uint64_t ls7a_gpe_readb(void *opaque, hwaddr addr, unsigned width) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ return acpi_gpe_ioport_readb(&pm->acpi_regs, addr); -+} -+ -+static void ls7a_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static const MemoryRegionOps ls7a_gpe_ops = { -+ .read = ls7a_gpe_readb, -+ .write = ls7a_gpe_writeb, -+ .valid.min_access_size = 1, -+ .valid.max_access_size = 8, -+ .impl.min_access_size = 1, -+ .impl.max_access_size = 1, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+#define VMSTATE_GPE_ARRAY(_field, _state) \ -+ { \ -+ .name = (stringify(_field)), \ -+ .version_id = 0, \ -+ .num = ACPI_GPE0_LEN, \ -+ .info = &vmstate_info_uint8, \ -+ .size = sizeof(uint8_t), \ -+ .flags = VMS_ARRAY | VMS_POINTER, \ -+ .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ -+ } -+ -+static uint64_t ls7a_reset_readw(void *opaque, hwaddr addr, unsigned width) -+{ -+ return 0; -+} -+ -+static void ls7a_reset_writew(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ if (val & 1) { -+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); -+ return; -+ } -+} -+ -+static const MemoryRegionOps ls7a_reset_ops = { -+ .read = ls7a_reset_readw, -+ .write = ls7a_reset_writew, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static bool vmstate_test_use_memhp(void *opaque) -+{ -+ LS7APCIPMRegs *s = opaque; -+ return s->acpi_memory_hotplug.is_enabled; -+} -+ -+static const VMStateDescription vmstate_memhp_state = { -+ .name = "ls7a_pm/memhp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .needed = vmstate_test_use_memhp, -+ .fields = (VMStateField[]) { -+ VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const VMStateDescription vmstate_cpuhp_state = { -+ .name = "ls7a_pm/cpuhp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_CPU_HOTPLUG(cpuhp_state, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+const VMStateDescription vmstate_ls7a_pm = { -+ .name = "ls7a_pm", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT16(acpi_regs.pm1.evt.sts, LS7APCIPMRegs), -+ VMSTATE_UINT16(acpi_regs.pm1.evt.en, LS7APCIPMRegs), -+ VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, LS7APCIPMRegs), -+ VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, LS7APCIPMRegs), -+ VMSTATE_INT64(acpi_regs.tmr.overflow_time, LS7APCIPMRegs), -+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, LS7APCIPMRegs), -+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ }, -+ .subsections = (const VMStateDescription * []) { -+ &vmstate_memhp_state, -+ &vmstate_cpuhp_state, -+ NULL -+ } -+}; -+ -+static inline int64_t acpi_pm_tmr_get_clock(void) -+{ -+ return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY, -+ NANOSECONDS_PER_SECOND); -+} -+ -+static uint32_t acpi_pm_tmr_get(ACPIREGS *ar) -+{ -+ uint32_t d = acpi_pm_tmr_get_clock(); -+ return d & 0xffffff; -+} -+ -+static void acpi_pm_tmr_timer(void *opaque) -+{ -+ ACPIREGS *ar = opaque; -+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL); -+ ar->tmr.update_sci(ar); -+} -+ -+static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ return acpi_pm_tmr_get(opaque); -+} -+ -+static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ /* nothing */ -+} -+ -+static const MemoryRegionOps acpi_pm_tmr_ops = { -+ .read = acpi_pm_tmr_read, -+ .write = acpi_pm_tmr_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void ls7a_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, -+ MemoryRegion *parent, uint64_t offset) -+{ -+ ar->tmr.update_sci = update_sci; -+ ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar); -+ memory_region_init_io(&ar->tmr.io, memory_region_owner(parent), -+ &acpi_pm_tmr_ops, ar, "acpi-tmr", 4); -+ memory_region_add_subregion(parent, offset, &ar->tmr.io); -+} -+ -+static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) -+{ -+ uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar); -+ if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { -+ /* if TMRSTS is reset, then compute the new overflow time */ -+ acpi_pm_tmr_calc_overflow_time(ar); -+ } -+ ar->pm1.evt.sts &= ~val; -+} -+ -+static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ switch (addr) { -+ case 0: -+ return acpi_pm1_evt_get_sts(ar); -+ case 4: -+ return ar->pm1.evt.en; -+ default: -+ return 0; -+ } -+} -+ -+static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) -+{ -+ ar->pm1.evt.en = val; -+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, -+ val & ACPI_BITMASK_RT_CLOCK_ENABLE); -+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, -+ val & ACPI_BITMASK_TIMER_ENABLE); -+} -+ -+static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ switch (addr) { -+ case 0: -+ acpi_pm1_evt_write_sts(ar, val); -+ ar->pm1.evt.update_sci(ar); -+ break; -+ case 4: -+ acpi_pm1_evt_write_en(ar, val); -+ ar->pm1.evt.update_sci(ar); -+ break; -+ } -+} -+ -+static const MemoryRegionOps acpi_pm_evt_ops = { -+ .read = acpi_pm_evt_read, -+ .write = acpi_pm_evt_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void ls7a_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, -+ MemoryRegion *parent, uint64_t offset) -+{ -+ ar->pm1.evt.update_sci = update_sci; -+ memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent), -+ &acpi_pm_evt_ops, ar, "acpi-evt", 8); -+ memory_region_add_subregion(parent, offset, &ar->pm1.evt.io); -+} -+ -+static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ return ar->pm1.cnt.cnt; -+} -+ -+/* ACPI PM1aCNT */ -+static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) -+{ -+ ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); -+ -+ if (val & ACPI_BITMASK_SLEEP_ENABLE) { -+ /* change suspend type */ -+ uint16_t sus_typ = (val >> 10) & 7; -+ switch (sus_typ) { -+ case 0: /* soft power off */ -+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); -+ break; -+ case 1: -+ qemu_system_suspend_request(); -+ break; -+ default: -+ if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */ -+ qapi_event_send_suspend_disk(); -+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); -+ } -+ break; -+ } -+ } -+} -+ -+static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ acpi_pm1_cnt_write(opaque, val); -+} -+ -+static const MemoryRegionOps acpi_pm_cnt_ops = { -+ .read = acpi_pm_cnt_read, -+ .write = acpi_pm_cnt_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void acpi_notify_wakeup(Notifier *notifier, void *data) -+{ -+ ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup); -+ WakeupReason *reason = data; -+ -+ switch (*reason) { -+ case QEMU_WAKEUP_REASON_RTC: -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS); -+ break; -+ case QEMU_WAKEUP_REASON_PMTIMER: -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS); -+ break; -+ case QEMU_WAKEUP_REASON_OTHER: -+ /* ACPI_BITMASK_WAKE_STATUS should be set on resume. -+ * Pretend that resume was caused by power button */ -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void ls7a_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, -+ bool disable_s3, bool disable_s4, uint8_t s4_val, uint64_t offset) -+{ -+ FWCfgState *fw_cfg; -+ -+ ar->pm1.cnt.s4_val = s4_val; -+ ar->wakeup.notify = acpi_notify_wakeup; -+ qemu_register_wakeup_notifier(&ar->wakeup); -+ memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent), -+ &acpi_pm_cnt_ops, ar, "acpi-cnt", 4); -+ memory_region_add_subregion(parent, offset, &ar->pm1.cnt.io); -+ -+ fw_cfg = fw_cfg_find(); -+ if (fw_cfg) { -+ uint8_t suspend[6] = {128, 0, 0, 129, 128, 128}; -+ suspend[3] = 1 | ((!disable_s3) << 7); -+ suspend[4] = s4_val | ((!disable_s4) << 7); -+ fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6); -+ } -+} -+ -+static void ls7a_pm_reset(void *opaque) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ -+ acpi_pm1_evt_reset(&pm->acpi_regs); -+ acpi_pm1_cnt_reset(&pm->acpi_regs); -+ acpi_pm_tmr_reset(&pm->acpi_regs); -+ acpi_gpe_reset(&pm->acpi_regs); -+ -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static void pm_powerdown_req(Notifier *n, void *opaque) -+{ -+ LS7APCIPMRegs *pm = container_of(n, LS7APCIPMRegs, powerdown_notifier); -+ -+ acpi_pm1_evt_power_down(&pm->acpi_regs); -+} -+ -+void ls7a_pm_init(LS7APCIPMRegs *pm, qemu_irq *pic) -+{ -+ unsigned long base, gpe_len, acpi_aci_irq; -+ -+ /* ls7a board acpi hardware info, including -+ * acpi system io base address -+ * acpi gpe length -+ * acpi sci irq number -+ */ -+ base = ACPI_IO_BASE; -+ gpe_len = ACPI_GPE0_LEN; -+ acpi_aci_irq = ACPI_SCI_IRQ; -+ -+ pm->irq = pic[acpi_aci_irq - 64]; -+ memory_region_init(&pm->iomem, NULL, "ls7a_pm", ACPI_IO_SIZE); -+ memory_region_add_subregion(get_system_memory(), base, &pm->iomem); -+ -+ cpu_hotplug_hw_init(get_system_memory(), NULL, &pm->cpuhp_state, CPU_HOTPLUG_BASE); -+ -+ ls7a_pm_tmr_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, LS7A_PM_TMR_BLK); -+ ls7a_pm1_evt_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, LS7A_PM_EVT_BLK); -+ ls7a_pm1_cnt_init(&pm->acpi_regs, &pm->iomem, false, false, 2, LS7A_PM_CNT_BLK); -+ -+ acpi_gpe_init(&pm->acpi_regs, gpe_len); -+ memory_region_init_io(&pm->iomem_gpe, NULL, &ls7a_gpe_ops, pm, -+ "acpi-gpe0", gpe_len); -+ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_STS_REG, &pm->iomem_gpe); -+ -+ memory_region_init_io(&pm->iomem_reset, NULL, &ls7a_reset_ops, pm, -+ "acpi-reset", 4); -+ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_RESET_REG, &pm->iomem_reset); -+ -+ qemu_register_reset(ls7a_pm_reset, pm); -+ -+ pm->powerdown_notifier.notify = pm_powerdown_req; -+ qemu_register_powerdown_notifier(&pm->powerdown_notifier); -+ -+ if (pm->acpi_memory_hotplug.is_enabled) { -+ acpi_memory_hotplug_init(get_system_memory(), NULL, -+ &pm->acpi_memory_hotplug, MEMORY_HOTPLUG_BASE); -+ } -+} -+ -+ -+static void ls7a_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ uint64_t value = ACPI_IO_BASE + LS7A_GPE0_STS_REG; -+ -+ visit_type_uint64(v, name, &value, errp); -+} -+ -+static bool ls7a_pm_get_memory_hotplug_support(Object *obj, Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ return ls7a->pm.acpi_memory_hotplug.is_enabled; -+} -+ -+static void ls7a_pm_set_memory_hotplug_support(Object *obj, bool value, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ ls7a->pm.acpi_memory_hotplug.is_enabled = value; -+} -+ -+static void ls7a_pm_get_disable_s3(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->disable_s3; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_disable_s3(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->disable_s3 = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void ls7a_pm_get_disable_s4(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->disable_s4; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_disable_s4(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->disable_s4 = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void ls7a_pm_get_s4_val(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->s4_val; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_s4_val(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->s4_val = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+void ls7a_pm_add_properties(Object *obj, LS7APCIPMRegs *pm, Error **errp) -+{ -+ static const uint32_t gpe0_len = ACPI_GPE0_LEN; -+ pm->acpi_memory_hotplug.is_enabled = true; -+ pm->disable_s3 = 0; -+ pm->disable_s4 = 0; -+ pm->s4_val = 2; -+ -+ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, -+ &pm->pm_io_base, OBJ_PROP_FLAG_READ); -+ object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", -+ ls7a_pm_get_gpe0_blk, -+ NULL, NULL, pm); -+ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, -+ &gpe0_len, OBJ_PROP_FLAG_READ); -+ object_property_add_bool(obj, "memory-hotplug-support", -+ ls7a_pm_get_memory_hotplug_support, -+ ls7a_pm_set_memory_hotplug_support); -+ object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8", -+ ls7a_pm_get_disable_s3, -+ ls7a_pm_set_disable_s3, -+ NULL, pm); -+ object_property_add(obj, ACPI_PM_PROP_S4_DISABLED, "uint8", -+ ls7a_pm_get_disable_s4, -+ ls7a_pm_set_disable_s4, -+ NULL, pm); -+ object_property_add(obj, ACPI_PM_PROP_S4_VAL, "uint8", -+ ls7a_pm_get_s4_val, -+ ls7a_pm_set_s4_val, -+ NULL, pm); -+} -+ -+void ls7a_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { -+ nvdimm_acpi_plug_cb(hotplug_dev, dev); -+ } else { -+ acpi_memory_plug_cb(hotplug_dev, &ls7a->pm.acpi_memory_hotplug, -+ dev, errp); -+ } -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_plug_cb(hotplug_dev, &ls7a->pm.cpuhp_state, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device plug request for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ acpi_memory_unplug_request_cb(hotplug_dev, -+ &ls7a->pm.acpi_memory_hotplug, dev, -+ errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_unplug_request_cb(hotplug_dev, &ls7a->pm.cpuhp_state, -+ dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug request for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ acpi_memory_unplug_cb(&ls7a->pm.acpi_memory_hotplug, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_unplug_cb(&ls7a->pm.cpuhp_state, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); -+ -+ acpi_memory_ospm_status(&ls7a->pm.acpi_memory_hotplug, list); -+ acpi_cpu_ospm_status(&ls7a->pm.cpuhp_state, list); -+} -+ -+void ls7a_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); -+ -+ acpi_send_gpe_event(&ls7a->pm.acpi_regs, ls7a->pm.irq, ev); -+} -+ -+ -+ -diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build -index adf6347bc..5fe4cfa4f 100644 ---- a/hw/acpi/meson.build -+++ b/hw/acpi/meson.build -@@ -6,6 +6,7 @@ acpi_ss.add(files( - 'core.c', - 'utils.c', - )) -+acpi_ss.add(when: 'CONFIG_ACPI_LOONGARCH', if_true: files('larch_7a.c')) - acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_true: files('cpu.c', 'cpu_hotplug.c')) - acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_false: files('acpi-cpu-hotplug-stub.c')) - acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_true: files('memory_hotplug.c')) -diff --git a/include/hw/acpi/ls7a.h b/include/hw/acpi/ls7a.h -new file mode 100644 -index 000000000..4401515c7 ---- /dev/null -+++ b/include/hw/acpi/ls7a.h -@@ -0,0 +1,80 @@ -+/* -+ * QEMU GMCH/LS7A PCI PM Emulation -+ * -+ * Copyright (c) 2009 Isaku Yamahata -+ * VA Linux Systems Japan K.K. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 -+ */ -+ -+#ifndef HW_ACPI_LS7A_H -+#define HW_ACPI_LS7A_H -+ -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/cpu_hotplug.h" -+#include "hw/acpi/cpu.h" -+#include "hw/acpi/memory_hotplug.h" -+#include "hw/acpi/acpi_dev_interface.h" -+#include "hw/acpi/tco.h" -+ -+#define CPU_HOTPLUG_BASE 0x1e000000 -+#define MEMORY_HOTPLUG_BASE 0x1e00000c -+ -+typedef struct LS7APCIPMRegs { -+ /* -+ * In ls7a spec says that pm1_cnt register is 32bit width and -+ * that the upper 16bits are reserved and unused. -+ * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t. -+ */ -+ ACPIREGS acpi_regs; -+ -+ MemoryRegion iomem; -+ MemoryRegion iomem_gpe; -+ MemoryRegion iomem_smi; -+ MemoryRegion iomem_reset; -+ -+ qemu_irq irq; /* SCI */ -+ -+ uint32_t pm_io_base; -+ Notifier powerdown_notifier; -+ -+ bool cpu_hotplug_legacy; -+ AcpiCpuHotplug gpe_cpu; -+ CPUHotplugState cpuhp_state; -+ -+ MemHotplugState acpi_memory_hotplug; -+ -+ uint8_t disable_s3; -+ uint8_t disable_s4; -+ uint8_t s4_val; -+} LS7APCIPMRegs; -+ -+void ls7a_pm_init(LS7APCIPMRegs *ls7a, qemu_irq *sci_irq); -+ -+void ls7a_pm_iospace_update(LS7APCIPMRegs *pm, uint32_t pm_io_base); -+extern const VMStateDescription vmstate_ls7a_pm; -+ -+void ls7a_pm_add_properties(Object *obj, LS7APCIPMRegs *pm, Error **errp); -+ -+void ls7a_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp); -+void ls7a_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+void ls7a_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp); -+ -+void ls7a_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); -+ -+void ls7a_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev); -+#endif /* HW_ACPI_LS7A_H */ --- -2.43.5 - diff --git a/0001-anolis-csv-i386-add-CSV-context.patch b/0001-anolis-csv-i386-add-CSV-context.patch deleted file mode 100644 index 89e3d49..0000000 --- a/0001-anolis-csv-i386-add-CSV-context.patch +++ /dev/null @@ -1,205 +0,0 @@ -From fda324e163898d543e215cfec1aa3d26ba816426 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Tue, 24 Aug 2021 14:57:28 +0800 -Subject: [PATCH 1/8] anolis: csv/i386: add CSV context - -CSV is the secure virtualization feature on Hygon CPU. -It is compatible with the AMD SEV/SEV-ES and extends out -specific funtionality by setting bit 6 of guest policy. - -Add the context and the build option. - -Change-Id: I02b48c779dd25ddda4546fe3e28c1fe0c8c2e4c6 -Signed-off-by: Xin Jiang ---- - configs/devices/i386-softmmu/default.mak | 1 + - .../x86_64-softmmu/x86_64-rh-devices.mak | 1 + - hw/i386/Kconfig | 5 ++ - target/i386/csv-sysemu-stub.c | 16 ++++++ - target/i386/csv.c | 51 +++++++++++++++++++ - target/i386/csv.h | 35 +++++++++++++ - target/i386/meson.build | 1 + - 7 files changed, 110 insertions(+) - create mode 100644 target/i386/csv-sysemu-stub.c - create mode 100644 target/i386/csv.c - create mode 100644 target/i386/csv.h - -diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak -index 598c6646df..db83ffcab9 100644 ---- a/configs/devices/i386-softmmu/default.mak -+++ b/configs/devices/i386-softmmu/default.mak -@@ -23,6 +23,7 @@ - #CONFIG_TPM_TIS_ISA=n - #CONFIG_VTD=n - #CONFIG_SGX=n -+#CONFIG_CSV=n - - # Boards: - # -diff --git a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak -index 31ce08edab..ee1df7aa52 100644 ---- a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak -+++ b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak -@@ -102,3 +102,4 @@ CONFIG_TPM_TIS_ISA=y - CONFIG_TPM_EMULATOR=y - CONFIG_TPM_PASSTHROUGH=y - CONFIG_SGX=y -+CONFIG_CSV=y -diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig -index d22ac4a4b9..ed35d762b3 100644 ---- a/hw/i386/Kconfig -+++ b/hw/i386/Kconfig -@@ -10,6 +10,10 @@ config SGX - bool - depends on KVM - -+config CSV -+ bool -+ depends on SEV -+ - config PC - bool - imply APPLESMC -@@ -26,6 +30,7 @@ config PC - imply QXL - imply SEV - imply SGX -+ imply CSV - imply SGA - imply TEST_DEVICES - imply TPM_CRB -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -new file mode 100644 -index 0000000000..a89b2600e7 ---- /dev/null -+++ b/target/i386/csv-sysemu-stub.c -@@ -0,0 +1,16 @@ -+/* -+ * QEMU CSV support -+ * -+ * Copyright: Hygon Info Technologies Ltd. 2022 -+ * -+ * Author: -+ * Jiang Xin -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include "sev.h" -+#include "csv.h" -diff --git a/target/i386/csv.c b/target/i386/csv.c -new file mode 100644 -index 0000000000..aac825d3f9 ---- /dev/null -+++ b/target/i386/csv.c -@@ -0,0 +1,51 @@ -+/* -+ * QEMU CSV support -+ * -+ * Copyright: Hygon Info Technologies Ltd. 2022 -+ * -+ * Author: -+ * Jiang Xin -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ */ -+ -+#include "qemu/osdep.h" -+ -+#include "cpu.h" -+#include "sev.h" -+#include "csv.h" -+ -+CsvGuestState csv_guest = { 0 }; -+ -+#define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ -+#define CPUID_VENDOR_HYGON_ECX 0x656e6975 /* "uine" */ -+#define CPUID_VENDOR_HYGON_EDX 0x6e65476e /* "nGen" */ -+ -+#define GUEST_POLICY_CSV_BIT (1 << 6) -+ -+static bool is_hygon_cpu(void) -+{ -+ uint32_t ebx = 0; -+ uint32_t ecx = 0; -+ uint32_t edx = 0; -+ -+ host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); -+ -+ if (ebx == CPUID_VENDOR_HYGON_EBX && -+ ecx == CPUID_VENDOR_HYGON_ECX && -+ edx == CPUID_VENDOR_HYGON_EDX) -+ return true; -+ else -+ return false; -+} -+ -+bool -+csv_enabled(void) -+{ -+ if (!is_hygon_cpu()) -+ return false; -+ -+ return sev_es_enabled() && (csv_guest.policy & GUEST_POLICY_CSV_BIT); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -new file mode 100644 -index 0000000000..057d37d975 ---- /dev/null -+++ b/target/i386/csv.h -@@ -0,0 +1,35 @@ -+/* -+ * QEMU CSV support -+ * -+ * Copyright: Hygon Info Technologies Ltd. 2022 -+ * -+ * Author: -+ * Jiang Xin -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ */ -+ -+#ifndef QEMU_CSV_H -+#define QEMU_CSV_H -+ -+#include "qapi/qapi-commands-misc-target.h" -+ -+#ifdef CONFIG_CSV -+bool csv_enabled(void); -+#else -+#define csv_enabled() 0 -+#endif -+ -+struct CsvGuestState { -+ uint32_t policy; -+ int sev_fd; -+ void *state; -+}; -+ -+typedef struct CsvGuestState CsvGuestState; -+ -+extern struct CsvGuestState csv_guest; -+ -+#endif -diff --git a/target/i386/meson.build b/target/i386/meson.build -index ae38dc9563..361dea9290 100644 ---- a/target/i386/meson.build -+++ b/target/i386/meson.build -@@ -21,6 +21,7 @@ i386_softmmu_ss.add(files( - 'cpu-sysemu.c', - )) - i386_softmmu_ss.add(when: 'CONFIG_SEV', if_true: files('sev.c'), if_false: files('sev-sysemu-stub.c')) -+i386_softmmu_ss.add(when: 'CONFIG_CSV', if_true: files('csv.c'), if_false: files('csv-sysemu-stub.c')) - - i386_user_ss = ss.source_set() - --- -2.17.1 - diff --git a/0002-Support-rtc.patch b/0002-Support-rtc.patch deleted file mode 100644 index 989778e..0000000 --- a/0002-Support-rtc.patch +++ /dev/null @@ -1,370 +0,0 @@ -From e0a8c8cb06e866bd334501d637e7219a14ae601b Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:15:49 -0400 -Subject: [PATCH 02/28] Support rtc. - -Change-Id: Idd50274dd2a6c00b21ec0cd099f8d115ab4fa449 -Signed-off-by: lixianglai ---- - hw/timer/Kconfig | 2 + - hw/timer/ls7a_rtc.c | 325 +++++++++++++++++++++++++++++++++++++++++++ - hw/timer/meson.build | 1 + - 3 files changed, 328 insertions(+) - create mode 100644 hw/timer/ls7a_rtc.c - -diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig -index 010be7ed1..b395c72d7 100644 ---- a/hw/timer/Kconfig -+++ b/hw/timer/Kconfig -@@ -60,3 +60,5 @@ config STELLARIS_GPTM - - config AVR_TIMER16 - bool -+config LS7A_RTC -+ bool -diff --git a/hw/timer/ls7a_rtc.c b/hw/timer/ls7a_rtc.c -new file mode 100644 -index 000000000..756f2fc9c ---- /dev/null -+++ b/hw/timer/ls7a_rtc.c -@@ -0,0 +1,325 @@ -+#include "qemu/osdep.h" -+#include "hw/sysbus.h" -+#include "hw/irq.h" -+#include "include/hw/register.h" -+#include "qemu/timer.h" -+#include "sysemu/sysemu.h" -+#include "qemu/cutils.h" -+#include "qemu/log.h" -+#include "qemu-common.h" -+#include "migration/vmstate.h" -+ -+#ifdef DEBUG_LS7A_RTC -+#define DPRINTF (fmt, ...) \ -+do { printf("ls7a_rtc: " fmt , ## __VA_ARGS__); } while (0) -+#else -+#define DPRINTF (fmt, ...) do {} while (0) -+#endif -+ -+ -+#define SYS_TOYTRIM 0x20 -+#define SYS_TOYWRITE0 0x24 -+#define SYS_TOYWRITE1 0x28 -+#define SYS_TOYREAD0 0x2C -+#define SYS_TOYREAD1 0x30 -+#define SYS_TOYMATCH0 0x34 -+#define SYS_TOYMATCH1 0x38 -+#define SYS_TOYMATCH2 0x3C -+#define SYS_RTCCTRL 0x40 -+#define SYS_RTCTRIM 0x60 -+#define SYS_RTCWRTIE0 0x64 -+#define SYS_RTCREAD0 0x68 -+#define SYS_RTCMATCH0 0x6C -+#define SYS_RTCMATCH1 0x70 -+#define SYS_RTCMATCH2 0x74 -+ -+/** -+ ** shift bits and filed mask -+ **/ -+#define TOY_MON_MASK 0x3f -+#define TOY_DAY_MASK 0x1f -+#define TOY_HOUR_MASK 0x1f -+#define TOY_MIN_MASK 0x3f -+#define TOY_SEC_MASK 0x3f -+#define TOY_MSEC_MASK 0xf -+ -+#define TOY_MON_SHIFT 26 -+#define TOY_DAY_SHIFT 21 -+#define TOY_HOUR_SHIFT 16 -+#define TOY_MIN_SHIFT 10 -+#define TOY_SEC_SHIFT 4 -+#define TOY_MSEC_SHIFT 0 -+ -+#define TOY_MATCH_YEAR_MASK 0x3f -+#define TOY_MATCH_MON_MASK 0xf -+#define TOY_MATCH_DAY_MASK 0x1f -+#define TOY_MATCH_HOUR_MASK 0x1f -+#define TOY_MATCH_MIN_MASK 0x3f -+#define TOY_MATCH_SEC_MASK 0x3f -+ -+ -+#define TOY_MATCH_YEAR_SHIFT 26 -+#define TOY_MATCH_MON_SHIFT 22 -+#define TOY_MATCH_DAY_SHIFT 17 -+#define TOY_MATCH_HOUR_SHIFT 12 -+#define TOY_MATCH_MIN_SHIFT 6 -+#define TOY_MATCH_SEC_SHIFT 0 -+ -+#define TOY_ENABLE_BIT (1U << 11) -+ -+#define TYPE_LS7A_RTC "ls7a_rtc" -+#define LS7A_RTC(obj) OBJECT_CHECK(LS7A_RTCState, (obj), TYPE_LS7A_RTC) -+ -+typedef struct LS7A_RTCState { -+ SysBusDevice parent_obj; -+ -+ MemoryRegion iomem; -+ QEMUTimer *timer; -+ /* Needed to preserve the tick_count across migration, even if the -+ * absolute value of the rtc_clock is different on the source and -+ * destination. -+ */ -+ int64_t offset; -+ int64_t data; -+ int64_t save_alarm_offset; -+ int tidx; -+ uint32_t toymatch[3]; -+ uint32_t toytrim; -+ uint32_t cntrctl; -+ uint32_t rtctrim; -+ uint32_t rtccount; -+ uint32_t rtcmatch[3]; -+ qemu_irq toy_irq; -+} LS7A_RTCState; -+ -+enum { -+TOYEN = 1UL << 11, -+RTCEN = 1UL << 13, -+}; -+ -+static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, -+ unsigned size) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *)opaque; -+ struct tm tm; -+ unsigned int val; -+ -+ val = 0; -+ -+ switch (addr) { -+ case SYS_TOYREAD0: -+ qemu_get_timedate(&tm, s->offset); -+ val = (((tm.tm_mon + 1) & TOY_MON_MASK) << TOY_MON_SHIFT) -+ | (((tm.tm_mday) & TOY_DAY_MASK) << TOY_DAY_SHIFT) -+ | (((tm.tm_hour) & TOY_HOUR_MASK) << TOY_HOUR_SHIFT) -+ | (((tm.tm_min) & TOY_MIN_MASK) << TOY_MIN_SHIFT) -+ | (((tm.tm_sec) & TOY_SEC_MASK) << TOY_SEC_SHIFT) | 0x0; -+ break; -+ case SYS_TOYREAD1: -+ qemu_get_timedate(&tm, s->offset); -+ val = tm.tm_year; -+ break; -+ case SYS_TOYMATCH0: -+ val = s->toymatch[0]; -+ break; -+ case SYS_TOYMATCH1: -+ val = s->toymatch[1]; -+ break; -+ case SYS_TOYMATCH2: -+ val = s->toymatch[2]; -+ break; -+ case SYS_RTCCTRL: -+ val = s->cntrctl; -+ break; -+ case SYS_RTCREAD0: -+ val = s->rtccount; -+ break; -+ case SYS_RTCMATCH0: -+ val = s->rtcmatch[0]; -+ break; -+ case SYS_RTCMATCH1: -+ val = s->rtcmatch[1]; -+ break; -+ case SYS_RTCMATCH2: -+ val = s->rtcmatch[2]; -+ break; -+ default: -+ val = 0; -+ break; -+ } -+ return val; -+} -+ -+ -+static void ls7a_rtc_write(void *opaque, hwaddr addr, -+ uint64_t val, unsigned size) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *)opaque; -+ struct tm tm; -+ int64_t alarm_offset, year_diff, expire_time; -+ -+ switch (addr) { -+ case SYS_TOYWRITE0: -+ qemu_get_timedate(&tm, s->offset); -+ tm.tm_sec = (val >> TOY_SEC_SHIFT) & TOY_SEC_MASK; -+ tm.tm_min = (val >> TOY_MIN_SHIFT) & TOY_MIN_MASK; -+ tm.tm_hour = (val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK; -+ tm.tm_mday = ((val >> TOY_DAY_SHIFT) & TOY_DAY_MASK); -+ tm.tm_mon = ((val >> TOY_MON_SHIFT) & TOY_MON_MASK) - 1; -+ s->offset = qemu_timedate_diff(&tm); -+ break; -+ case SYS_TOYWRITE1: -+ qemu_get_timedate(&tm, s->offset); -+ tm.tm_year = val; -+ s->offset = qemu_timedate_diff(&tm); -+ break; -+ case SYS_TOYMATCH0: -+ s->toymatch[0] = val; -+ qemu_get_timedate(&tm, s->offset); -+ tm.tm_sec = (val >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK; -+ tm.tm_min = (val >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK; -+ tm.tm_hour = ((val >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK); -+ tm.tm_mday = ((val >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK); -+ tm.tm_mon = ((val >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1; -+ year_diff = ((val >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK); -+ year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK); -+ tm.tm_year = tm.tm_year + year_diff; -+ alarm_offset = qemu_timedate_diff(&tm) - s->offset; -+ if ((alarm_offset < 0) && (alarm_offset > -5)) { -+ alarm_offset = 0; -+ } -+ expire_time = qemu_clock_get_ms(rtc_clock); -+ expire_time += ((alarm_offset * 1000) + 100); -+ timer_mod(s->timer, expire_time); -+ break; -+ case SYS_TOYMATCH1: -+ s->toymatch[1] = val; -+ break; -+ case SYS_TOYMATCH2: -+ s->toymatch[2] = val; -+ break; -+ case SYS_RTCCTRL: -+ s->cntrctl = val; -+ break; -+ case SYS_RTCWRTIE0: -+ s->rtccount = val; -+ break; -+ case SYS_RTCMATCH0: -+ s->rtcmatch[0] = val; -+ break; -+ case SYS_RTCMATCH1: -+ val = s->rtcmatch[1]; -+ break; -+ case SYS_RTCMATCH2: -+ val = s->rtcmatch[2]; -+ break; -+ default: -+ break; -+ } -+} -+ -+static const MemoryRegionOps ls7a_rtc_ops = { -+ .read = ls7a_rtc_read, -+ .write = ls7a_rtc_write, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+ .valid = { -+ .min_access_size = 4, -+ .max_access_size = 4, -+ }, -+ -+}; -+ -+static void toy_timer(void *opaque) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *) opaque; -+ -+ if (s->cntrctl & TOY_ENABLE_BIT) { -+ qemu_irq_pulse(s->toy_irq); -+ } -+} -+ -+static void ls7a_rtc_realize(DeviceState *dev, Error **errp) -+{ -+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev); -+ LS7A_RTCState *d = LS7A_RTC(sbd); -+ memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops, -+ (void *)d, "ls7a_rtc", 0x100); -+ -+ sysbus_init_irq(sbd, &d->toy_irq); -+ -+ sysbus_init_mmio(sbd, &d->iomem); -+ d->timer = timer_new_ms(rtc_clock, toy_timer, d); -+ timer_mod(d->timer, qemu_clock_get_ms(rtc_clock) + 100); -+ d->offset = 0; -+} -+ -+static int ls7a_rtc_pre_save(void *opaque) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *)opaque; -+ struct tm tm; -+ int64_t year_diff, value; -+ -+ value = s->toymatch[0]; -+ qemu_get_timedate(&tm, s->offset); -+ tm.tm_sec = (value >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK; -+ tm.tm_min = (value >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK; -+ tm.tm_hour = ((value >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK); -+ tm.tm_mday = ((value >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK); -+ tm.tm_mon = ((value >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1; -+ year_diff = ((value >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK); -+ year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK); -+ tm.tm_year = tm.tm_year + year_diff; -+ s->save_alarm_offset = qemu_timedate_diff(&tm) - s->offset; -+ -+ return 0; -+} -+ -+ -+static int ls7a_rtc_post_load(void *opaque, int version_id) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *)opaque; -+ int64_t expire_time; -+ -+ expire_time = qemu_clock_get_ms(rtc_clock) + (s->save_alarm_offset * 1000); -+ timer_mod(s->timer, expire_time); -+ -+ return 0; -+} -+ -+static const VMStateDescription vmstate_ls7a_rtc = { -+ .name = "ls7a_rtc", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = ls7a_rtc_pre_save, -+ .post_load = ls7a_rtc_post_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_INT64(offset, LS7A_RTCState), -+ VMSTATE_INT64(save_alarm_offset, LS7A_RTCState), -+ VMSTATE_UINT32(toymatch[0], LS7A_RTCState), -+ VMSTATE_UINT32(cntrctl, LS7A_RTCState), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+static void ls7a_rtc_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ dc->vmsd = &vmstate_ls7a_rtc; -+ dc->realize = ls7a_rtc_realize; -+ dc->desc = "ls7a rtc"; -+} -+ -+static const TypeInfo ls7a_rtc_info = { -+ .name = TYPE_LS7A_RTC, -+ .parent = TYPE_SYS_BUS_DEVICE, -+ .instance_size = sizeof(LS7A_RTCState), -+ .class_init = ls7a_rtc_class_init, -+}; -+ -+static void ls7a_rtc_register_types(void) -+{ -+ type_register_static(&ls7a_rtc_info); -+} -+ -+type_init(ls7a_rtc_register_types) -diff --git a/hw/timer/meson.build b/hw/timer/meson.build -index 03092e2ce..e841a2f6e 100644 ---- a/hw/timer/meson.build -+++ b/hw/timer/meson.build -@@ -16,6 +16,7 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_mct.c')) - softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pwm.c')) - softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_gptimer.c')) - softmmu_ss.add(when: 'CONFIG_HPET', if_true: files('hpet.c')) -+softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c')) - softmmu_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c')) - softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c')) - softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c')) --- -2.43.5 - diff --git a/0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch b/0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch deleted file mode 100644 index a62796a..0000000 --- a/0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 3239acc6c33806fac55fc08d7e5a81ef9ce85e23 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Wed, 25 Aug 2021 11:07:41 +0800 -Subject: [PATCH 2/8] anolis: csv/i386: add command to initialize CSV context - -When CSV is enabled, KVM_CSV_INIT command is used to initialize -the platform, which is implemented by reusing the SEV API -framework and extending the functionality. - -The KVM_CSV_INIT command should be performed earlier than -any other command. - -Signed-off-by: Xin Jiang -Change-Id: Ia4201dc90c250c23658e1cf5e19b528df9075330 ---- - linux-headers/linux/kvm.h | 11 +++++++++ - target/i386/csv-sysemu-stub.c | 5 ++++ - target/i386/csv.c | 44 +++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 3 +++ - target/i386/sev.c | 17 ++++++++++++++ - target/i386/sev.h | 5 ++++ - 6 files changed, 85 insertions(+) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index bcaf66cc4d..b15b8f5550 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1808,6 +1808,17 @@ struct kvm_sev_receive_update_data { - __u32 trans_len; - }; - -+/* CSV command */ -+enum csv_cmd_id { -+ KVM_CSV_NR_MIN = 0xc0, -+ -+ KVM_CSV_INIT = KVM_CSV_NR_MIN, -+}; -+ -+struct kvm_csv_init_data { -+ __u64 nodemask; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index a89b2600e7..dbd710dc6f 100644 ---- a/target/i386/csv-sysemu-stub.c -+++ b/target/i386/csv-sysemu-stub.c -@@ -14,3 +14,8 @@ - #include "qemu/osdep.h" - #include "sev.h" - #include "csv.h" -+ -+int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) -+{ -+ return 0; -+} -diff --git a/target/i386/csv.c b/target/i386/csv.c -index aac825d3f9..c11f59f30c 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -13,6 +13,12 @@ - - #include "qemu/osdep.h" - -+#include -+ -+#ifdef CONFIG_NUMA -+#include -+#endif -+ - #include "cpu.h" - #include "sev.h" - #include "csv.h" -@@ -41,6 +47,44 @@ static bool is_hygon_cpu(void) - return false; - } - -+int -+csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) -+{ -+ int fw_error; -+ int ret; -+ struct kvm_csv_init_data data = { 0 }; -+ -+#ifdef CONFIG_NUMA -+ int mode; -+ unsigned long nodemask; -+ -+ /* Set flags as 0 to retrieve the default NUMA policy. */ -+ ret = get_mempolicy(&mode, &nodemask, sizeof(nodemask) * 8, NULL, 0); -+ if (ret == 0 && (mode == MPOL_BIND)) -+ data.nodemask = nodemask; -+#endif -+ -+ if (!ops || !ops->sev_ioctl || !ops->fw_error_to_str) -+ return -1; -+ -+ csv_guest.policy = policy; -+ if (csv_enabled()) { -+ ret = ops->sev_ioctl(fd, KVM_CSV_INIT, &data, &fw_error); -+ if (ret) { -+ csv_guest.policy = 0; -+ error_report("%s: Fail to initialize ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, ops->fw_error_to_str(fw_error)); -+ return -1; -+ } -+ -+ csv_guest.sev_fd = fd; -+ csv_guest.state = state; -+ csv_guest.sev_ioctl = ops->sev_ioctl; -+ csv_guest.fw_error_to_str = ops->fw_error_to_str; -+ } -+ return 0; -+} -+ - bool - csv_enabled(void) - { -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 057d37d975..886dbb2613 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -26,10 +26,13 @@ struct CsvGuestState { - uint32_t policy; - int sev_fd; - void *state; -+ int (*sev_ioctl)(int fd, int cmd, void *data, int *error); -+ const char *(*fw_error_to_str)(int code); - }; - - typedef struct CsvGuestState CsvGuestState; - - extern struct CsvGuestState csv_guest; -+extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); - - #endif -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 025ff7a6f8..023532f4ec 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -26,6 +26,7 @@ - #include "crypto/hash.h" - #include "sysemu/kvm.h" - #include "sev.h" -+#include "csv.h" - #include "sysemu/sysemu.h" - #include "sysemu/runstate.h" - #include "trace.h" -@@ -43,6 +44,8 @@ - OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST) - - -+extern struct sev_ops sev_ops; -+ - /** - * SevGuestState: - * -@@ -952,6 +955,15 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - goto err; - } - -+ /* Support CSV */ -+ if (!ret && cmd == KVM_SEV_ES_INIT) { -+ ret = csv_init(sev_guest->policy, sev->sev_fd, &sev->state, &sev_ops); -+ if (ret) { -+ error_setg(errp, "%s: failed to init csv context", __func__); -+ goto err; -+ } -+ } -+ - ret = sev_launch_start(sev); - if (ret) { - error_setg(errp, "%s: failed to create encryption context", __func__); -@@ -1332,6 +1344,11 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) - return ret; - } - -+struct sev_ops sev_ops = { -+ .sev_ioctl = sev_ioctl, -+ .fw_error_to_str = fw_error_to_str, -+}; -+ - static void - sev_register_types(void) - { -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 83e82aa42c..1c97bff99e 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -59,4 +59,9 @@ void sev_es_set_reset_vector(CPUState *cpu); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - -+struct sev_ops { -+ int (*sev_ioctl)(int fd, int cmd, void *data, int *error); -+ const char *(*fw_error_to_str)(int code); -+}; -+ - #endif --- -2.17.1 - diff --git a/0003-Add-loongarch-machine.patch b/0003-Add-loongarch-machine.patch deleted file mode 100644 index 9052ba7..0000000 --- a/0003-Add-loongarch-machine.patch +++ /dev/null @@ -1,5752 +0,0 @@ -From 3cb18285115f8dd7f9135c65b39c93cb7eb3580c Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:39:00 -0400 -Subject: [PATCH 03/28] Add loongarch machine. - -Change-Id: I7e31f874c676b740269945d5e19c6bc836de6a99 -Signed-off-by: lixianglai ---- - hw/loongarch/Kconfig | 17 + - hw/loongarch/acpi-build.c | 783 ++++++++++++ - hw/loongarch/acpi-build.h | 16 + - hw/loongarch/apic.c | 675 +++++++++++ - hw/loongarch/ioapic.c | 422 +++++++ - hw/loongarch/iocsr.c | 219 ++++ - hw/loongarch/ipi.c | 267 +++++ - hw/loongarch/larch_3a.c | 2026 ++++++++++++++++++++++++++++++++ - hw/loongarch/larch_hotplug.c | 355 ++++++ - hw/loongarch/larch_int.c | 91 ++ - hw/loongarch/ls7a_nb.c | 352 ++++++ - hw/loongarch/meson.build | 15 + - include/hw/loongarch/bios.h | 5 + - include/hw/loongarch/cpudevs.h | 53 + - include/hw/loongarch/larch.h | 163 +++ - include/hw/loongarch/ls7a.h | 152 +++ - 16 files changed, 5611 insertions(+) - create mode 100644 hw/loongarch/Kconfig - create mode 100644 hw/loongarch/acpi-build.c - create mode 100644 hw/loongarch/acpi-build.h - create mode 100644 hw/loongarch/apic.c - create mode 100644 hw/loongarch/ioapic.c - create mode 100644 hw/loongarch/iocsr.c - create mode 100644 hw/loongarch/ipi.c - create mode 100644 hw/loongarch/larch_3a.c - create mode 100644 hw/loongarch/larch_hotplug.c - create mode 100644 hw/loongarch/larch_int.c - create mode 100644 hw/loongarch/ls7a_nb.c - create mode 100644 hw/loongarch/meson.build - create mode 100644 include/hw/loongarch/bios.h - create mode 100644 include/hw/loongarch/cpudevs.h - create mode 100644 include/hw/loongarch/larch.h - create mode 100644 include/hw/loongarch/ls7a.h - -diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig -new file mode 100644 -index 000000000..3fe2677fd ---- /dev/null -+++ b/hw/loongarch/Kconfig -@@ -0,0 +1,17 @@ -+config LS7A_APIC -+ bool -+ -+config LS7A_RTC -+ bool -+ -+config LOONGSON3A -+ bool -+ -+config MEM_HOTPLUG -+ bool -+ -+config ACPI_LOONGARCH -+ bool -+ -+config E1000E_PCI -+ bool -diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c -new file mode 100644 -index 000000000..6ba637be5 ---- /dev/null -+++ b/hw/loongarch/acpi-build.c -@@ -0,0 +1,783 @@ -+/* Support for generating ACPI tables and passing them to Guests -+ * -+ * Copyright (C) 2008-2010 Kevin O'Connor -+ * Copyright (C) 2006 Fabrice Bellard -+ * Copyright (C) 2013 Red Hat Inc -+ * -+ * Author: Michael S. Tsirkin -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ -+ * This program 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 General Public License for more details. -+ -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "qapi/qmp/qnum.h" -+#include "acpi-build.h" -+#include "qemu-common.h" -+#include "qemu/bitmap.h" -+#include "qemu/error-report.h" -+#include "hw/pci/pci.h" -+#include "hw/boards.h" -+#include "hw/core/cpu.h" -+#include "target/loongarch64/cpu.h" -+#include "hw/misc/pvpanic.h" -+#include "hw/timer/hpet.h" -+#include "hw/acpi/acpi-defs.h" -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/cpu.h" -+#include "hw/nvram/fw_cfg.h" -+#include "hw/acpi/bios-linker-loader.h" -+#include "hw/loader.h" -+#include "hw/isa/isa.h" -+#include "hw/block/fdc.h" -+#include "hw/acpi/memory_hotplug.h" -+#include "sysemu/tpm.h" -+#include "hw/acpi/tpm.h" -+#include "hw/acpi/vmgenid.h" -+#include "sysemu/tpm_backend.h" -+#include "hw/rtc/mc146818rtc_regs.h" -+#include "sysemu/numa.h" -+#include "sysemu/runstate.h" -+#include "sysemu/reset.h" -+#include "migration/vmstate.h" -+#include "hw/mem/memory-device.h" -+#include "hw/acpi/utils.h" -+#include "hw/acpi/pci.h" -+/* Supported chipsets: */ -+#include "hw/acpi/aml-build.h" -+#include "hw/loongarch/larch.h" -+#include "hw/loongarch/ls7a.h" -+ -+#include "hw/acpi/ipmi.h" -+#include "hw/acpi/ls7a.h" -+ -+/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and -+ * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows -+ * a little bit, there should be plenty of free space since the DSDT -+ * shrunk by ~1.5k between QEMU 2.0 and QEMU 2.1. -+ */ -+#define ACPI_BUILD_ALIGN_SIZE 0x1000 -+ -+#define ACPI_BUILD_TABLE_SIZE 0x20000 -+ -+/* #define DEBUG_ACPI_BUILD */ -+#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 -+ -+/* Default IOAPIC ID */ -+#define ACPI_BUILD_IOAPIC_ID 0x0 -+ -+/* PCI fw r3.0 MCFG table. */ -+/* Subtable */ -+ -+typedef struct AcpiMiscInfo { -+ bool is_piix4; -+ bool has_hpet; -+ TPMVersion tpm_version; -+ const unsigned char *dsdt_code; -+ unsigned dsdt_size; -+ uint16_t pvpanic_port; -+ uint16_t applesmc_io_base; -+} AcpiMiscInfo; -+ -+typedef struct AcpiBuildPciBusHotplugState { -+ GArray *device_table; -+ GArray *notify_table; -+ struct AcpiBuildPciBusHotplugState *parent; -+ bool pcihp_bridge_en; -+} AcpiBuildPciBusHotplugState; -+ -+static void init_common_fadt_data(AcpiFadtData *data) -+{ -+ AmlAddressSpace as = AML_AS_SYSTEM_MEMORY; -+ uint64_t base = LS7A_ACPI_REG_BASE; -+ AcpiFadtData fadt = { -+ .rev = 3, -+ .flags = -+ (1 << ACPI_FADT_F_WBINVD) | -+ (1 << ACPI_FADT_F_PROC_C1) | -+ (1 << ACPI_FADT_F_SLP_BUTTON) | -+ (1 << ACPI_FADT_F_TMR_VAL_EXT) | -+ (1 << ACPI_FADT_F_RESET_REG_SUP) , -+ .plvl2_lat = 0xfff /* C2 state not supported */, -+ .plvl3_lat = 0xfff /* C3 state not supported */, -+ .smi_cmd = 0x00, -+ .sci_int = ACPI_SCI_IRQ, -+ .acpi_enable_cmd = 0x00, -+ .acpi_disable_cmd = 0x00, -+ .pm1a_evt = { .space_id = as, .bit_width = 8 * 8, -+ .address = base + LS7A_PM_EVT_BLK }, -+ .pm1a_cnt = { .space_id = as, .bit_width = 4 * 8, -+ .address = base + LS7A_PM_CNT_BLK }, -+ .pm_tmr = { .space_id = as, .bit_width = 4 * 8, -+ .address = base + LS7A_PM_TMR_BLK }, -+ .gpe0_blk = { .space_id = as, .bit_width = 8 * 8, -+ .address = base + LS7A_GPE0_STS_REG}, -+ .reset_reg = { .space_id = as, .bit_width = 4 * 8, -+ .address = base + LS7A_GPE0_RESET_REG}, -+ .reset_val = 0x1, -+ }; -+ *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)); -+} -+ -+/* 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 */ -+} -+ -+void ls7a_madt_cpu_entry(AcpiDeviceIf *adev, int uid, -+ const CPUArchIdList *apic_ids, GArray *entry, bool force_enabled) -+{ -+ uint32_t apic_id = apic_ids->cpus[uid].arch_id; -+ /* Flags – Local APIC Flags */ -+ uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? -+ 1 /* Enabled */ : 0; -+ -+ /* Rev 1.0b, Table 5-13 Processor Local APIC Structure */ -+ build_append_int_noprefix(entry, 0, 1); /* Type */ -+ build_append_int_noprefix(entry, 8, 1); /* Length */ -+ build_append_int_noprefix(entry, uid, 1); /* ACPI Processor ID */ -+ build_append_int_noprefix(entry, apic_id, 1); /* APIC ID */ -+ build_append_int_noprefix(entry, flags, 4); /* Flags */ -+} -+static void build_ioapic(GArray *entry, uint8_t id, uint32_t addr, uint32_t irq) -+{ -+ /* Rev 1.0b, 5.2.8.2 IO APIC */ -+ build_append_int_noprefix(entry, 1, 1); /* Type */ -+ build_append_int_noprefix(entry, 12, 1); /* Length */ -+ build_append_int_noprefix(entry, id, 1); /* IO APIC ID */ -+ build_append_int_noprefix(entry, 0, 1); /* Reserved */ -+ build_append_int_noprefix(entry, addr, 4); /* IO APIC Address */ -+ build_append_int_noprefix(entry, irq, 4); /* System Vector Base */ -+} -+ -+static void -+build_madt(GArray *table_data, BIOSLinker *linker, LoongarchMachineState *lsms) -+{ -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ MachineClass *mc = MACHINE_GET_CLASS(lsms); -+ const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(lsms)); -+ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(lsms->acpi_dev); -+ AcpiDeviceIf *adev = ACPI_DEVICE_IF(lsms->acpi_dev); -+ int i; -+ AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lsms->oem_id, -+ .oem_table_id = lsms->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 < apic_ids->len; i++) { -+ adevc->madt_cpu(adev, i, apic_ids, table_data, false); -+ } -+ -+ -+ build_ioapic(table_data, ACPI_BUILD_IOAPIC_ID, lsmc->ls7a_ioapic_reg_base, LOONGARCH_PCH_IRQ_BASE); -+ -+ /* Rev 1.0b, 5.2.8.3.3 Local APIC NMI */ -+ build_append_int_noprefix(table_data, 3, 1); /* Type */ -+ build_append_int_noprefix(table_data, 6, 1); /* Length */ -+ /* ACPI Processor ID */ -+ build_append_int_noprefix(table_data, 0xFF /* all processors */, 1); -+ build_append_int_noprefix(table_data, 0, 2); /* Flags */ -+ /* Local APIC INTI# */ -+ build_append_int_noprefix(table_data, 1 /* ACPI_LINT1 */, 1); -+ -+ /* Rev 1.0b, 5.2.8.3.3 Local APIC NMI */ -+ build_append_int_noprefix(table_data, 4, 1); /* Type */ -+ build_append_int_noprefix(table_data, 6, 1); /* Length */ -+ /* ACPI Processor ID */ -+ build_append_int_noprefix(table_data, 0xFF /* all processors */, 1); -+ build_append_int_noprefix(table_data, 0, 2); /* Flags */ -+ /* Local APIC INTI# */ -+ build_append_int_noprefix(table_data, 1 /* ACPI_LINT1 */, 1); -+ -+ -+ acpi_table_end(linker, &table); -+} -+ -+static void -+build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) -+{ -+ uint64_t i, mem_len, mem_base; -+ MachineClass *mc = MACHINE_GET_CLASS(machine); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine); -+ int nb_numa_nodes = machine->numa_state->num_nodes; -+ NodeInfo *numa_info = machine->numa_state->nodes; -+ AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lsms->oem_id, -+ .oem_table_id = lsms->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 < apic_ids->len; ++i) { -+ /* 5.2.15.1 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, apic_ids->cpus[i].props.node_id, 1); -+ build_append_int_noprefix(table_data, apic_ids->cpus[i].arch_id, 1); /* APIC ID */ -+ /* Flags, Table 5-36 */ -+ build_append_int_noprefix(table_data, 1, 4); -+ build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */ -+ /* Proximity Domain [31:8] */ -+ build_append_int_noprefix(table_data, 0, 3); -+ build_append_int_noprefix(table_data, 0, 4); /* Reserved */ -+ } -+ -+ /* node0 */ -+ mem_base = (uint64_t)0; -+ mem_len = 0x10000000; -+ build_srat_memory(table_data, mem_base, mem_len, -+ 0, MEM_AFFINITY_ENABLED); -+ mem_base = 0x90000000; -+ if (!nb_numa_nodes) { -+ mem_len = machine->ram_size - 0x10000000; -+ } else { -+ mem_len = numa_info[0].node_mem - 0x10000000; -+ } -+ -+ build_srat_memory(table_data, mem_base, mem_len, -+ 0, MEM_AFFINITY_ENABLED); -+ mem_base += mem_len; -+ -+ /* node1 ~ nodemax */ -+ for (i = 1; i < nb_numa_nodes; ++i) { -+ mem_len = numa_info[i].node_mem; -+ build_srat_memory(table_data, mem_base, mem_len, -+ i, MEM_AFFINITY_ENABLED); -+ mem_base += mem_len; -+ } -+ -+ if (lsms->hotplug_memory_size) { -+ build_srat_memory(table_data, machine->device_memory->base, -+ lsms->hotplug_memory_size, 0, -+ MEM_AFFINITY_HOTPLUGGABLE | 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_ls7a_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(LOONGARCH_PCH_IRQ_BASE + 16 + (slot * 4 + pin) % 16)); -+ 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_ls7a_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_ls7a_rtc_device_aml(Aml *table) -+{ -+ Aml *dev; -+ Aml *crs; -+ uint32_t rtc_irq = LS7A_RTC_IRQ; -+ -+ Aml *scope = aml_scope("_SB"); -+ dev = aml_device("RTC"); -+ aml_append(dev, aml_name_decl("_HID", aml_string("LOON0001"))); -+ 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, LS7A_RTC_REG_BASE, -+ LS7A_RTC_REG_BASE + LS7A_RTC_LEN - 1, 0, LS7A_RTC_LEN)); -+ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, -+ AML_EXCLUSIVE, &rtc_irq, 1)); -+ -+ aml_append(dev, aml_name_decl("_CRS", crs)); -+ aml_append(scope, dev); -+ aml_append(table, scope); -+} -+ -+static void build_ls7a_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, LS7A_UART_BASE, LS7A_UART_BASE + LS7A_UART_LEN - 1, 0, 0x8)); -+ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, -+ AML_EXCLUSIVE, &uart_irq, 1)); -+ aml_append(dev, aml_name_decl("_CRS", crs)); -+ pkg0 = aml_package(0x2); -+ aml_append(pkg0, aml_int(0x01F78A40)); -+ aml_append(pkg0, aml_string("clock-frenquency")); -+ pkg1 = aml_package(0x1); -+ aml_append(pkg1, pkg0); -+ pkg2 = aml_package(0x2); -+ aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); -+ aml_append(pkg2, pkg1); -+ -+ aml_append(dev, aml_name_decl("_DSD", pkg2)); -+ -+ aml_append(scope, dev); -+ aml_append(table, scope); -+} -+ -+static void -+build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) -+{ -+ Aml *dsdt, *sb_scope, *scope, *dev, *crs, *pkg; -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ uint32_t nr_mem = machine->ram_slots; -+ uint64_t base = LS7A_ACPI_REG_BASE; -+ int root_bus_limit = PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1); -+ AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lsms->oem_id, -+ .oem_table_id = lsms->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_ls7a_osc_method()); -+ aml_append(sb_scope, dev); -+ aml_append(dsdt, sb_scope); -+ -+ build_ls7a_pci0_int(dsdt); -+ build_ls7a_rtc_device_aml(dsdt); -+ build_ls7a_uart_device_aml(dsdt); -+ -+ if (lsms->acpi_dev) { -+ CPUHotplugFeatures opts = { -+ .acpi_1_compatible = true, .has_legacy_cphp = false -+ }; -+ build_cpus_aml(dsdt, machine, opts, CPU_HOTPLUG_BASE, -+ "\\_SB.PCI0", "\\_GPE._E02"); -+ -+ build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", -+ "\\_GPE._E03", AML_SYSTEM_MEMORY, -+ MEMORY_HOTPLUG_BASE); -+ } -+ -+ scope = aml_scope("_GPE"); -+ { -+ aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); -+ } -+ aml_append(dsdt, scope); -+ -+ 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_word_io(AML_MIN_FIXED, AML_MAX_FIXED, -+ AML_POS_DECODE, AML_ENTIRE_RANGE, -+ 0x0000, 0x4000, 0xFFFF, 0x0000, 0xC000)); -+ aml_append(crs, -+ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, -+ AML_CACHEABLE, AML_READ_WRITE, -+ 0, 0x40000000, 0x7FFFFFFF, 0, 0x40000000)); -+ aml_append(scope, aml_name_decl("_CRS", crs)); -+ -+ /* reserve GPE0 block resources */ -+ dev = aml_device("GPE0"); -+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06"))); -+ aml_append(dev, aml_name_decl("_UID", aml_string("GPE0 resources"))); -+ /* device present, functioning, decoding, not shown in UI */ -+ aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); -+ crs = aml_resource_template(); -+ aml_append(crs, -+ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, -+ AML_CACHEABLE, AML_READ_WRITE, -+ 0, base + LS7A_GPE0_STS_REG, -+ base + LS7A_GPE0_STS_REG + 0x3, 0, 0x4)); -+ aml_append(dev, aml_name_decl("_CRS", crs)); -+ aml_append(scope, dev); -+ aml_append(dsdt, scope); -+ -+ scope = aml_scope("\\"); -+ pkg = aml_package(4); -+ aml_append(pkg, aml_int(7)); /* PM1a_CNT.SLP_TYP */ -+ aml_append(pkg, aml_int(7)); /* PM1b_CNT.SLP_TYP not impl. */ -+ 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 *lsms = LoongarchMACHINE(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 /* clear */, -+ sizeof(uint32_t)); -+ ACPI_BUILD_DPRINTF("init ACPI tables\n"); -+ -+ bios_linker_loader_alloc(tables->linker, -+ ACPI_BUILD_TABLE_FILE, tables_blob, -+ 64 /* Ensure FACS is aligned */, -+ false /* high memory */); -+ -+ /* -+ * 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(qdev_get_machine())); -+ -+ /* Count the size of the DSDT and SSDT, 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, -+ "LOONGS", "TP-R00"); -+ aml_len += tables_blob->len - fadt; -+ -+ acpi_add_table(table_offsets, tables_blob); -+ build_madt(tables_blob, tables->linker, lsms); -+ -+ acpi_add_table(table_offsets, tables_blob); -+ build_srat(tables_blob, tables->linker, machine); -+ if (machine->numa_state->have_numa_distance) { -+ acpi_add_table(table_offsets, tables_blob); -+ build_slit(tables_blob, tables->linker, machine, lsms->oem_id, -+ lsms->oem_table_id); -+ } -+ -+ /* Build mcfg */ -+ acpi_add_table(table_offsets, tables_blob); -+ { -+ AcpiMcfgInfo mcfg = { -+ .base = LS_PCIECFG_BASE, -+ .size = LS_PCIECFG_SIZE, -+ }; -+ build_mcfg(tables_blob, tables->linker, &mcfg, lsms->oem_id, -+ lsms->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, -+ "LOONGS", "TP-R00"); -+ -+ /* RSDP is in FSEG memory, so allocate it separately */ -+ { -+ AcpiRsdpData rsdp_data = { -+ .revision = 0, -+ .oem_id = lsms->oem_id, -+ .xsdt_tbl_offset = NULL, -+ .rsdt_tbl_offset = &rsdt, -+ }; -+ build_rsdp(tables->rsdp, tables->linker, &rsdp_data); -+ } -+ 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); -+ -+ if (build_state->rsdp) { -+ memcpy(build_state->rsdp, tables.rsdp->data, -+ acpi_data_len(tables.rsdp)); -+ } else { -+ 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(void) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ AcpiBuildTables tables; -+ AcpiBuildState *build_state; -+ -+ if (!lsms->fw_cfg) { -+ ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); -+ return; -+ } -+ -+ if (!lsms->acpi_build_enabled) { -+ ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n"); -+ return; -+ } -+ -+ if (!loongarch_is_acpi_enabled(lsms)) { -+ 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(lsms)); -+ -+ /* 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, -+ "etc/table-loader"); -+ -+ fw_cfg_add_file(lsms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, -+ tables.tcpalog->data, acpi_data_len(tables.tcpalog)); -+ -+ build_state->rsdp = NULL; -+ 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); -+} -diff --git a/hw/loongarch/acpi-build.h b/hw/loongarch/acpi-build.h -new file mode 100644 -index 000000000..a914268bb ---- /dev/null -+++ b/hw/loongarch/acpi-build.h -@@ -0,0 +1,16 @@ -+ -+#ifndef HW_LARCH_ACPI_BUILD_H -+#define HW_LARCH_ACPI_BUILD_H -+ -+#define EFI_ACPI_OEM_ID "LARCH" -+#define EFI_ACPI_OEM_TABLE_ID "LARCH" /* OEM table id 8 bytes long */ -+#define EFI_ACPI_OEM_REVISION 0x00000002 -+#define EFI_ACPI_CREATOR_ID "LINUX" -+#define EFI_ACPI_CREATOR_REVISION 0x01000013 -+ -+#define ACPI_COMPATIBLE_1_0 0 -+#define ACPI_COMPATIBLE_2_0 1 -+ -+void loongarch_acpi_setup(void); -+ -+#endif -diff --git a/hw/loongarch/apic.c b/hw/loongarch/apic.c -new file mode 100644 -index 000000000..d6ba2a2ce ---- /dev/null -+++ b/hw/loongarch/apic.c -@@ -0,0 +1,675 @@ -+/* -+ * Loongarch 3A5000 interrupt controller emulation -+ * -+ * Copyright (C) 2020 Lu Zeng -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program 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 General Public License -+ * for more details. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "hw/boards.h" -+#include "hw/irq.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/sysbus.h" -+#include "qemu/host-utils.h" -+#include "qemu/error-report.h" -+#include "sysemu/kvm.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "target/loongarch64/cpu.h" -+#include "exec/address-spaces.h" -+#include "hw/loongarch/larch.h" -+#include "migration/vmstate.h" -+ -+#define DEBUG_APIC 0 -+ -+#define DPRINTF(fmt, ...) \ -+do { \ -+ if (DEBUG_APIC) { \ -+ fprintf(stderr, "APIC: " fmt , ## __VA_ARGS__); \ -+ } \ -+} while (0) -+ -+#define APIC_OFFSET 0x400 -+#define APIC_BASE (0x1f010000ULL) -+#define EXTIOI_NODETYPE_START (0x4a0 - APIC_OFFSET) -+#define EXTIOI_NODETYPE_END (0x4c0 - APIC_OFFSET) -+#define EXTIOI_IPMAP_START (0x4c0 - APIC_OFFSET) -+#define EXTIOI_IPMAP_END (0x4c8 - APIC_OFFSET) -+#define EXTIOI_ENABLE_START (0x600 - APIC_OFFSET) -+#define EXTIOI_ENABLE_END (0x620 - APIC_OFFSET) -+#define EXTIOI_BOUNCE_START (0x680 - APIC_OFFSET) -+#define EXTIOI_BOUNCE_END (0x6a0 - APIC_OFFSET) -+#define EXTIOI_ISR_START (0x700 - APIC_OFFSET) -+#define EXTIOI_ISR_END (0x720 - APIC_OFFSET) -+#define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET) -+#define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET) -+#define EXTIOI_COREISR_START (0x10000) -+#define EXTIOI_COREISR_END (EXTIOI_COREISR_START + 0x10000) -+ -+static int ext_irq_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ apicState *apic = opaque; -+ struct loongarch_kvm_irqchip *chip; -+ struct kvm_loongarch_ls3a_extirq_state *kstate; -+ int ret, length, i, vcpuid; -+#endif -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+#ifdef CONFIG_KVM -+ length = sizeof(struct loongarch_kvm_irqchip) + -+ sizeof(struct kvm_loongarch_ls3a_extirq_state); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS3A_EXTIRQ; -+ chip->len = length; -+ -+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ -+ kstate = (struct kvm_loongarch_ls3a_extirq_state *)chip->data; -+ for (i = 0; i < EXTIOI_IRQS_BITMAP_SIZE; i++) { -+ apic->ext_en[i] = kstate->ext_en_r.reg_u8[i]; -+ apic->ext_bounce[i] = kstate->bounce_r.reg_u8[i]; -+ apic->ext_isr[i] = kstate->ext_isr_r.reg_u8[i]; -+ for (vcpuid = 0; vcpuid < MAX_CORES; vcpuid++) { -+ apic->ext_coreisr[vcpuid][i] = kstate->ext_core_isr_r.reg_u8[vcpuid][i]; -+ } -+ } -+ for (i = 0; i < EXTIOI_IRQS_IPMAP_SIZE; i++) { -+ apic->ext_ipmap[i] = kstate->ip_map_r.reg_u8[i]; -+ } -+ for (i = 0; i < EXTIOI_IRQS; i++) { -+ apic->ext_coremap[i] = kstate->core_map_r.reg_u8[i];; -+ } -+ for (i = 0; i < 16; i++) { -+ apic->ext_nodetype[i] = kstate->node_type_r.reg_u16[i]; -+ } -+ g_free(chip); -+#endif -+ return 0; -+} -+ -+static int ext_irq_post_load(void *opaque, int version) -+{ -+#ifdef CONFIG_KVM -+ apicState *apic = opaque; -+ struct loongarch_kvm_irqchip *chip; -+ struct kvm_loongarch_ls3a_extirq_state *kstate; -+ int ret, length, i, vcpuid; -+#endif -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+#ifdef CONFIG_KVM -+ length = sizeof(struct loongarch_kvm_irqchip) + -+ sizeof(struct kvm_loongarch_ls3a_extirq_state); -+ chip = g_malloc0(length); -+ -+ chip->chip_id = KVM_IRQCHIP_LS3A_EXTIRQ; -+ chip->len = length; -+ -+ kstate = (struct kvm_loongarch_ls3a_extirq_state *)chip->data; -+ for (i = 0; i < EXTIOI_IRQS_BITMAP_SIZE; i++) { -+ kstate->ext_en_r.reg_u8[i] = apic->ext_en[i]; -+ kstate->bounce_r.reg_u8[i] = apic->ext_bounce[i]; -+ kstate->ext_isr_r.reg_u8[i] = apic->ext_isr[i]; -+ for (vcpuid = 0; vcpuid < MAX_CORES; vcpuid++) { -+ kstate->ext_core_isr_r.reg_u8[vcpuid][i] = apic->ext_coreisr[vcpuid][i]; -+ } -+ } -+ for (i = 0; i < EXTIOI_IRQS_IPMAP_SIZE; i++) { -+ kstate->ip_map_r.reg_u8[i] = apic->ext_ipmap[i]; -+ } -+ for (i = 0; i < EXTIOI_IRQS; i++) { -+ kstate->core_map_r.reg_u8[i] = apic->ext_coremap[i]; -+ } -+ for (i = 0; i < 16; i++) { -+ kstate->node_type_r.reg_u16[i] = apic->ext_nodetype[i]; -+ } -+ -+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_SET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ g_free(chip); -+#endif -+ return 0; -+} -+typedef struct nodeApicState { -+ unsigned long addr; -+ int nodeid; -+ apicState *apic; -+} nodeApicState; -+ -+static void ioapic_update_irq(void *opaque, int irq, int level) -+{ -+ apicState *s = opaque; -+ uint8_t ipnum, cpu, cpu_ipnum; -+ unsigned long found1, found2; -+ uint8_t reg_count, reg_bit; -+ -+ reg_count = irq / 32; -+ reg_bit = irq % 32; -+ -+ ipnum = s->ext_sw_ipmap[irq]; -+ cpu = s->ext_sw_coremap[irq]; -+ cpu_ipnum = cpu * LS3A_INTC_IP + ipnum; -+ if (level == 1) { -+ if (test_bit(reg_bit, ((void *)s->ext_en + 0x4 * reg_count)) == false) { -+ return; -+ } -+ -+ if (test_bit(reg_bit, ((void *)s->ext_isr + 0x4 * reg_count)) == false) { -+ return; -+ } -+ bitmap_set(((void *)s->ext_coreisr[cpu] + 0x4 * reg_count), reg_bit, 1); -+ found1 = find_next_bit(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), -+ EXTIOI_IRQS, 0); -+ bitmap_set(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), reg_bit, 1); -+ if (found1 >= EXTIOI_IRQS) { -+ qemu_set_irq(s->parent_irq[cpu][ipnum], level); -+ } -+ } else { -+ bitmap_clear(((void *)s->ext_isr + 0x4 * reg_count), reg_bit, 1); -+ bitmap_clear(((void *)s->ext_coreisr[cpu] + 0x4 * reg_count), reg_bit, 1); -+ found1 = find_next_bit(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), -+ EXTIOI_IRQS, 0); -+ found1 += reg_count * 32; -+ bitmap_clear(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), reg_bit, 1); -+ found2 = find_next_bit(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), -+ EXTIOI_IRQS, 0); -+ if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) { -+ qemu_set_irq(s->parent_irq[cpu][ipnum], level); -+ } -+ } -+} -+ -+static void ioapic_setirq(void *opaque, int irq, int level) -+{ -+ apicState *s = opaque; -+ uint8_t reg_count, reg_bit; -+ -+ reg_count = irq / 32; -+ reg_bit = irq % 32; -+ -+ if (level) { -+ bitmap_set(((void *)s->ext_isr + 0x4 * reg_count), reg_bit, 1); -+ } else { -+ bitmap_clear(((void *)s->ext_isr + 0x4 * reg_count), reg_bit, 1); -+ } -+ -+ ioapic_update_irq(s, irq, level); -+} -+ -+static uint32_t apic_readb(void *opaque, hwaddr addr) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint8_t ret; -+ int cpu; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ ret = 0; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ ret = *(uint8_t *)((void *)state->ext_en + off); -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ ret = *(uint8_t *)((void *)state->ext_bounce + off); -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ ret = *(uint8_t *)((void *)state->ext_isr + off); -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ ret = *(uint8_t *)((void *)state->ext_coreisr[cpu] + (off & 0x1f)); -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ off -= EXTIOI_IPMAP_START; -+ ret = *(uint8_t *)((void *)state->ext_ipmap + off); -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ off -= EXTIOI_COREMAP_START; -+ ret = *(uint8_t *)((void *)state->ext_coremap + off); -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ ret = *(uint8_t *)((void *)state->ext_nodetype + off); -+ } -+ -+ DPRINTF("readb reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, ret); -+ return ret; -+} -+ -+static uint32_t apic_readw(void *opaque, hwaddr addr) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint16_t ret; -+ int cpu; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ ret = 0; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ ret = *(uint16_t *)((void *)state->ext_en + off); -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ ret = *(uint16_t *)((void *)state->ext_bounce + off); -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ ret = *(uint16_t *)((void *)state->ext_isr + off); -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ ret = *(uint16_t *)((void *)state->ext_coreisr[cpu] + (off & 0x1f)); -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ off -= EXTIOI_IPMAP_START; -+ ret = *(uint16_t *)((void *)state->ext_ipmap + off); -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ off -= EXTIOI_COREMAP_START; -+ ret = *(uint16_t *)((void *)state->ext_coremap + off); -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ ret = *(uint16_t *)((void *)state->ext_nodetype + off); -+ } -+ -+ DPRINTF("readw reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, ret); -+ return ret; -+} -+ -+static uint32_t apic_readl(void *opaque, hwaddr addr) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint32_t ret; -+ int cpu; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ ret = 0; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ ret = *(uint32_t *)((void *)state->ext_en + off); -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ ret = *(uint32_t *)((void *)state->ext_bounce + off); -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ ret = *(uint32_t *)((void *)state->ext_isr + off); -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ ret = *(uint32_t *)((void *)state->ext_coreisr[cpu] + (off & 0x1f)); -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ off -= EXTIOI_IPMAP_START; -+ ret = *(uint32_t *)((void *)state->ext_ipmap + off); -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ off -= EXTIOI_COREMAP_START; -+ ret = *(uint32_t *)((void *)state->ext_coremap + off); -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ ret = *(uint32_t *)((void *)state->ext_nodetype + off); -+ } -+ -+ DPRINTF("readl reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, ret); -+ return ret; -+ -+} -+ -+static void apic_writeb(void *opaque, hwaddr addr, uint32_t val) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint8_t old; -+ int cpu, i, ipnum, level, mask; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ old = *(uint8_t *)((void *)state->ext_en + off); -+ if (old != val) { -+ *(uint8_t *)((void *)state->ext_en + off) = val; -+ old = old ^ val; -+ mask = 0x1; -+ for (i = 0; i < 8; i++) { -+ if (old & mask) { -+ level = !!(val & (0x1 << i)); -+ ioapic_update_irq(state, i + off * 8, level); -+ } -+ mask = mask << 1; -+ } -+ } -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ *(uint8_t *)((void *)state->ext_bounce + off) = val; -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ old = *(uint8_t *)((void *)state->ext_isr + off); -+ *(uint8_t *)((void *)state->ext_isr + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 8; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ off = off & 0x1f; -+ old = *(uint8_t *)((void *)state->ext_coreisr[cpu] + off); -+ *(uint8_t *)((void *)state->ext_coreisr[cpu] + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 8; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ off -= EXTIOI_IPMAP_START; -+ val = val & 0xf; -+ *(uint8_t *)((void *)state->ext_ipmap + off) = val; -+ ipnum = 0; -+ for (i = 0; i < 4; i++) { -+ if (val & (0x1 << i)) { -+ ipnum = i; -+ break; -+ } -+ } -+ if (val) { -+ for (i = 0; i < 32; i++) { -+ cpu = off * 32 + i; -+ state->ext_sw_ipmap[cpu] = ipnum; -+ } -+ } -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ off -= EXTIOI_COREMAP_START; -+ val = val & 0xff; -+ *(uint8_t *)((void *)state->ext_coremap + off) = val; -+ state->ext_sw_coremap[off] = val; -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ *(uint8_t *)((void *)state->ext_nodetype + off) = val; -+ } -+ -+ DPRINTF("writeb reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, val); -+} -+ -+static void apic_writew(void *opaque, hwaddr addr, uint32_t val) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint16_t old; -+ int cpu, i, level, mask; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ old = *(uint16_t *)((void *)state->ext_en + off); -+ if (old != val) { -+ *(uint16_t *)((void *)state->ext_en + off) = val; -+ old = old ^ val; -+ mask = 0x1; -+ for (i = 0; i < 16; i++) { -+ if (old & mask) { -+ level = !!(val & (0x1 << i)); -+ ioapic_update_irq(state, i + off * 8, level); -+ } -+ mask = mask << 1; -+ } -+ } -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ *(uint16_t *)((void *)state->ext_bounce + off) = val; -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ old = *(uint16_t *)((void *)state->ext_isr + off); -+ *(uint16_t *)((void *)state->ext_isr + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 16; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ off = off & 0x1f; -+ old = *(uint16_t *)((void *)state->ext_coreisr[cpu] + off); -+ *(uint16_t *)((void *)state->ext_coreisr[cpu] + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 16; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ apic_writeb(opaque, addr, val & 0xff); -+ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); -+ -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ apic_writeb(opaque, addr, val & 0xff); -+ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); -+ -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ *(uint16_t *)((void *)state->ext_nodetype + off) = val; -+ } -+ -+ DPRINTF("writew reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, val); -+} -+ -+static void apic_writel(void *opaque, hwaddr addr, uint32_t val) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint32_t old; -+ int cpu, i, level, mask; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ old = *(uint32_t *)((void *)state->ext_en + off); -+ if (old != val) { -+ *(uint32_t *)((void *)state->ext_en + off) = val; -+ old = old ^ val; -+ mask = 0x1; -+ for (i = 0; i < 32; i++) { -+ if (old & mask) { -+ level = !!(val & (0x1 << i)); -+ ioapic_update_irq(state, i + off * 8, level); -+ } -+ mask = mask << 1; -+ } -+ } -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ *(uint32_t *)((void *)state->ext_bounce + off) = val; -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ old = *(uint32_t *)((void *)state->ext_isr + off); -+ *(uint32_t *)((void *)state->ext_isr + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 32; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ off = off & 0x1f; -+ old = *(uint32_t *)((void *)state->ext_coreisr[cpu] + off); -+ *(uint32_t *)((void *)state->ext_coreisr[cpu] + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 32; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ apic_writeb(opaque, addr, val & 0xff); -+ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); -+ apic_writeb(opaque, addr + 2, (val >> 16) & 0xff); -+ apic_writeb(opaque, addr + 3, (val >> 24) & 0xff); -+ -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ apic_writeb(opaque, addr, val & 0xff); -+ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); -+ apic_writeb(opaque, addr + 2, (val >> 16) & 0xff); -+ apic_writeb(opaque, addr + 3, (val >> 24) & 0xff); -+ -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ *(uint32_t *)((void *)state->ext_nodetype + off) = val; -+ } -+ -+ DPRINTF("writel reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, val); -+} -+ -+static uint64_t apic_readfn(void *opaque, hwaddr addr, -+ unsigned size) -+{ -+ switch (size) { -+ case 1: -+ return apic_readb(opaque, addr); -+ case 2: -+ return apic_readw(opaque, addr); -+ case 4: -+ return apic_readl(opaque, addr); -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void apic_writefn(void *opaque, hwaddr addr, -+ uint64_t value, unsigned size) -+{ -+ switch (size) { -+ case 1: -+ apic_writeb(opaque, addr, value); -+ break; -+ case 2: -+ apic_writew(opaque, addr, value); -+ break; -+ case 4: -+ apic_writel(opaque, addr, value); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static const VMStateDescription vmstate_apic = { -+ .name = "apic", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = ext_irq_pre_save, -+ .post_load = ext_irq_post_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT8_ARRAY(ext_en, apicState, EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_UINT8_ARRAY(ext_bounce, apicState, EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_UINT8_ARRAY(ext_isr, apicState, EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_UINT8_2DARRAY(ext_coreisr, apicState, MAX_CORES, -+ EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_UINT8_ARRAY(ext_ipmap, apicState, EXTIOI_IRQS_IPMAP_SIZE), -+ VMSTATE_UINT8_ARRAY(ext_coremap, apicState, EXTIOI_IRQS), -+ VMSTATE_UINT16_ARRAY(ext_nodetype, apicState, 16), -+ VMSTATE_UINT64(ext_control, apicState), -+ VMSTATE_UINT8_ARRAY(ext_sw_ipmap, apicState, EXTIOI_IRQS), -+ VMSTATE_UINT8_ARRAY(ext_sw_coremap, apicState, EXTIOI_IRQS), -+ VMSTATE_UINT8_2DARRAY(ext_ipisr, apicState, MAX_CORES * LS3A_INTC_IP, -+ EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const MemoryRegionOps apic_ops = { -+ .read = apic_readfn, -+ .write = apic_writefn, -+ .impl.min_access_size = 1, -+ .impl.max_access_size = 4, -+ .valid.min_access_size = 1, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+}; -+ -+int cpu_init_apic(LoongarchMachineState *ms, CPULOONGARCHState *env, int cpu) -+{ -+ apicState *apic; -+ nodeApicState *node; -+ MemoryRegion *iomem; -+ unsigned long base; -+ int pin; -+ char str[32]; -+ -+ if (ms->apic == NULL) { -+ apic = g_malloc0(sizeof(apicState)); -+ vmstate_register(NULL, 0, &vmstate_apic, apic); -+ apic->irq = qemu_allocate_irqs(ioapic_setirq, apic, EXTIOI_IRQS); -+ -+ for (pin = 0; pin < LS3A_INTC_IP; pin++) { -+ /* cpu_pin[9:2] <= intc_pin[7:0] */ -+ apic->parent_irq[cpu][pin] = env->irq[pin + 2]; -+ } -+ ms->apic = apic; -+ -+ if (cpu == 0) { -+ base = APIC_BASE; -+ node = g_malloc0(sizeof(nodeApicState)); -+ node->apic = ms->apic; -+ node->addr = base; -+ -+ iomem = g_new(MemoryRegion, 1); -+ sprintf(str, "apic%d", cpu); -+ /* extioi addr 0x1f010000~0x1f02ffff */ -+ memory_region_init_io(iomem, NULL, &apic_ops, node, str, 0x20000); -+ memory_region_add_subregion(get_system_memory(), base, iomem); -+ } -+ -+ } else { -+ if (cpu != 0) { -+ for (pin = 0; pin < LS3A_INTC_IP; pin++) { -+ ms->apic->parent_irq[cpu][pin] = env->irq[pin + 2]; -+ } -+ } -+ } -+ return 0; -+} -+ -diff --git a/hw/loongarch/ioapic.c b/hw/loongarch/ioapic.c -new file mode 100644 -index 000000000..3de0ed88d ---- /dev/null -+++ b/hw/loongarch/ioapic.c -@@ -0,0 +1,422 @@ -+/* -+ * LS7A1000 Northbridge IOAPIC support -+ * -+ * Copyright (c) 2019 Loongarch Technology -+ * Authors: -+ * Zhu Chen -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/sysbus.h" -+#include "hw/irq.h" -+#include "qemu/log.h" -+#include "sysemu/kvm.h" -+#include "linux/kvm.h" -+#include "migration/vmstate.h" -+ -+#define DEBUG_LS7A_APIC 0 -+ -+#define DPRINTF(fmt, ...) \ -+do { \ -+ if (DEBUG_LS7A_APIC) { \ -+ fprintf(stderr, "IOAPIC: " fmt , ## __VA_ARGS__); \ -+ } \ -+} while (0) -+ -+#define TYPE_LS7A_APIC "ioapic" -+#define LS7A_APIC(obj) OBJECT_CHECK(LS7AApicState, (obj), TYPE_LS7A_APIC) -+ -+#define LS7A_IOAPIC_ROUTE_ENTRY_OFFSET 0x100 -+#define LS7A_IOAPIC_INT_ID_OFFSET 0x00 -+#define LS7A_INT_ID_VAL 0x7000000UL -+#define LS7A_INT_ID_VER 0x1f0001UL -+#define LS7A_IOAPIC_INT_MASK_OFFSET 0x20 -+#define LS7A_IOAPIC_INT_EDGE_OFFSET 0x60 -+#define LS7A_IOAPIC_INT_CLEAR_OFFSET 0x80 -+#define LS7A_IOAPIC_INT_STATUS_OFFSET 0x3a0 -+#define LS7A_IOAPIC_INT_POL_OFFSET 0x3e0 -+#define LS7A_IOAPIC_HTMSI_EN_OFFSET 0x40 -+#define LS7A_IOAPIC_HTMSI_VEC_OFFSET 0x200 -+#define LS7A_AUTO_CTRL0_OFFSET 0xc0 -+#define LS7A_AUTO_CTRL1_OFFSET 0xe0 -+ -+typedef struct LS7AApicState { -+ SysBusDevice parent_obj; -+ qemu_irq parent_irq[257]; -+ uint64_t int_id; -+ uint64_t int_mask; /*0x020 interrupt mask register*/ -+ uint64_t htmsi_en;/*0x040 1=msi*/ -+ uint64_t intedge; /*0x060 edge=1 level =0*/ -+ uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/ -+ uint64_t auto_crtl0; /*0x0c0*/ -+ uint64_t auto_crtl1; /*0x0e0*/ -+ uint8_t route_entry[64]; /*0x100 - 0x140*/ -+ uint8_t htmsi_vector[64]; /*0x200 - 0x240*/ -+ uint64_t intisr_chip0; /*0x300*/ -+ uint64_t intisr_chip1;/*0x320*/ -+ uint64_t last_intirr; /* edge detection */ -+ uint64_t intirr; /* 0x380 interrupt request register */ -+ uint64_t intisr; /* 0x3a0 interrupt service register */ -+ uint64_t int_polarity; /*0x3e0 interrupt level polarity -+ selection register 0 for high level tirgger*/ -+ MemoryRegion iomem; -+} LS7AApicState; -+ -+static void update_irq(LS7AApicState *s) -+{ -+ int i; -+ if ((s->intirr & (~s->int_mask)) & (~s->htmsi_en)) { -+ DPRINTF("7a update irqline up\n"); -+ s->intisr = (s->intirr & (~s->int_mask) & (~s->htmsi_en)); -+ qemu_set_irq(s->parent_irq[256], 1); -+ } else { -+ DPRINTF("7a update irqline down\n"); -+ s->intisr &= (~s->htmsi_en); -+ qemu_set_irq(s->parent_irq[256], 0); -+ } -+ if (s->htmsi_en) { -+ for (i = 0; i < 64; i++) { -+ if ((((~s->intisr) & s->intirr) & s->htmsi_en) & (1ULL << i)) { -+ s->intisr |= 1ULL << i; -+ qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 1); -+ } else if (((~(s->intisr | s->intirr)) & s->htmsi_en) & -+ (1ULL << i)) { -+ qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 0); -+ } -+ } -+ } -+} -+ -+static void irq_handler(void *opaque, int irq, int level) -+{ -+ LS7AApicState *s = opaque; -+ -+ assert(irq < 64); -+ uint64_t mask = 1ULL << irq; -+ DPRINTF("------ %s irq %d %d\n", __func__, irq, level); -+ -+ if (s->intedge & mask) { -+ /* edge triggered */ -+ /*TODO*/ -+ } else { -+ /* level triggered */ -+ if (level) { -+ s->intirr |= mask; -+ } else { -+ s->intirr &= ~mask; -+ } -+ -+ } -+ update_irq(s); -+ -+} -+ -+static uint64_t ls7a_apic_reg_read(void *opaque, hwaddr addr, unsigned size) -+{ -+ LS7AApicState *a = opaque; -+ uint64_t val = 0; -+ uint64_t offset; -+ int64_t offset_tmp; -+ offset = addr & 0xfff; -+ if (8 == size) { -+ switch (offset) { -+ case LS7A_IOAPIC_INT_ID_OFFSET: -+ val = LS7A_INT_ID_VER; -+ val = (val << 32) + LS7A_INT_ID_VAL; -+ break; -+ case LS7A_IOAPIC_INT_MASK_OFFSET: -+ val = a->int_mask; -+ break; -+ case LS7A_IOAPIC_INT_STATUS_OFFSET: -+ val = a->intisr & (~a->int_mask); -+ break; -+ case LS7A_IOAPIC_INT_EDGE_OFFSET: -+ val = a->intedge; -+ break; -+ case LS7A_IOAPIC_INT_POL_OFFSET: -+ val = a->int_polarity; -+ break; -+ case LS7A_IOAPIC_HTMSI_EN_OFFSET: -+ val = a->htmsi_en; -+ break; -+ case LS7A_AUTO_CTRL0_OFFSET: -+ case LS7A_AUTO_CTRL1_OFFSET: -+ break; -+ default: -+ break; -+ } -+ } else if (1 == size) { -+ if (offset >= LS7A_IOAPIC_HTMSI_VEC_OFFSET) { -+ offset_tmp = offset - LS7A_IOAPIC_HTMSI_VEC_OFFSET; -+ if (offset_tmp >= 0 && offset_tmp < 64) { -+ val = a->htmsi_vector[offset_tmp]; -+ } -+ } else if (offset >= LS7A_IOAPIC_ROUTE_ENTRY_OFFSET) { -+ offset_tmp = offset - LS7A_IOAPIC_ROUTE_ENTRY_OFFSET; -+ if (offset_tmp >= 0 && offset_tmp < 64) { -+ val = a->route_entry[offset_tmp]; -+ DPRINTF("addr %lx val %lx\n", addr, val); -+ } -+ } -+ } -+ DPRINTF(TARGET_FMT_plx" val %lx\n", addr, val); -+ return val; -+} -+ -+static void ls7a_apic_reg_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) -+{ -+ LS7AApicState *a = opaque; -+ int64_t offset_tmp; -+ uint64_t offset; -+ offset = addr & 0xfff; -+ DPRINTF(TARGET_FMT_plx" size %d val %lx\n", addr, size, data); -+ if (8 == size) { -+ switch (offset) { -+ case LS7A_IOAPIC_INT_MASK_OFFSET: -+ a->int_mask = data; -+ update_irq(a); -+ break; -+ case LS7A_IOAPIC_INT_STATUS_OFFSET: -+ a->intisr = data; -+ break; -+ case LS7A_IOAPIC_INT_EDGE_OFFSET: -+ a->intedge = data; -+ break; -+ case LS7A_IOAPIC_INT_CLEAR_OFFSET: -+ a->intisr &= (~data); -+ update_irq(a); -+ break; -+ case LS7A_IOAPIC_INT_POL_OFFSET: -+ a->int_polarity = data; -+ break; -+ case LS7A_IOAPIC_HTMSI_EN_OFFSET: -+ a->htmsi_en = data; -+ break; -+ case LS7A_AUTO_CTRL0_OFFSET: -+ case LS7A_AUTO_CTRL1_OFFSET: -+ break; -+ default: -+ break; -+ } -+ } else if (1 == size) { -+ if (offset >= LS7A_IOAPIC_HTMSI_VEC_OFFSET) { -+ offset_tmp = offset - LS7A_IOAPIC_HTMSI_VEC_OFFSET; -+ if (offset_tmp >= 0 && offset_tmp < 64) { -+ a->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); -+ } -+ } else if (offset >= LS7A_IOAPIC_ROUTE_ENTRY_OFFSET) { -+ offset_tmp = offset - LS7A_IOAPIC_ROUTE_ENTRY_OFFSET; -+ if (offset_tmp >= 0 && offset_tmp < 64) { -+ a->route_entry[offset_tmp] = (uint8_t)(data & 0xff); -+ } -+ } -+ } -+} -+ -+static const MemoryRegionOps ls7a_apic_ops = { -+ .read = ls7a_apic_reg_read, -+ .write = ls7a_apic_reg_write, -+ .valid = { -+ .min_access_size = 1, -+ .max_access_size = 8, -+ }, -+ .impl = { -+ .min_access_size = 1, -+ .max_access_size = 8, -+ }, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+}; -+ -+static int kvm_ls7a_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ LS7AApicState *s = opaque; -+ struct loongarch_kvm_irqchip *chip; -+ struct ls7a_ioapic_state *state; -+ int ret, i, length; -+ -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+ -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct ls7a_ioapic_state); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS7A_IOAPIC; -+ chip->len = length; -+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ state = (struct ls7a_ioapic_state *)chip->data; -+ s->int_id = state->int_id; -+ s->int_mask = state->int_mask; -+ s->htmsi_en = state->htmsi_en; -+ s->intedge = state->intedge; -+ s->intclr = state->intclr; -+ s->auto_crtl0 = state->auto_crtl0; -+ s->auto_crtl1 = state->auto_crtl1; -+ for (i = 0; i < 64; i++) { -+ s->route_entry[i] = state->route_entry[i]; -+ s->htmsi_vector[i] = state->htmsi_vector[i]; -+ } -+ s->intisr_chip0 = state->intisr_chip0; -+ s->intisr_chip1 = state->intisr_chip1; -+ s->intirr = state->intirr; -+ s->intisr = state->intisr; -+ s->int_polarity = state->int_polarity; -+ g_free(chip); -+#endif -+ return 0; -+} -+ -+static int kvm_ls7a_post_load(void *opaque, int version) -+{ -+#ifdef CONFIG_KVM -+ LS7AApicState *s = opaque; -+ struct loongarch_kvm_irqchip *chip; -+ struct ls7a_ioapic_state *state; -+ int ret, i, length; -+ -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct ls7a_ioapic_state); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS7A_IOAPIC; -+ chip->len = length; -+ -+ state = (struct ls7a_ioapic_state *)chip->data; -+ state->int_id = s->int_id; -+ state->int_mask = s->int_mask; -+ state->htmsi_en = s->htmsi_en; -+ state->intedge = s->intedge; -+ state->intclr = s->intclr; -+ state->auto_crtl0 = s->auto_crtl0; -+ state->auto_crtl1 = s->auto_crtl1; -+ for (i = 0; i < 64; i++) { -+ state->route_entry[i] = s->route_entry[i]; -+ state->htmsi_vector[i] = s->htmsi_vector[i]; -+ } -+ state->intisr_chip0 = s->intisr_chip0; -+ state->intisr_chip1 = s->intisr_chip1; -+ state->last_intirr = 0; -+ state->intirr = s->intirr; -+ state->intisr = s->intisr; -+ state->int_polarity = s->int_polarity; -+ -+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ g_free(chip); -+#endif -+ return 0; -+} -+ -+static void ls7a_apic_reset(DeviceState *d) -+{ -+ LS7AApicState *s = LS7A_APIC(d); -+ int i; -+ -+ s->int_id = 0x001f000107000000; -+ s->int_mask = 0xffffffffffffffff; -+ s->htmsi_en = 0x0; -+ s->intedge = 0x0; -+ s->intclr = 0x0; -+ s->auto_crtl0 = 0x0; -+ s->auto_crtl1 = 0x0; -+ for (i = 0; i < 64; i++) { -+ s->route_entry[i] = 0x1; -+ s->htmsi_vector[i] = 0x0; -+ } -+ s->intisr_chip0 = 0x0; -+ s->intisr_chip1 = 0x0; -+ s->intirr = 0x0; -+ s->intisr = 0x0; -+ s->int_polarity = 0x0; -+ kvm_ls7a_post_load(s, 0); -+} -+ -+static void ls7a_apic_init(Object *obj) -+{ -+ DeviceState *dev = DEVICE(obj); -+ LS7AApicState *s = LS7A_APIC(obj); -+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj); -+ int tmp; -+ memory_region_init_io(&s->iomem, obj, &ls7a_apic_ops, s, TYPE_LS7A_APIC, 0x1000); -+ sysbus_init_mmio(sbd, &s->iomem); -+ for (tmp = 0; tmp < 257; tmp++) { -+ sysbus_init_irq(sbd, &s->parent_irq[tmp]); -+ } -+ qdev_init_gpio_in(dev, irq_handler, 64); -+} -+ -+static const VMStateDescription vmstate_ls7a_apic = { -+ .name = TYPE_LS7A_APIC, -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = kvm_ls7a_pre_save, -+ .post_load = kvm_ls7a_post_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT64(int_mask, LS7AApicState), -+ VMSTATE_UINT64(htmsi_en, LS7AApicState), -+ VMSTATE_UINT64(intedge, LS7AApicState), -+ VMSTATE_UINT64(intclr, LS7AApicState), -+ VMSTATE_UINT64(auto_crtl0, LS7AApicState), -+ VMSTATE_UINT64(auto_crtl1, LS7AApicState), -+ VMSTATE_UINT8_ARRAY(route_entry, LS7AApicState, 64), -+ VMSTATE_UINT8_ARRAY(htmsi_vector, LS7AApicState, 64), -+ VMSTATE_UINT64(intisr_chip0, LS7AApicState), -+ VMSTATE_UINT64(intisr_chip1, LS7AApicState), -+ VMSTATE_UINT64(last_intirr, LS7AApicState), -+ VMSTATE_UINT64(intirr, LS7AApicState), -+ VMSTATE_UINT64(intisr, LS7AApicState), -+ VMSTATE_UINT64(int_polarity, LS7AApicState), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static void ls7a_apic_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ -+ dc->reset = ls7a_apic_reset; -+ dc->vmsd = &vmstate_ls7a_apic; -+} -+ -+static const TypeInfo ls7a_apic_info = { -+ .name = TYPE_LS7A_APIC, -+ .parent = TYPE_SYS_BUS_DEVICE, -+ .instance_size = sizeof(LS7AApicState), -+ .instance_init = ls7a_apic_init, -+ .class_init = ls7a_apic_class_init, -+}; -+ -+static void ls7a_apic_register_types(void) -+{ -+ type_register_static(&ls7a_apic_info); -+} -+ -+type_init(ls7a_apic_register_types) -diff --git a/hw/loongarch/iocsr.c b/hw/loongarch/iocsr.c -new file mode 100644 -index 000000000..14521c2d5 ---- /dev/null -+++ b/hw/loongarch/iocsr.c -@@ -0,0 +1,219 @@ -+/* -+ * LOONGARCH IOCSR support -+ * -+ * Copyright (c) 2021 Loongarch Technology -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/sysbus.h" -+#include "qemu/log.h" -+#include "sysemu/kvm.h" -+#include "linux/kvm.h" -+#include "migration/vmstate.h" -+#include "hw/boards.h" -+#include "hw/loongarch/larch.h" -+ -+#define BIT_ULL(nr) (1ULL << (nr)) -+#define LOONGARCH_IOCSR_FEATURES 0x8 -+#define IOCSRF_TEMP BIT_ULL(0) -+#define IOCSRF_NODECNT BIT_ULL(1) -+#define IOCSRF_MSI BIT_ULL(2) -+#define IOCSRF_EXTIOI BIT_ULL(3) -+#define IOCSRF_CSRIPI BIT_ULL(4) -+#define IOCSRF_FREQCSR BIT_ULL(5) -+#define IOCSRF_FREQSCALE BIT_ULL(6) -+#define IOCSRF_DVFSV1 BIT_ULL(7) -+#define IOCSRF_GMOD BIT_ULL(9) -+#define IOCSRF_VM BIT_ULL(11) -+#define LOONGARCH_IOCSR_VENDOR 0x10 -+#define LOONGARCH_IOCSR_CPUNAME 0x20 -+#define LOONGARCH_IOCSR_NODECNT 0x408 -+#define LOONGARCH_IOCSR_MISC_FUNC 0x420 -+#define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21) -+#define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48) -+ -+enum { -+ IOCSR_FEATURES, -+ IOCSR_VENDOR, -+ IOCSR_CPUNAME, -+ IOCSR_NODECNT, -+ IOCSR_MISC_FUNC, -+ IOCSR_MAX -+}; -+ -+static uint32_t iocsr_array[IOCSR_MAX] = { -+ [IOCSR_FEATURES] = LOONGARCH_IOCSR_FEATURES, -+ [IOCSR_VENDOR] = LOONGARCH_IOCSR_VENDOR, -+ [IOCSR_CPUNAME] = LOONGARCH_IOCSR_CPUNAME, -+ [IOCSR_NODECNT] = LOONGARCH_IOCSR_NODECNT, -+ [IOCSR_MISC_FUNC] = LOONGARCH_IOCSR_MISC_FUNC, -+}; -+ -+ -+#define TYPE_IOCSR "iocsr" -+#define IOCSR(obj) OBJECT_CHECK(IOCSRState, (obj), TYPE_IOCSR) -+ -+typedef struct IOCSRState { -+ SysBusDevice parent_obj; -+ uint64_t iocsr_val[IOCSR_MAX]; -+} IOCSRState; -+ -+IOCSRState iocsr_init = { -+ .iocsr_val = { -+ IOCSRF_NODECNT | IOCSRF_MSI | IOCSRF_EXTIOI -+ | IOCSRF_CSRIPI | IOCSRF_GMOD | IOCSRF_VM, -+ 0x6e6f73676e6f6f4c, /* Loongson */ -+ 0x303030354133, /*3A5000*/ -+ 0x4, -+ 0x0, -+ } -+}; -+ -+static int kvm_iocsr_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ IOCSRState *s = opaque; -+ struct kvm_iocsr_entry entry; -+ int i = 0; -+ for (i = 0; i < IOCSR_MAX; i++) { -+ entry.addr = iocsr_array[i]; -+ kvm_vm_ioctl(kvm_state, KVM_LOONGARCH_GET_IOCSR, &entry); -+ s->iocsr_val[i] = entry.data; -+ } -+#endif -+ return 0; -+} -+ -+static int kvm_iocsr_post_load(void *opaque, int version) -+{ -+#ifdef CONFIG_KVM -+ IOCSRState *s = opaque; -+ struct kvm_iocsr_entry entry; -+ int i = 0; -+ -+ if (!kvm_enabled()) { -+ return 0; -+ } -+ -+ for (i = 0; i < IOCSR_MAX; i++) { -+ entry.addr = iocsr_array[i]; -+ entry.data = s->iocsr_val[i]; -+ kvm_vm_ioctl(kvm_state, KVM_LOONGARCH_SET_IOCSR, &entry); -+ } -+#endif -+ return 0; -+} -+ -+static void iocsr_reset(DeviceState *d) -+{ -+ IOCSRState *s = IOCSR(d); -+ int i; -+ -+ for (i = 0; i < IOCSR_MAX; i++) { -+ s->iocsr_val[i] = iocsr_init.iocsr_val[i]; -+ } -+ kvm_iocsr_post_load(s, 0); -+} -+static void init_vendor_cpuname(uint64_t *vendor, -+ uint64_t *cpu_name, char *cpuname) -+{ -+ int i = 0, len = 0; -+ char *index = NULL, *index_end = NULL; -+ char *vendor_c = (char *)vendor; -+ char *cpu_name_c = (char *)cpu_name; -+ -+ index = strstr(cpuname, "-"); -+ len = strlen(cpuname); -+ if ((index == NULL) || (len <= 0)) { -+ return ; -+ } -+ -+ *vendor = 0; -+ *cpu_name = 0; -+ index_end = cpuname + len; -+ -+ while (((cpuname + i) < index) && (i < sizeof(uint64_t))) { -+ vendor_c[i] = cpuname[i]; -+ i++; -+ } -+ -+ index += 1; -+ i = 0; -+ -+ while (((index + i) < index_end) && (i < sizeof(uint64_t))) { -+ cpu_name_c[i] = index[i]; -+ i++; -+ } -+ -+ return ; -+} -+ -+static void iocsr_instance_init(Object *obj) -+{ -+ IOCSRState *s = IOCSR(obj); -+ int i; -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ -+ init_vendor_cpuname((uint64_t *)&iocsr_init.iocsr_val[IOCSR_VENDOR], -+ (uint64_t *)&iocsr_init.iocsr_val[IOCSR_CPUNAME], -+ lsmc->cpu_name); -+ -+ for (i = 0; i < IOCSR_MAX; i++) { -+ s->iocsr_val[i] = iocsr_init.iocsr_val[i]; -+ } -+} -+ -+static const VMStateDescription vmstate_iocsr = { -+ .name = TYPE_IOCSR, -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = kvm_iocsr_pre_save, -+ .post_load = kvm_iocsr_post_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT64_ARRAY(iocsr_val, IOCSRState, IOCSR_MAX), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static void iocsr_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ -+ dc->reset = iocsr_reset; -+ dc->vmsd = &vmstate_iocsr; -+ -+} -+ -+static const TypeInfo iocsr_info = { -+ .name = TYPE_IOCSR, -+ .parent = TYPE_SYS_BUS_DEVICE, -+ .instance_size = sizeof(IOCSRState), -+ .instance_init = iocsr_instance_init, -+ .class_init = iocsr_class_init, -+}; -+ -+static void iocsr_register_types(void) -+{ -+ type_register_static(&iocsr_info); -+} -+ -+type_init(iocsr_register_types) -diff --git a/hw/loongarch/ipi.c b/hw/loongarch/ipi.c -new file mode 100644 -index 000000000..ade182abc ---- /dev/null -+++ b/hw/loongarch/ipi.c -@@ -0,0 +1,267 @@ -+#include "qemu/osdep.h" -+#include "qemu/units.h" -+#include "qapi/error.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/loongarch/cpudevs.h" -+#include "sysemu/sysemu.h" -+#include "sysemu/cpus.h" -+#include "sysemu/kvm.h" -+#include "hw/core/cpu.h" -+#include "qemu/log.h" -+#include "hw/loongarch/bios.h" -+#include "elf.h" -+#include "linux/kvm.h" -+#include "hw/loongarch/larch.h" -+#include "hw/loongarch/ls7a.h" -+#include "migration/vmstate.h" -+ -+static int gipi_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ gipiState *state = opaque; -+ struct loongarch_gipiState *kstate; -+ struct loongarch_kvm_irqchip *chip; -+ int ret, i, j, length; -+#endif -+ -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+ -+#ifdef CONFIG_KVM -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct loongarch_gipiState); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS3A_GIPI; -+ chip->len = length; -+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ -+ kstate = (struct loongarch_gipiState *)chip->data; -+ -+ for (i = 0; i < MAX_GIPI_CORE_NUM; i++) { -+ state->core[i].status = kstate->core[i].status; -+ state->core[i].en = kstate->core[i].en; -+ state->core[i].set = kstate->core[i].set; -+ state->core[i].clear = kstate->core[i].clear; -+ for (j = 0; j < MAX_GIPI_MBX_NUM; j++) { -+ state->core[i].buf[j] = kstate->core[i].buf[j]; -+ } -+ } -+ g_free(chip); -+#endif -+ -+ return 0; -+} -+ -+static int gipi_post_load(void *opaque, int version) -+{ -+#ifdef CONFIG_KVM -+ gipiState *state = opaque; -+ struct loongarch_gipiState *kstate; -+ struct loongarch_kvm_irqchip *chip; -+ int ret, i, j, length; -+#endif -+ -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+ -+#ifdef CONFIG_KVM -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct loongarch_gipiState); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS3A_GIPI; -+ chip->len = length; -+ kstate = (struct loongarch_gipiState *)chip->data; -+ -+ for (i = 0; i < MAX_GIPI_CORE_NUM; i++) { -+ kstate->core[i].status = state->core[i].status; -+ kstate->core[i].en = state->core[i].en; -+ kstate->core[i].set = state->core[i].set; -+ kstate->core[i].clear = state->core[i].clear; -+ for (j = 0; j < MAX_GIPI_MBX_NUM; j++) { -+ kstate->core[i].buf[j] = state->core[i].buf[j]; -+ } -+ } -+ -+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ g_free(chip); -+#endif -+ -+ return 0; -+} -+ -+static const VMStateDescription vmstate_gipi_core = { -+ .name = "gipi-single", -+ .version_id = 0, -+ .minimum_version_id = 0, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT32(status, gipi_core), -+ VMSTATE_UINT32(en, gipi_core), -+ VMSTATE_UINT32(set, gipi_core), -+ VMSTATE_UINT32(clear, gipi_core), -+ VMSTATE_UINT64_ARRAY(buf, gipi_core, MAX_GIPI_MBX_NUM), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const VMStateDescription vmstate_gipi = { -+ .name = "gipi", -+ .pre_save = gipi_pre_save, -+ .post_load = gipi_post_load, -+ .version_id = 0, -+ .minimum_version_id = 0, -+ .fields = (VMStateField[]) { -+ VMSTATE_STRUCT_ARRAY(core, gipiState, MAX_GIPI_CORE_NUM, 0, -+ vmstate_gipi_core, gipi_core), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+static void gipi_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) -+{ -+ gipi_core *s = opaque; -+ gipi_core *ss; -+ void *pbuf; -+ uint32_t cpu, action_data, mailaddr; -+ LoongarchMachineState *ms = LoongarchMACHINE(qdev_get_machine()); -+ -+ if ((size != 4) && (size != 8)) { -+ hw_error("size not 4 and not 8"); -+ } -+ addr &= 0xff; -+ switch (addr) { -+ case CORE0_STATUS_OFF: -+ hw_error("CORE0_STATUS_OFF Can't be write\n"); -+ break; -+ case CORE0_EN_OFF: -+ s->en = val; -+ break; -+ case CORE0_IPI_SEND: -+ cpu = (val >> 16) & 0x3ff; -+ action_data = 1UL << (val & 0x1f); -+ ss = &ms->gipi->core[cpu]; -+ ss->status |= action_data; -+ if (ss->status != 0) { -+ qemu_irq_raise(ss->irq); -+ } -+ break; -+ case CORE0_MAIL_SEND: -+ cpu = (val >> 16) & 0x3ff; -+ mailaddr = (val >> 2) & 0x7; -+ ss = &ms->gipi->core[cpu]; -+ pbuf = (void *)ss->buf + mailaddr * 4; -+ *(unsigned int *)pbuf = (val >> 32); -+ break; -+ case CORE0_SET_OFF: -+ hw_error("CORE0_SET_OFF Can't be write\n"); -+ break; -+ case CORE0_CLEAR_OFF: -+ s->status ^= val; -+ if (s->status == 0) { -+ qemu_irq_lower(s->irq); -+ } -+ break; -+ case 0x20 ... 0x3c: -+ pbuf = (void *)s->buf + (addr - 0x20); -+ if (size == 1) { -+ *(unsigned char *)pbuf = (unsigned char)val; -+ } else if (size == 2) { -+ *(unsigned short *)pbuf = (unsigned short)val; -+ } else if (size == 4) { -+ *(unsigned int *)pbuf = (unsigned int)val; -+ } else if (size == 8) { -+ *(unsigned long *)pbuf = (unsigned long)val; -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static uint64_t gipi_readl(void *opaque, hwaddr addr, unsigned size) -+{ -+ gipi_core *s = opaque; -+ uint64_t ret = 0; -+ void *pbuf; -+ -+ addr &= 0xff; -+ if ((size != 4) && (size != 8)) { -+ hw_error("size not 4 and not 8 size:%d\n", size); -+ } -+ switch (addr) { -+ case CORE0_STATUS_OFF: -+ ret = s->status; -+ break; -+ case CORE0_EN_OFF: -+ ret = s->en; -+ break; -+ case CORE0_SET_OFF: -+ ret = 0; -+ break; -+ case CORE0_CLEAR_OFF: -+ ret = 0; -+ break; -+ case 0x20 ... 0x3c: -+ pbuf = (void *)s->buf + (addr - 0x20); -+ if (size == 1) { -+ ret = *(unsigned char *)pbuf; -+ } else if (size == 2) { -+ ret = *(unsigned short *)pbuf; -+ } else if (size == 4) { -+ ret = *(unsigned int *)pbuf; -+ } else if (size == 8) { -+ ret = *(unsigned long *)pbuf; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+static const MemoryRegionOps gipi_ops = { -+ .read = gipi_readl, -+ .write = gipi_writel, -+ .valid = { -+ .min_access_size = 4, -+ .max_access_size = 8, -+ }, -+ .impl = { -+ .min_access_size = 4, -+ .max_access_size = 8, -+ }, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+}; -+ -+int cpu_init_ipi(LoongarchMachineState *ms, qemu_irq parent, int cpu) -+{ -+ hwaddr addr; -+ MemoryRegion *region; -+ char str[32]; -+ -+ if (ms->gipi == NULL) { -+ ms->gipi = g_malloc0(sizeof(gipiState)); -+ vmstate_register(NULL, 0, &vmstate_gipi, ms->gipi); -+ } -+ -+ ms->gipi->core[cpu].irq = parent; -+ -+ addr = SMP_GIPI_MAILBOX | (cpu << 8); -+ region = g_new(MemoryRegion, 1); -+ sprintf(str, "gipi%d", cpu); -+ memory_region_init_io(region, NULL, &gipi_ops, &ms->gipi->core[cpu], str, 0x100); -+ memory_region_add_subregion(get_system_memory(), addr, region); -+ return 0; -+} -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -new file mode 100644 -index 000000000..3db269274 ---- /dev/null -+++ b/hw/loongarch/larch_3a.c -@@ -0,0 +1,2026 @@ -+/* -+ * QEMU loongarch 3a develop board emulation -+ * -+ * Copyright (C) 2013-2014 qiaochong -+ * Copyright (C) 2016-2017 zhangshuangshuang -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#include "qemu/osdep.h" -+#include "qemu/units.h" -+#include "qapi/error.h" -+#include "qemu/datadir.h" -+#include "hw/hw.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/i386/pc.h" -+#include "hw/char/serial.h" -+#include "hw/isa/isa.h" -+#include "hw/qdev-core.h" -+#include "sysemu/sysemu.h" -+#include "sysemu/runstate.h" -+#include "sysemu/reset.h" -+#include "migration/vmstate.h" -+#include "sysemu/cpus.h" -+#include "hw/boards.h" -+#include "qemu/log.h" -+#include "hw/loongarch/bios.h" -+#include "hw/loader.h" -+#include "elf.h" -+#include "exec/address-spaces.h" -+#include "hw/ide.h" -+#include "hw/pci/pci_host.h" -+#include "hw/pci/msi.h" -+#include "linux/kvm.h" -+#include "sysemu/kvm.h" -+#include "sysemu/numa.h" -+#include "hw/rtc/mc146818rtc.h" -+#include "hw/irq.h" -+#include "net/net.h" -+#include "hw/timer/i8254.h" -+#include "hw/loongarch/larch.h" -+#include "hw/loongarch/ls7a.h" -+#include "hw/nvram/fw_cfg.h" -+#include "hw/firmware/smbios.h" -+#include "acpi-build.h" -+#include -+#include -+#include "sysemu/block-backend.h" -+#include "hw/block/flash.h" -+#include "sysemu/device_tree.h" -+#include "qapi/visitor.h" -+#include "qapi/qapi-visit-common.h" -+ -+#include -+ -+#define DMA64_SUPPORTED 0x2 -+#define MAX_IDE_BUS 2 -+ -+#define BOOTPARAM_PHYADDR 0x0ff00000ULL -+#define BOOTPARAM_ADDR (0x9000000000000000ULL + BOOTPARAM_PHYADDR) -+#define SMBIOS_PHYSICAL_ADDRESS 0x0fe00000 -+#define SMBIOS_SIZE_LIMIT 0x200000 -+#define RESERVED_SIZE_LIMIT 0x1100000 -+#define COMMAND_LINE_SIZE 4096 -+#define FW_CONF_ADDR 0x0fff0000 -+ -+#define PHYS_TO_VIRT(x) ((x) | 0x9000000000000000ULL) -+ -+#define TARGET_REALPAGE_MASK (TARGET_PAGE_MASK << 2) -+ -+#ifdef CONFIG_KVM -+#define LS_ISA_IO_SIZE 0x02000000 -+#define LS_ISA_MEM_SIZE 0x40000000 -+#else -+#define LS_ISA_IO_SIZE 0x00010000 -+#define LS_ISA_MEM_SIZE 0x01000000 -+#endif -+ -+#ifdef CONFIG_KVM -+#define align(x) (((x) + 63) & ~63) -+#else -+#define align(x) (((x) + 15) & ~15) -+#endif -+ -+#define DEBUG_LOONGARCH3A 0 -+#define FLASH_SECTOR_SIZE 4096 -+ -+#define DPRINTF(fmt, ...) \ -+ do { if (DEBUG_LOONGARCH3A) { fprintf(stderr, fmt, ## __VA_ARGS__); } } while (0) -+ -+#define DEFINE_LS3A5K_MACHINE(suffix, name, optionfn) \ -+ static void ls3a5k_init_##suffix(MachineState *machine) \ -+ { \ -+ ls3a5k_init(machine); \ -+ } \ -+ DEFINE_LOONGARCH_MACHINE(suffix, name, ls3a5k_init_##suffix, optionfn) -+ -+struct efi_memory_map_loongarch { -+ uint16_t vers; /* version of efi_memory_map */ -+ uint32_t nr_map; /* number of memory_maps */ -+ uint32_t mem_freq; /* memory frequence */ -+ struct mem_map { -+ uint32_t node_id; /* node_id which memory attached to */ -+ uint32_t mem_type; /* system memory, pci memory, pci io, etc. */ -+ uint64_t mem_start; /* memory map start address */ -+ uint32_t mem_size; /* each memory_map size, not the total size */ -+ } map[128]; -+} __attribute__((packed)); -+ -+enum loongarch_cpu_type { -+ Loongson3 = 0x1, -+ Loongson3_comp = 0x2 -+}; -+ -+struct GlobalProperty loongarch_compat[] = { -+ { -+ .driver = "rtl8139", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "e1000", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "virtio-net-pci", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "qxl-vga", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "VGA", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "cirrus-vga", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "virtio-vga", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "vmware-svga", -+ .property = "romfile", -+ .value = "", -+ }, -+}; -+const size_t loongarch_compat_len = G_N_ELEMENTS(loongarch_compat); -+ -+/* -+ * Capability and feature descriptor structure for LOONGARCH CPU -+ */ -+struct efi_cpuinfo_loongarch { -+ uint16_t vers; /* version of efi_cpuinfo_loongarch */ -+ uint32_t processor_id; /* PRID, e.g. 6305, 6306 */ -+ enum loongarch_cpu_type cputype; /* 3A, 3B, etc. */ -+ uint32_t total_node; /* num of total numa nodes */ -+ uint16_t cpu_startup_core_id; /* Core id */ -+ uint16_t reserved_cores_mask; -+ uint32_t cpu_clock_freq; /* cpu_clock */ -+ uint32_t nr_cpus; -+} __attribute__((packed)); -+ -+#define MAX_UARTS 64 -+struct uart_device { -+ uint32_t iotype; /* see include/linux/serial_core.h */ -+ uint32_t uartclk; -+ uint32_t int_offset; -+ uint64_t uart_base; -+} __attribute__((packed)); -+ -+#define MAX_SENSORS 64 -+#define SENSOR_TEMPER 0x00000001 -+#define SENSOR_VOLTAGE 0x00000002 -+#define SENSOR_FAN 0x00000004 -+struct sensor_device { -+ char name[32]; /* a formal name */ -+ char label[64]; /* a flexible description */ -+ uint32_t type; /* SENSOR_* */ -+ uint32_t id; /* instance id of a sensor-class */ -+ uint32_t fan_policy; /* see arch/loongarch/include/ -+ asm/mach-loongarch/loongarch_hwmon.h */ -+ uint32_t fan_percent;/* only for constant speed policy */ -+ uint64_t base_addr; /* base address of device registers */ -+} __attribute__((packed)); -+ -+struct system_loongarch { -+ uint16_t vers; /* version of system_loongarch */ -+ uint32_t ccnuma_smp; /* 0: no numa; 1: has numa */ -+ uint32_t sing_double_channel;/* 1:single; 2:double */ -+ uint32_t nr_uarts; -+ struct uart_device uarts[MAX_UARTS]; -+ uint32_t nr_sensors; -+ struct sensor_device sensors[MAX_SENSORS]; -+ char has_ec; -+ char ec_name[32]; -+ uint64_t ec_base_addr; -+ char has_tcm; -+ char tcm_name[32]; -+ uint64_t tcm_base_addr; -+ uint64_t workarounds; /* see workarounds.h */ -+} __attribute__((packed)); -+ -+struct irq_source_routing_table { -+ uint16_t vers; -+ uint16_t size; -+ uint16_t rtr_bus; -+ uint16_t rtr_devfn; -+ uint32_t vendor; -+ uint32_t device; -+ uint32_t PIC_type; /* conform use HT or PCI to route to CPU-PIC */ -+ uint64_t ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ -+ uint64_t ht_enable; /* irqs used in this PIC */ -+ uint32_t node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ -+ uint64_t pci_mem_start_addr; -+ uint64_t pci_mem_end_addr; -+ uint64_t pci_io_start_addr; -+ uint64_t pci_io_end_addr; -+ uint64_t pci_config_addr; -+ uint32_t dma_mask_bits; -+ uint16_t dma_noncoherent; -+} __attribute__((packed)); -+ -+struct interface_info { -+ uint16_t vers; /* version of the specificition */ -+ uint16_t size; -+ uint8_t flag; -+ char description[64]; -+} __attribute__((packed)); -+ -+#define MAX_RESOURCE_NUMBER 128 -+struct resource_loongarch { -+ uint64_t start; /* resource start address */ -+ uint64_t end; /* resource end address */ -+ char name[64]; -+ uint32_t flags; -+}; -+ -+struct archdev_data {}; /* arch specific additions */ -+ -+struct board_devices { -+ char name[64]; /* hold the device name */ -+ uint32_t num_resources; /* number of device_resource */ -+ /* for each device's resource */ -+ struct resource_loongarch resource[MAX_RESOURCE_NUMBER]; -+ /* arch specific additions */ -+ struct archdev_data archdata; -+}; -+ -+struct loongarch_special_attribute { -+ uint16_t vers; /* version of this special */ -+ char special_name[64]; /* special_atribute_name */ -+ uint32_t loongarch_special_type; /* type of special device */ -+ /* for each device's resource */ -+ struct resource_loongarch resource[MAX_RESOURCE_NUMBER]; -+}; -+ -+struct loongarch_params { -+ uint64_t memory_offset; /* efi_memory_map_loongarch struct offset */ -+ uint64_t cpu_offset; /* efi_cpuinfo_loongarch struct offset */ -+ uint64_t system_offset; /* system_loongarch struct offset */ -+ uint64_t irq_offset; /* irq_source_routing_table struct offset */ -+ uint64_t interface_offset; /* interface_info struct offset */ -+ uint64_t special_offset; /* loongarch_special_attribute struct offset */ -+ uint64_t boarddev_table_offset; /* board_devices offset */ -+}; -+ -+struct smbios_tables { -+ uint16_t vers; /* version of smbios */ -+ uint64_t vga_bios; /* vga_bios address */ -+ struct loongarch_params lp; -+}; -+ -+struct efi_reset_system_t { -+ uint64_t ResetCold; -+ uint64_t ResetWarm; -+ uint64_t ResetType; -+ uint64_t Shutdown; -+ uint64_t DoSuspend; /* NULL if not support */ -+}; -+ -+struct efi_loongarch { -+ uint64_t mps; /* MPS table */ -+ uint64_t acpi; /* ACPI table (IA64 ext 0.71) */ -+ uint64_t acpi20; /* ACPI table (ACPI 2.0) */ -+ struct smbios_tables smbios; /* SM BIOS table */ -+ uint64_t sal_systab; /* SAL system table */ -+ uint64_t boot_info; /* boot info table */ -+}; -+ -+struct boot_params { -+ struct efi_loongarch efi; -+ struct efi_reset_system_t reset_system; -+}; -+ -+static struct _loaderparams { -+ unsigned long ram_size; -+ const char *kernel_filename; -+ const char *kernel_cmdline; -+ const char *initrd_filename; -+ unsigned long a0, a1, a2; -+} loaderparams; -+ -+static struct _firmware_config { -+ unsigned long ram_size; -+ unsigned int mem_freq; -+ unsigned int cpu_nr; -+ unsigned int cpu_clock_freq; -+} fw_config; -+ -+struct la_memmap_entry { -+ uint64_t address; -+ uint64_t length; -+ uint32_t type; -+ uint32_t reserved; -+} ; -+ -+static void *boot_params_buf; -+static void *boot_params_p; -+static struct la_memmap_entry *la_memmap_table; -+static unsigned la_memmap_entries; -+ -+CPULOONGARCHState *cpu_states[LOONGARCH_MAX_VCPUS]; -+ -+struct kvm_cpucfg ls3a5k_cpucfgs = { -+ .cpucfg[LOONGARCH_CPUCFG0] = CPUCFG0_3A5000_PRID, -+ .cpucfg[LOONGARCH_CPUCFG1] = CPUCFG1_ISGR64 | CPUCFG1_PAGING | -+ CPUCFG1_IOCSR | CPUCFG1_PABITS | CPUCFG1_VABITS | CPUCFG1_UAL | -+ CPUCFG1_RI | CPUCFG1_XI | CPUCFG1_RPLV | CPUCFG1_HUGEPG | -+ CPUCFG1_IOCSRBRD, -+ .cpucfg[LOONGARCH_CPUCFG2] = CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP | -+ CPUCFG2_FPVERS | CPUCFG2_LSX | CPUCFG2_LASX | CPUCFG2_COMPLEX | -+ CPUCFG2_CRYPTO | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | CPUCFG2_LSPW | -+ CPUCFG2_LAM, -+ .cpucfg[LOONGARCH_CPUCFG3] = CPUCFG3_CCDMA | CPUCFG3_SFB | CPUCFG3_UCACC | -+ CPUCFG3_LLEXC | CPUCFG3_SCDLY | CPUCFG3_LLDBAR | CPUCFG3_ITLBT | -+ CPUCFG3_ICACHET | CPUCFG3_SPW_LVL | CPUCFG3_SPW_HG_HF | CPUCFG3_RVA | -+ CPUCFG3_RVAMAX, -+ .cpucfg[LOONGARCH_CPUCFG4] = CCFREQ_100M, -+ .cpucfg[LOONGARCH_CPUCFG5] = CPUCFG5_CCMUL | CPUCFG5_CCDIV, -+ .cpucfg[LOONGARCH_CPUCFG6] = CPUCFG6_PMP | CPUCFG6_PAMVER | CPUCFG6_PMNUM | -+ CPUCFG6_PMBITS | CPUCFG6_UPM, -+ .cpucfg[LOONGARCH_CPUCFG16] = CPUCFG16_L1_IUPRE | CPUCFG16_L1_DPRE | -+ CPUCFG16_L2_IUPRE | CPUCFG16_L2_IUUNIFY | CPUCFG16_L2_IUPRIV | -+ CPUCFG16_L3_IUPRE | CPUCFG16_L3_IUUNIFY | CPUCFG16_L3_IUINCL, -+ .cpucfg[LOONGARCH_CPUCFG17] = CPUCFG17_L1I_WAYS_M | CPUCFG17_L1I_SETS_M | -+ CPUCFG17_L1I_SIZE_M, -+ .cpucfg[LOONGARCH_CPUCFG18] = CPUCFG18_L1D_WAYS_M | CPUCFG18_L1D_SETS_M | -+ CPUCFG18_L1D_SIZE_M, -+ .cpucfg[LOONGARCH_CPUCFG19] = CPUCFG19_L2_WAYS_M | CPUCFG19_L2_SETS_M | -+ CPUCFG19_L2_SIZE_M, -+ .cpucfg[LOONGARCH_CPUCFG20] = CPUCFG20_L3_WAYS_M | CPUCFG20_L3_SETS_M | -+ CPUCFG20_L3_SIZE_M, -+}; -+ -+bool loongarch_is_acpi_enabled(LoongarchMachineState *vms) -+{ -+ if (vms->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 *lsms = LoongarchMACHINE(obj); -+ OnOffAuto acpi = lsms->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 *lsms = LoongarchMACHINE(obj); -+ -+ visit_type_OnOffAuto(v, name, &lsms->acpi, errp); -+} -+int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) -+{ -+ int i; -+ -+ for (i = 0; i < la_memmap_entries; i++) { -+ if (la_memmap_table[i].address == address) { -+ fprintf(stderr, "%s address:0x%lx length:0x%lx already exists\n", -+ __func__, address, length); -+ return 0; -+ } -+ } -+ -+ la_memmap_table = g_renew(struct la_memmap_entry, la_memmap_table, -+ la_memmap_entries + 1); -+ la_memmap_table[la_memmap_entries].address = cpu_to_le64(address); -+ la_memmap_table[la_memmap_entries].length = cpu_to_le64(length); -+ la_memmap_table[la_memmap_entries].type = cpu_to_le32(type); -+ la_memmap_entries++; -+ -+ return la_memmap_entries; -+} -+ -+static ram_addr_t get_hotplug_membase(ram_addr_t ram_size) -+{ -+ ram_addr_t sstart; -+ -+ if (ram_size <= 0x10000000) { -+ sstart = 0x90000000; -+ } else { -+ sstart = 0x90000000 + ROUND_UP((ram_size - 0x10000000), -+ LOONGARCH_HOTPLUG_MEM_ALIGN); -+ } -+ return sstart; -+} -+ -+static struct efi_memory_map_loongarch *init_memory_map(void *g_map) -+{ -+ struct efi_memory_map_loongarch *emap = g_map; -+ -+ emap->nr_map = 4; -+ emap->mem_freq = 266000000; -+ -+ emap->map[0].node_id = 0; -+ emap->map[0].mem_type = 1; -+ emap->map[0].mem_start = 0x0; -+#ifdef CONFIG_KVM -+ emap->map[0].mem_size = (loaderparams.ram_size > 0x10000000 -+ ? 256 : (loaderparams.ram_size >> 20)) - 18; -+#else -+ emap->map[0].mem_size = atoi(getenv("memsize")); -+#endif -+ -+ emap->map[1].node_id = 0; -+ emap->map[1].mem_type = 2; -+ emap->map[1].mem_start = 0x90000000; -+#ifdef CONFIG_KVM -+ emap->map[1].mem_size = (loaderparams.ram_size > 0x10000000 -+ ? (loaderparams.ram_size >> 20) - 256 : 0); -+#else -+ emap->map[1].mem_size = atoi(getenv("highmemsize")); -+#endif -+ -+ /* support for smbios */ -+ emap->map[2].node_id = 0; -+ emap->map[2].mem_type = 10; -+ emap->map[2].mem_start = SMBIOS_PHYSICAL_ADDRESS; -+ emap->map[2].mem_size = SMBIOS_SIZE_LIMIT >> 20; -+ -+ emap->map[3].node_id = 0; -+ emap->map[3].mem_type = 3; -+ emap->map[3].mem_start = 0xee00000; -+ emap->map[3].mem_size = RESERVED_SIZE_LIMIT >> 20; -+ -+ return emap; -+} -+ -+static uint64_t get_host_cpu_freq(void) -+{ -+ int fd = 0; -+ char buf[1024]; -+ uint64_t freq = 0, size = 0; -+ char *buf_p; -+ -+ fd = open("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", O_RDONLY); -+ if (fd == -1) { -+ fprintf(stderr, "/sys/devices/system/cpu/cpu0/cpufreq/ \ -+ cpuinfo_max_freq not exist!\n"); -+ fprintf(stderr, "Trying /proc/cpuinfo...\n"); -+ } else { -+ size = read(fd, buf, 16); -+ if (size == -1) { -+ fprintf(stderr, "read err...\n"); -+ } -+ close(fd); -+ freq = (uint64_t)atoi(buf); -+ return freq * 1000; -+ } -+ -+ fd = open("/proc/cpuinfo", O_RDONLY); -+ if (fd == -1) { -+ fprintf(stderr, "Failed to open /proc/cpuinfo!\n"); -+ return 0; -+ } -+ -+ size = read(fd, buf, 1024); -+ if (size == -1) { -+ fprintf(stderr, "read err...\n"); -+ } -+ close(fd); -+ -+ buf_p = strstr(buf, "MHz"); -+ if (buf_p) { -+ while (*buf_p != ':') { -+ buf_p++; -+ } -+ buf_p += 2; -+ } else { -+ buf_p = strstr(buf, "name"); -+ while (*buf_p != '@') { -+ buf_p++; -+ } -+ buf_p += 2; -+ } -+ -+ memcpy(buf, buf_p, 12); -+ buf_p = buf; -+ while ((*buf_p >= '0') && (*buf_p <= '9')) { -+ buf_p++; -+ } -+ *buf_p = '\0'; -+ -+ freq = (uint64_t)atoi(buf); -+ return freq * 1000 * 1000; -+} -+ -+static char *get_host_cpu_model_name(void) -+{ -+ int fd = 0; -+ int size = 0; -+ static char buf[1024]; -+ char *buf_p; -+ -+ fd = open("/proc/cpuinfo", O_RDONLY); -+ if (fd == -1) { -+ fprintf(stderr, "Failed to open /proc/cpuinfo!\n"); -+ return 0; -+ } -+ -+ size = read(fd, buf, 1024); -+ if (size == -1) { -+ fprintf(stderr, "read err...\n"); -+ } -+ close(fd); -+ buf_p = strstr(buf, "name"); -+ -+ while (*buf_p != ':') { -+ buf_p++; -+ } -+ buf_p = buf_p + 2; -+ memcpy(buf, buf_p, 40); -+ buf_p = buf; -+ while (*buf_p != '\n') { -+ buf_p++; -+ } -+ -+ *(buf_p) = '\0'; -+ -+ return buf; -+} -+ -+static void fw_conf_init(unsigned long ramsize) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ int smp_cpus = ms->smp.cpus; -+ fw_config.ram_size = ramsize; -+ fw_config.mem_freq = 266000000; -+ fw_config.cpu_nr = smp_cpus ; -+ fw_config.cpu_clock_freq = get_host_cpu_freq(); -+} -+ -+static struct efi_cpuinfo_loongarch *init_cpu_info(void *g_cpuinfo_loongarch) -+{ -+ struct efi_cpuinfo_loongarch *c = g_cpuinfo_loongarch; -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ int smp_cpus = ms->smp.cpus; -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ -+ if (strstr(lsmc->cpu_name, "5000")) { -+ c->processor_id = 0x14c010; -+ } -+ c->cputype = Loongson3_comp; -+ c->cpu_clock_freq = get_host_cpu_freq(); -+ if (!c->cpu_clock_freq) { -+ c->cpu_clock_freq = 200000000; -+ } -+ c->total_node = 1; -+ c->nr_cpus = smp_cpus; -+ c->cpu_startup_core_id = 0; -+ c->reserved_cores_mask = 0xffff & (0xffff << smp_cpus); -+ -+ return c; -+} -+ -+static struct system_loongarch *init_system_loongarch(void *g_sysitem) -+{ -+ struct system_loongarch *s = g_sysitem; -+ -+ s->ccnuma_smp = 1; -+ s->ccnuma_smp = 0; -+ s->sing_double_channel = 1; -+ -+ return s; -+} -+ -+enum loongarch_irq_source_enum { -+ HT, I8259, UNKNOWN -+}; -+ -+static struct irq_source_routing_table *init_irq_source(void *g_irq_source) -+{ -+ struct irq_source_routing_table *irq_info = g_irq_source; -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ -+ irq_info->PIC_type = HT; -+ irq_info->ht_int_bit = 1 << 24; -+ irq_info->ht_enable = 0x0000d17b; -+ irq_info->node_id = 0; -+ -+ irq_info->pci_mem_start_addr = LS_ISA_MEM_BASE; -+ irq_info->pci_mem_end_addr = irq_info->pci_mem_start_addr + LS_ISA_MEM_SIZE - 1; -+ -+ if (strstr(lsmc->cpu_name, "5000")) { -+ irq_info->pci_io_start_addr = LS3A5K_ISA_IO_BASE; -+ } -+ irq_info->dma_noncoherent = 1; -+ return irq_info; -+} -+ -+static struct interface_info *init_interface_info(void *g_interface) -+{ -+ struct interface_info *inter = g_interface; -+ int flashsize = 0x80000; -+ -+ inter->vers = 0x0001; -+ inter->size = flashsize / 0x400; -+ inter->flag = 1; -+ -+ strcpy(inter->description, "PMON_Version_v2.1"); -+ -+ return inter; -+} -+ -+static struct board_devices *board_devices_info(void *g_board) -+{ -+ struct board_devices *bd = g_board; -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ -+ if (!strcmp(lsmc->bridge_name, "ls7a")) { -+ strcpy(bd->name, "Loongarch-3A-7A-1w-V1.03-demo"); -+ } -+ bd->num_resources = 10; -+ -+ return bd; -+} -+ -+static struct loongarch_special_attribute *init_special_info(void *g_special) -+{ -+ struct loongarch_special_attribute *special = g_special; -+ char update[11] = "2013-01-01"; -+ int VRAM_SIZE = 0x20000; -+ -+ strcpy(special->special_name, update); -+ special->resource[0].flags = 0; -+ special->resource[0].start = 0; -+ special->resource[0].end = VRAM_SIZE; -+ strcpy(special->resource[0].name, "SPMODULE"); -+ special->resource[0].flags |= DMA64_SUPPORTED; -+ -+ return special; -+} -+ -+static void init_loongarch_params(struct loongarch_params *lp) -+{ -+ void *p = boot_params_p; -+ -+ lp->memory_offset = (unsigned long long)init_memory_map(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct efi_memory_map_loongarch)); -+ -+ lp->cpu_offset = (unsigned long long)init_cpu_info(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct efi_cpuinfo_loongarch)); -+ -+ lp->system_offset = (unsigned long long)init_system_loongarch(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct system_loongarch)); -+ -+ lp->irq_offset = (unsigned long long)init_irq_source(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct irq_source_routing_table)); -+ -+ lp->interface_offset = (unsigned long long)init_interface_info(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct interface_info)); -+ -+ lp->boarddev_table_offset = (unsigned long long)board_devices_info(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct board_devices)); -+ -+ lp->special_offset = (unsigned long long)init_special_info(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct loongarch_special_attribute)); -+ -+ boot_params_p = p; -+} -+ -+static void init_smbios(struct smbios_tables *smbios) -+{ -+ smbios->vers = 1; -+ smbios->vga_bios = 1; -+ init_loongarch_params(&(smbios->lp)); -+} -+ -+static void init_efi(struct efi_loongarch *efi) -+{ -+ init_smbios(&(efi->smbios)); -+} -+ -+static int init_boot_param(struct boot_params *bp) -+{ -+ init_efi(&(bp->efi)); -+ -+ return 0; -+} -+ -+static unsigned int ls3a5k_aui_boot_code[] = { -+ 0x0380200d, /* ori $r13,$r0,0x8 */ -+ 0x0400002d, /* csrwr $r13,0x0 */ -+ 0x0401000e, /* csrrd $r14,0x40 */ -+ 0x0343fdce, /* andi $r14,$r14,0xff */ -+ 0x143fc02c, /* lu12i.w $r12,261889(0x1fe01) */ -+ 0x1600000c, /* lu32i.d $r12,0 */ -+ 0x0320018c, /* lu52i.d $r12,$r12,-1792(0x800) */ -+ 0x03400dcf, /* andi $r15,$r14,0x3 */ -+ 0x004121ef, /* slli.d $r15,$r15,0x8 */ -+ 0x00153d8c, /* or $r12,$r12,$r15 */ -+ 0x034031d0, /* andi $r16,$r14,0xc */ -+ 0x0041aa10, /* slli.d $r16,$r16,0x2a */ -+ 0x0015418c, /* or $r12,$r12,$r16 */ -+ 0x28808184, /* ld.w $r4,$r12,32(0x20) */ -+ 0x43fffc9f, /* beqz $r4,0 -4 */ -+ 0x28c08184, /* ld.d $r4,$r12,32(0x20) */ -+ 0x28c0a183, /* ld.d $r3,$r12,40(0x28) */ -+ 0x28c0c182, /* ld.d $r2,$r12,48(0x30) */ -+ 0x28c0e185, /* ld.d $r5,$r12,56(0x38) */ -+ 0x4c000080, /* jirl $r0,$r4,0 */ -+}; -+ -+static int set_bootparam_uefi(ram_addr_t initrd_offset, long initrd_size) -+{ -+ long params_size; -+ char memenv[32]; -+ char highmemenv[32]; -+ void *params_buf; -+ unsigned long *parg_env; -+ int ret = 0; -+ -+ /* Allocate params_buf for command line. */ -+ params_size = 0x100000; -+ params_buf = g_malloc0(params_size); -+ -+ /* -+ * Layout of params_buf looks like this: -+ * argv[0], argv[1], 0, env[0], env[1], ...env[i], 0, -+ * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0 -+ */ -+ parg_env = (void *)params_buf; -+ -+ ret = (3 + 1) * sizeof(target_ulong); -+ *parg_env++ = (BOOTPARAM_ADDR + ret); -+ ret += (1 + snprintf(params_buf + ret, COMMAND_LINE_SIZE - ret, "g")); -+ -+ /* argv1 */ -+ *parg_env++ = BOOTPARAM_ADDR + ret; -+ if (initrd_size > 0) -+ ret += (1 + snprintf(params_buf + ret, COMMAND_LINE_SIZE - ret, -+ "rd_start=0x%llx rd_size=%li %s", -+ PHYS_TO_VIRT((uint32_t)initrd_offset), -+ initrd_size, loaderparams.kernel_cmdline)); -+ else -+ ret += (1 + snprintf(params_buf + ret, COMMAND_LINE_SIZE - ret, "%s", -+ loaderparams.kernel_cmdline)); -+ -+ /* argv2 */ -+ *parg_env++ = 0; -+ -+ /* env */ -+ sprintf(memenv, "%lu", loaderparams.ram_size > 0x10000000 -+ ? 256 : (loaderparams.ram_size >> 20)); -+ sprintf(highmemenv, "%lu", loaderparams.ram_size > 0x10000000 -+ ? (loaderparams.ram_size >> 20) - 256 : 0); -+ -+ setenv("memsize", memenv, 1); -+ setenv("highmemsize", highmemenv, 1); -+ -+ ret = ((ret + 32) & ~31); -+ -+ boot_params_buf = (void *)(params_buf + ret); -+ boot_params_p = boot_params_buf + align(sizeof(struct boot_params)); -+ init_boot_param(boot_params_buf); -+ rom_add_blob_fixed("params", params_buf, params_size, -+ BOOTPARAM_PHYADDR); -+ loaderparams.a0 = 2; -+ loaderparams.a1 = BOOTPARAM_ADDR; -+ loaderparams.a2 = BOOTPARAM_ADDR + ret; -+ -+ return 0; -+} -+ -+static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) -+{ -+ return addr & 0x1fffffffll; -+} -+ -+static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg, -+ uint64_t highram_size, -+ uint64_t phyAddr_initrd) -+{ -+ int64_t entry, kernel_low, kernel_high; -+ long initrd_size = 0; -+ uint64_t initrd_offset = 0; -+ void *cmdline_buf; -+ int ret = 0; -+ -+ ret = load_elf(loaderparams.kernel_filename, NULL, cpu_loongarch_virt_to_phys, NULL, -+ (uint64_t *)&entry, (uint64_t *)&kernel_low, -+ (uint64_t *)&kernel_high, NULL, 0, EM_LOONGARCH, 1, 0); -+ -+ if(0 > ret) { -+ error_report("kernel image load error"); -+ exit(1); -+ } -+ -+ fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ENTRY, entry); -+ -+ if (loaderparams.initrd_filename) { -+ initrd_size = get_image_size(loaderparams.initrd_filename); -+ if (0 < initrd_size) { -+ if (initrd_size > highram_size) { -+ error_report("initrd size is too big, should below %ld MB", -+ highram_size / S_1MiB); -+ /*prevent write io memory address space*/ -+ exit(1); -+ } -+ initrd_offset = (phyAddr_initrd - initrd_size) & TARGET_REALPAGE_MASK; -+ initrd_size = load_image_targphys(loaderparams.initrd_filename, -+ initrd_offset, -+ loaderparams.ram_size - initrd_offset); -+ fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_offset); -+ fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); -+ } else { -+ error_report("initrd image size is error"); -+ } -+ } -+ -+ cmdline_buf = g_malloc0(COMMAND_LINE_SIZE); -+ if (initrd_size > 0) -+ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE, -+ "rd_start=0x%llx rd_size=%li %s", -+ PHYS_TO_VIRT(initrd_offset), -+ initrd_size, loaderparams.kernel_cmdline)); -+ else -+ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE, "%s", -+ loaderparams.kernel_cmdline)); -+ -+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, ret); -+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, (const char *)cmdline_buf); -+ -+ return ; -+} -+ -+static int64_t load_kernel(void) -+{ -+ int64_t entry, kernel_low, kernel_high; -+ long initrd_size = 0; -+ ram_addr_t initrd_offset = 0; -+ -+ load_elf(loaderparams.kernel_filename, NULL, cpu_loongarch_virt_to_phys, NULL, -+ (uint64_t *)&entry, (uint64_t *)&kernel_low, -+ (uint64_t *)&kernel_high, NULL, 0, EM_LOONGARCH, 1, 0); -+ -+ if (loaderparams.initrd_filename) { -+ initrd_size = get_image_size(loaderparams.initrd_filename); -+ -+ if (initrd_size > 0) { -+ initrd_offset = (kernel_high * 4 + ~TARGET_REALPAGE_MASK) -+ & TARGET_REALPAGE_MASK; -+ initrd_size = load_image_targphys(loaderparams.initrd_filename, -+ initrd_offset, -+ loaderparams.ram_size - initrd_offset); -+ } -+ } -+ set_bootparam_uefi(initrd_offset, initrd_size); -+ -+ return entry; -+} -+ -+static void main_cpu_reset(void *opaque) -+{ -+ ResetData *s = (ResetData *)opaque; -+ CPULOONGARCHState *env = &s->cpu->env; -+ -+ cpu_reset(CPU(s->cpu)); -+ env->active_tc.PC = s->vector; -+ env->active_tc.gpr[4] = loaderparams.a0; -+ env->active_tc.gpr[5] = loaderparams.a1; -+ env->active_tc.gpr[6] = loaderparams.a2; -+} -+ -+void slave_cpu_reset(void *opaque) -+{ -+ ResetData *s = (ResetData *)opaque; -+ -+ cpu_reset(CPU(s->cpu)); -+} -+ -+ -+/* KVM_IRQ_LINE irq field index values */ -+#define KVM_LOONGARCH_IRQ_TYPE_SHIFT 24 -+#define KVM_LOONGARCH_IRQ_TYPE_MASK 0xff -+#define KVM_LOONGARCH_IRQ_VCPU_SHIFT 16 -+#define KVM_LOONGARCH_IRQ_VCPU_MASK 0xff -+#define KVM_LOONGARCH_IRQ_NUM_SHIFT 0 -+#define KVM_LOONGARCH_IRQ_NUM_MASK 0xffff -+ -+/* irq_type field */ -+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IP 0 -+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IO 1 -+#define KVM_LOONGARCH_IRQ_TYPE_HT 2 -+#define KVM_LOONGARCH_IRQ_TYPE_MSI 3 -+#define KVM_LOONGARCH_IRQ_TYPE_IOAPIC 4 -+ -+static void legacy_set_irq(void *opaque, int irq, int level) -+{ -+ qemu_irq *pic = opaque; -+ -+ qemu_set_irq(pic[irq], level); -+} -+ -+typedef struct ls3a_intctlstate { -+ uint8_t nodecounter_reg[0x100]; -+ uint8_t pm_reg[0x100]; -+ uint8_t msi_reg[0x8]; -+ CPULOONGARCHState **env; -+ DeviceState *apicdev; -+ qemu_irq *ioapic_irq; -+#ifdef CONFIG_KVM -+ struct loongarch_kvm_irqchip chip; -+#endif -+} ls3a_intctlstate; -+ -+typedef struct ls3a_func_args { -+ ls3a_intctlstate *state; -+ uint64_t base; -+ uint32_t mask; -+ uint8_t *mem; -+} ls3a_func_args; -+ -+static uint64_t ls3a_msi_mem_read(void *opaque, hwaddr addr, unsigned size) -+{ -+ return 0; -+} -+ -+static void ls3a_msi_mem_write(void *opaque, hwaddr addr, -+ uint64_t val, unsigned size) -+{ -+ struct kvm_msi msi; -+ apicState *apic; -+ -+ apic = (apicState *)opaque; -+ msi.address_lo = 0; -+ msi.address_hi = 0; -+ msi.data = val & 0xff; -+ msi.flags = 0; -+ memset(msi.pad, 0, sizeof(msi.pad)); -+ -+ if (kvm_irqchip_in_kernel()) { -+ kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi); -+ } else { -+ qemu_set_irq(apic->irq[msi.data], 1); -+ } -+} -+ -+ -+static const MemoryRegionOps ls3a_msi_ops = { -+ .read = ls3a_msi_mem_read, -+ .write = ls3a_msi_mem_write, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+}; -+ -+ -+static const VMStateDescription vmstate_ls3a_msi = { -+ .name = "ls3a-msi", -+ .version_id = 0, -+ .minimum_version_id = 0, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT8_ARRAY(msi_reg, ls3a_intctlstate, 0x8), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static void ioapic_handler(void *opaque, int irq, int level) -+{ -+ apicState *apic; -+ int kvm_irq; -+ -+ apic = (apicState *)opaque; -+ -+ if (kvm_irqchip_in_kernel()) { -+ kvm_irq = (KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT) -+ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | irq; -+ kvm_set_irq(kvm_state, kvm_irq, !!level); -+ } else { -+ qemu_set_irq(apic->irq[irq], level); -+ } -+} -+ -+static void *ls3a_intctl_init(MachineState *machine, CPULOONGARCHState *env[]) -+{ -+ qemu_irq *irqhandler; -+ ls3a_intctlstate *s; -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LoongarchMachineClass *mc = LoongarchMACHINE_GET_CLASS(lsms); -+ DeviceState *dev; -+ SysBusDevice *busdev; -+ MemoryRegion *address_space_mem = get_system_memory(); -+ MemoryRegion *iomem = NULL; -+ int i; -+ -+ s = g_malloc0(sizeof(ls3a_intctlstate)); -+ -+ if (!s) { -+ return NULL; -+ } -+ -+ /*Add MSI mmio memory*/ -+ iomem = g_new(MemoryRegion, 1); -+ memory_region_init_io(iomem, NULL, &ls3a_msi_ops, lsms->apic, -+ "ls3a_msi", 0x8); -+ memory_region_add_subregion(address_space_mem, -+ MSI_ADDR_LOW, iomem); -+ vmstate_register(NULL, 0, &vmstate_ls3a_msi, s); -+ -+ s->env = env; -+ -+ if (!strcmp(mc->bridge_name, "ls7a")) { -+ if (lsms->apic_xrupt_override) { -+ DPRINTF("irqchip in kernel %d\n", kvm_irqchip_in_kernel()); -+#ifdef CONFIG_KVM -+ if (kvm_has_gsi_routing()) { -+ for (i = 0; i < 32; ++i) { -+ kvm_irqchip_add_irq_route(kvm_state, i, 0, i); -+ } -+ kvm_gsi_routing_allowed = true; -+ } -+ kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); -+#endif -+ } -+ -+ irqhandler = qemu_allocate_irqs(ioapic_handler, lsms->apic, 64); -+ dev = qdev_new("ioapic"); -+ busdev = SYS_BUS_DEVICE(dev); -+ sysbus_realize_and_unref(busdev, &error_fatal); -+ sysbus_mmio_map(busdev, 0, mc->ls7a_ioapic_reg_base); -+ s->ioapic_irq = irqhandler; -+ s->apicdev = dev; -+ return s->ioapic_irq; -+ } -+ return NULL; -+} -+ -+/* Network support */ -+static void network_init(PCIBus *pci_bus) -+{ -+ int i; -+ -+ for (i = 0; i < nb_nics; i++) { -+ NICInfo *nd = &nd_table[i]; -+ -+ if (!nd->model) { -+ nd->model = g_strdup("virtio-net-pci"); -+ } -+ -+ pci_nic_init_nofail(nd, pci_bus, nd->model, NULL); -+ } -+} -+ -+void loongarch_cpu_destroy(MachineState *machine, LOONGARCHCPU *cpu) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ unsigned int id; -+ int smp_cpus = machine->smp.cpus; -+ id = cpu->id; -+ qemu_unregister_reset(slave_cpu_reset, lsms->reset_info[id]); -+ g_free(lsms->reset_info[id]); -+ lsms->reset_info[id] = NULL; -+ -+ smp_cpus -= 1; -+ if (lsms->fw_cfg) { -+ fw_cfg_modify_i16(lsms->fw_cfg, FW_CFG_NB_CPUS, -+ (uint16_t)smp_cpus); -+ } -+ -+ qemu_del_vm_change_state_handler(cpu->cpuStateEntry); -+} -+ -+LOONGARCHCPU *loongarch_cpu_create(MachineState *machine, -+ LOONGARCHCPU *cpu, Error **errp) -+{ -+ CPULOONGARCHState *env; -+ unsigned int id; -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ int smp_cpus = machine->smp.cpus; -+ id = cpu->id; -+ env = &cpu->env; -+ cpu_states[id] = env; -+ env->CSR_TMID |= id; -+ -+ lsms = LoongarchMACHINE(machine); -+ lsms->reset_info[id] = g_malloc0(sizeof(ResetData)); -+ lsms->reset_info[id]->cpu = cpu; -+ lsms->reset_info[id]->vector = env->active_tc.PC; -+ qemu_register_reset(slave_cpu_reset, lsms->reset_info[id]); -+ -+ /* Init CPU internal devices */ -+ cpu_init_irq(cpu); -+ cpu_loongarch_clock_init(cpu); -+ -+ smp_cpus += 1; -+ if (lsms->fw_cfg) { -+ fw_cfg_modify_i16(lsms->fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); -+ } -+ cpu_init_ipi(lsms, env->irq[12], id); -+ cpu_init_apic(lsms, env, id); -+ -+ return cpu; -+} -+ -+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]); -+} -+ -+static FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, -+ LoongarchMachineState *lsms) -+{ -+ FWCfgState *fw_cfg; -+ uint64_t *numa_fw_cfg; -+ int i; -+ const CPUArchIdList *cpus; -+ MachineClass *mc = MACHINE_GET_CLASS(lsms); -+ MachineState *ms = MACHINE(OBJECT(lsms)); -+ int max_cpus = ms->smp.max_cpus; -+ int smp_cpus = ms->smp.cpus; -+ int nb_numa_nodes = ms->numa_state->num_nodes; -+ NodeInfo *numa_info = ms->numa_state->nodes; -+ -+ fw_cfg = fw_cfg_init_mem_wide(FW_CFG_ADDR + 8, FW_CFG_ADDR, 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); -+ -+ /* allocate memory for the NUMA channel: one (64bit) word for the number -+ * of nodes, one word for each VCPU->node and one word for each node to -+ * hold the amount of memory. -+ */ -+ numa_fw_cfg = g_new0(uint64_t, 1 + max_cpus + nb_numa_nodes); -+ numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes); -+ cpus = mc->possible_cpu_arch_ids(MACHINE(lsms)); -+ for (i = 0; i < cpus->len; i++) { -+ unsigned int apic_id = cpus->cpus[i].arch_id; -+ assert(apic_id < max_cpus); -+ numa_fw_cfg[apic_id + 1] = cpu_to_le64(cpus->cpus[i].props.node_id); -+ } -+ for (i = 0; i < nb_numa_nodes; i++) { -+ numa_fw_cfg[max_cpus + 1 + i] = -+ cpu_to_le64(numa_info[i].node_mem); -+ } -+ fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, -+ (1 + max_cpus + nb_numa_nodes) * -+ sizeof(*numa_fw_cfg)); -+ -+ qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); -+ return fw_cfg; -+} -+ -+static void loongarch_build_smbios(LoongarchMachineState *lsms) -+{ -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ MachineState *ms = MACHINE(OBJECT(lsms)); -+ uint8_t *smbios_tables, *smbios_anchor; -+ size_t smbios_tables_len, smbios_anchor_len; -+ const char *product = "QEMU Virtual Machine"; -+ ms->smp.cores = 4; -+ -+ if (!lsms->fw_cfg) { -+ return; -+ } -+ -+ if (kvm_enabled()) { -+ if (strstr(lsmc->cpu_name, "5000")) { -+ product = "KVM"; -+ } -+ } else { -+ product = "Loongarch-3A5K-7A1000-TCG"; -+ } -+ -+ host_cpufreq = get_host_cpu_freq(); -+ -+ smbios_set_defaults("Loongson", product, lsmc->cpu_name, false, -+ true, NULL, NULL, SMBIOS_ENTRY_POINT_30); -+ -+ 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(lsms->fw_cfg, "etc/smbios/smbios-tables", -+ smbios_tables, smbios_tables_len); -+ fw_cfg_add_file(lsms->fw_cfg, "etc/smbios/smbios-anchor", -+ smbios_anchor, smbios_anchor_len); -+ } -+} -+ -+static -+void loongarch_machine_done(Notifier *notifier, void *data) -+{ -+ LoongarchMachineState *lsms = container_of(notifier, -+ LoongarchMachineState, machine_done); -+ loongarch_acpi_setup(); -+ loongarch_build_smbios(lsms); -+} -+ -+#ifdef CONFIG_TCG -+#define FEATURE_REG 0x1fe00008 -+#define VENDOR_REG 0x1fe00010 -+#define CPUNAME_REG 0x1fe00020 -+#define OTHER_FUNC_REG 0x1fe00420 -+#define _str(x) #x -+#define str(x) _str(x) -+#define SIMPLE_OPS(ADDR, SIZE) \ -+({\ -+ MemoryRegion *iomem = g_new(MemoryRegion, 1);\ -+ memory_region_init_io(iomem, NULL, &loongarch_qemu_ops, \ -+ (void *)ADDR, str(ADDR) , SIZE);\ -+ memory_region_add_subregion_overlap(address_space_mem, ADDR, iomem, 1);\ -+}) -+ -+static int reg180; -+ -+static void loongarch_qemu_write(void *opaque, hwaddr addr, -+ uint64_t val, unsigned size) -+{ -+ addr = ((hwaddr)(long)opaque) + addr; -+ addr = addr & 0xffffffff; -+ switch (addr) { -+ case 0x1fe00180: -+ reg180 = val; -+ break; -+ } -+} -+ -+static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size) -+{ -+ uint64_t feature = 0UL; -+ addr = ((hwaddr)(long)opaque) + addr; -+ addr = addr & 0xffffffff; -+ switch (addr) { -+ case 0x1fe00180: -+ return reg180; -+ case 0x1001041c: -+ return 0xa800; -+ case FEATURE_REG: -+ feature |= 1UL << 2 | 1UL << 3 | 1UL << 4 | 1UL << 11; -+ return feature ; -+ case VENDOR_REG: -+ return *(uint64_t *)"Loongson-3A5000"; -+ case CPUNAME_REG: -+ return *(uint64_t *)"3A5000"; -+ case 0x10013ffc: -+ return 0x80; -+ } -+ return 0; -+} -+ -+static const MemoryRegionOps loongarch_qemu_ops = { -+ .read = loongarch_qemu_read, -+ .write = loongarch_qemu_write, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+ .valid = { -+ .min_access_size = 4, -+ .max_access_size = 8, -+ }, -+ .impl = { -+ .min_access_size = 4, -+ .max_access_size = 8, -+ }, -+}; -+#endif -+ -+ -+static void loongarch_system_flash_cleanup_unused(LoongarchMachineState *lsms) -+{ -+ char *prop_name; -+ int i; -+ Object *dev_obj; -+ -+ for (i = 0; i < ARRAY_SIZE(lsms->flash); i++) { -+ dev_obj = OBJECT(lsms->flash[i]); -+ if (!object_property_get_bool(dev_obj, "realized", &error_abort)) { -+ prop_name = g_strdup_printf("pflash%d", i); -+ object_property_del(OBJECT(lsms), prop_name); -+ g_free(prop_name); -+ object_unparent(dev_obj); -+ lsms->flash[i] = NULL; -+ } -+ } -+} -+ -+ -+static bool loongarch_system_flash_init( LoongarchMachineState *lsms) -+{ -+ int i = 0; -+ int64_t size = 0; -+ PFlashCFI01 *pflash = NULL; -+ BlockBackend *pflash_blk; -+ -+ for(i = 0; i < ARRAY_SIZE(lsms->flash); i++) { -+ pflash_blk = NULL; -+ pflash = NULL; -+ -+ pflash = lsms->flash[i]; -+ pflash_cfi01_legacy_drive(pflash, -+ drive_get(IF_PFLASH, 0, i)); -+ -+ pflash_blk = pflash_cfi01_get_blk(pflash); -+ /*The pflash0 must be exist, or not support boot by pflash*/ -+ if(pflash_blk == NULL) { -+ if(i == 0) { -+ return false; -+ } else { -+ break; -+ } -+ } -+ -+ size = blk_getlength(pflash_blk); -+ if (size == 0 || size % FLASH_SECTOR_SIZE != 0) { -+ error_report("system firmware block device %s has invalid size " -+ "%" PRId64, -+ blk_name(pflash_blk), size); -+ error_report("its size must be a non-zero multiple of 0x%x", -+ FLASH_SECTOR_SIZE); -+ exit(1); -+ } -+ qdev_prop_set_uint32(DEVICE(pflash), "num-blocks", -+ size / FLASH_SECTOR_SIZE); -+ sysbus_realize_and_unref(SYS_BUS_DEVICE(pflash), &error_fatal); -+ if(i == 0) { -+ sysbus_mmio_map(SYS_BUS_DEVICE(pflash), 0, LS_BIOS_BASE); -+ } else { -+ sysbus_mmio_map_overlap(SYS_BUS_DEVICE(pflash), 0, LS_BIOS_VAR_BASE, 1); -+ } -+ } -+ -+ return true; -+} -+static void ls3a5k_bios_init(LoongarchMachineState *lsms, -+ ram_addr_t ram_size, -+ uint64_t highram_size, -+ uint64_t phyAddr_initrd, -+ const char *kernel_filename, -+ const char *kernel_cmdline, -+ const char *initrd_filename) -+{ -+ MemoryRegion *bios; -+ bool fw_cfg_used = false; -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ char *filename; -+ int bios_size; -+ const char *bios_name; -+ -+ bios_name = MACHINE(lsms)->firmware; -+ if (kernel_filename) { -+ loaderparams.ram_size = ram_size; -+ loaderparams.kernel_filename = kernel_filename; -+ loaderparams.kernel_cmdline = kernel_cmdline; -+ loaderparams.initrd_filename = initrd_filename; -+ } -+ -+ if(loongarch_system_flash_init(lsms)) { -+ fw_cfg_used = true; -+ } else { -+ bios = g_new(MemoryRegion, 1); -+ memory_region_init_ram(bios, NULL, "loongarch.bios", LS_BIOS_SIZE, &error_fatal); -+ memory_region_set_readonly(bios, true); -+ memory_region_add_subregion(get_system_memory(), LS_BIOS_BASE, bios); -+ -+ /* BIOS load */ -+ if (bios_name) { -+ if (access(bios_name, R_OK) == 0) { -+ load_image_targphys(bios_name, LS_BIOS_BASE, LS_BIOS_SIZE); -+ } else { -+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); -+ load_image_targphys(filename, LS_BIOS_BASE, LS_BIOS_SIZE); -+ g_free(filename); -+ } -+ fw_cfg_used = true; -+ } else { -+ if (strstr(lsmc->cpu_name, "5000")) { -+ bios_size = sizeof(ls3a5k_aui_boot_code); -+ rom_add_blob_fixed("bios", ls3a5k_aui_boot_code, bios_size, LS_BIOS_BASE); -+ } -+ -+ if (kernel_filename) { -+ lsms->reset_info[0]->vector = load_kernel(); -+ } else { -+ error_report("Please specify at lease one of -bios and -kernel"); -+ exit(1); -+ } -+ } -+ } -+ -+ loongarch_system_flash_cleanup_unused(lsms); -+ -+ if (fw_cfg_used) { -+ lsms->fw_cfg = loongarch_fw_cfg_init(ram_size, lsms); -+ rom_set_fw(lsms->fw_cfg); -+ fw_conf_init(ram_size); -+ rom_add_blob_fixed("fw_conf", (void *)&fw_config, -+ sizeof(fw_config), FW_CONF_ADDR); -+ -+ if (kernel_filename) { -+ fw_cfg_add_kernel_info(lsms->fw_cfg, highram_size, phyAddr_initrd); -+ } -+ } -+ -+ if (lsms->fw_cfg != NULL) { -+ fw_cfg_add_file(lsms->fw_cfg, "etc/memmap", -+ la_memmap_table, -+ sizeof(struct la_memmap_entry) * (la_memmap_entries)); -+ } -+ -+ return ; -+} -+static void create_fdt(LoongarchMachineState *lsms) -+{ -+ lsms->fdt = create_device_tree(&lsms->fdt_size); -+ if (!lsms->fdt) { -+ error_report("create_device_tree() failed"); -+ exit(1); -+ } -+ -+ /* Header */ -+ qemu_fdt_setprop_string(lsms->fdt, "/", "compatible", -+ "linux,dummy-loongson3"); -+ qemu_fdt_setprop_cell(lsms->fdt, "/", "#address-cells", 0x2); -+ qemu_fdt_setprop_cell(lsms->fdt, "/", "#size-cells", 0x2); -+} -+ -+static void fdt_add_cpu_nodes(const LoongarchMachineState *lsms) -+{ -+ int num; -+ const MachineState *ms = MACHINE(lsms); -+ int smp_cpus = ms->smp.cpus; -+ -+ qemu_fdt_add_subnode(lsms->fdt, "/cpus"); -+ qemu_fdt_setprop_cell(lsms->fdt, "/cpus", "#address-cells", 0x1); -+ qemu_fdt_setprop_cell(lsms->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(lsms->fdt, nodename); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, "device_type", "cpu"); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, "compatible", -+ cpu->dtb_compatible); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "reg", num); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "phandle", -+ qemu_fdt_alloc_phandle(lsms->fdt)); -+ g_free(nodename); -+ } -+ -+ /*cpu map */ -+ qemu_fdt_add_subnode(lsms->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(lsms->fdt, map_path); -+ qemu_fdt_setprop_phandle(lsms->fdt, map_path, "cpu", cpu_path); -+ -+ g_free(map_path); -+ g_free(cpu_path); -+ } -+} -+ -+static void fdt_add_fw_cfg_node(const LoongarchMachineState *lsms) -+{ -+ char *nodename; -+ hwaddr base = FW_CFG_ADDR; -+ -+ nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base); -+ qemu_fdt_add_subnode(lsms->fdt, nodename); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, -+ "compatible", "qemu,fw-cfg-mmio"); -+ qemu_fdt_setprop_sized_cells(lsms->fdt, nodename, "reg", -+ 2, base, 2, 0x8); -+ qemu_fdt_setprop(lsms->fdt, nodename, "dma-coherent", NULL, 0); -+ g_free(nodename); -+} -+ -+static void fdt_add_pcie_node(const LoongarchMachineState *lsms) -+{ -+ char *nodename; -+ hwaddr base_mmio = LS_ISA_MEM_BASE; -+ hwaddr size_mmio = LS_ISA_MEM_SIZE; -+ hwaddr base_pio = LS3A5K_ISA_IO_BASE; -+ hwaddr size_pio = LS_ISA_IO_SIZE; -+ hwaddr base_pcie = LS_PCIECFG_BASE; -+ hwaddr size_pcie = LS_PCIECFG_SIZE; -+ hwaddr base = base_pcie; -+ -+ nodename = g_strdup_printf("/pcie@%" PRIx64, base); -+ qemu_fdt_add_subnode(lsms->fdt, nodename); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, -+ "compatible", "pci-host-ecam-generic"); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, "device_type", "pci"); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "#address-cells", 3); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "#size-cells", 2); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "linux,pci-domain", 0); -+ qemu_fdt_setprop_cells(lsms->fdt, nodename, "bus-range", 0, -+ PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1)); -+ qemu_fdt_setprop(lsms->fdt, nodename, "dma-coherent", NULL, 0); -+ qemu_fdt_setprop_sized_cells(lsms->fdt, nodename, "reg", -+ 2, base_pcie, 2, size_pcie); -+ qemu_fdt_setprop_sized_cells(lsms->fdt, nodename, "ranges", -+ 1, FDT_PCI_RANGE_IOPORT, 2, 0, -+ 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(lsms->fdt, lsms->fdt_size); -+} -+ -+static void ls3a5k_init(MachineState *args) -+{ -+ int i; -+ const char *cpu_model = args->cpu_type; -+ const char *kernel_filename = args->kernel_filename; -+ const char *kernel_cmdline = args->kernel_cmdline; -+ const char *initrd_filename = args->initrd_filename; -+ -+ ram_addr_t ram_size = args->ram_size; -+ MemoryRegion *address_space_mem = get_system_memory(); -+ ram_addr_t offset = 0; -+ MemoryRegion *isa_io = g_new(MemoryRegion, 1); -+ MemoryRegion *isa_mem = g_new(MemoryRegion, 1); -+ MachineState *machine = args; -+ MachineClass *mc = MACHINE_GET_CLASS(machine); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ int smp_cpus = machine->smp.cpus; -+ int nb_numa_nodes = machine->numa_state->num_nodes; -+ NodeInfo *numa_info = machine->numa_state->nodes; -+ LOONGARCHCPU *cpu; -+ CPULOONGARCHState *env; -+ qemu_irq *ls7a_apic = NULL; -+ qemu_irq *pirq = NULL; -+ PCIBus *pci_bus = NULL; -+ char *ramName = NULL; -+ uint64_t lowram_size = 0, highram_size = 0, phyAddr = 0, -+ memmap_size = 0, highram_end_addr = 0; -+ -+ CPUArchIdList *possible_cpus; -+ if (strstr(lsmc->cpu_name, "5000")) { -+ if (strcmp(cpu_model, LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000")) && -+ strcmp(cpu_model, LOONGARCH_CPU_TYPE_NAME("host"))) { -+ error_report("machine type %s does not match cpu type %s", -+ lsmc->cpu_name, cpu_model); -+ exit(1); -+ } -+ if (kvm_enabled()) { -+ kvm_vm_ioctl(kvm_state, KVM_LARCH_SET_CPUCFG, ls3a5k_cpucfgs); -+ } -+ } -+ -+ create_fdt(lsms); -+ -+ DPRINTF("isa 0x%lx\n", lsmc->isa_io_base); -+ DPRINTF("ht1lo 0x%lx\n", lsmc->ht1lo_pcicfg_base); -+ DPRINTF("cpu_name %s bridge_name %s\n", -+ lsmc->cpu_name, lsmc->bridge_name); -+ -+ /* init CPUs */ -+ mc->possible_cpu_arch_ids(machine); -+ possible_cpus = machine->possible_cpus; -+ -+ for (i = 0; i < smp_cpus; i++) { -+ Object *obj = NULL; -+ Error *local_err = NULL; -+ -+ obj = object_new(possible_cpus->cpus[i].type); -+ -+ object_property_set_uint(obj, "id", possible_cpus->cpus[i].arch_id, -+ &local_err); -+ object_property_set_bool(obj, "realized", true, &local_err); -+ -+ object_unref(obj); -+ error_propagate(&error_fatal, local_err); -+ -+ cpu = LOONGARCH_CPU(CPU(obj)); -+ if (cpu == NULL) { -+ fprintf(stderr, "Unable to find CPU definition\n"); -+ exit(1); -+ } -+ -+ env = &cpu->env; -+ cpu_states[i] = env; -+ env->CSR_TMID |= i; -+ -+ lsms->reset_info[i] = g_malloc0(sizeof(ResetData)); -+ lsms->reset_info[i]->cpu = cpu; -+ lsms->reset_info[i]->vector = env->active_tc.PC; -+ if (i == 0) { -+ qemu_register_reset(main_cpu_reset, lsms->reset_info[i]); -+ } else { -+ qemu_register_reset(slave_cpu_reset, lsms->reset_info[i]); -+ } -+ -+ /* Init CPU internal devices */ -+ cpu_init_irq(cpu); -+ cpu_loongarch_clock_init(cpu); -+ cpu_init_ipi(lsms, env->irq[12], i); -+ cpu_init_apic(lsms, env, i); -+ } -+ -+ lsms->hotpluged_cpu_num = 0; -+ fdt_add_cpu_nodes(lsms); -+ env = cpu_states[0]; -+ -+ /* node0 mem*/ -+ phyAddr = (uint64_t)0; -+ MemoryRegion *lowmem = g_new(MemoryRegion, 1); -+ ramName = g_strdup_printf("loongarch_ls3a.node%d.lowram", 0); -+ -+ lowram_size = MIN(ram_size, 256 * 0x100000); -+ memory_region_init_alias(lowmem, NULL, ramName, machine->ram, 0, lowram_size); -+ memory_region_add_subregion(address_space_mem, phyAddr, lowmem); -+ -+ offset += lowram_size; -+ if (nb_numa_nodes > 0) { -+ highram_size = numa_info[0].node_mem - S_256MiB; -+ if (numa_info[0].node_mem > S_1GiB) { -+ memmap_size = numa_info[0].node_mem - S_1GiB; -+ la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); -+ } -+ } else { -+ highram_size = ram_size - S_256MiB; -+ if (ram_size > S_1GiB) { -+ memmap_size = ram_size - S_1GiB; -+ la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); -+ } -+ } -+ -+ phyAddr = (uint64_t)0x90000000; -+ MemoryRegion *highmem = g_new(MemoryRegion, 1); -+ ramName = g_strdup_printf("loongarch_ls3a.node%d.highram", 0); -+ memory_region_init_alias(highmem, NULL, ramName, -+ machine->ram, offset, highram_size); -+ memory_region_add_subregion(address_space_mem, -+ phyAddr, highmem); -+ offset += highram_size; -+ phyAddr += highram_size; -+ -+ /* initrd address use high mem from high to low */ -+ highram_end_addr = phyAddr; -+ /* node1~ nodemax */ -+ for (i = 1; i < nb_numa_nodes; i++) { -+ MemoryRegion *nodemem = g_new(MemoryRegion, 1); -+ ramName = g_strdup_printf("loongarch_ls3a.node%d.ram", i); -+ memory_region_init_alias(nodemem, NULL, ramName, -+ machine->ram, offset, numa_info[i].node_mem); -+ memory_region_add_subregion(address_space_mem, -+ phyAddr, nodemem); -+ la_memmap_add_entry(phyAddr, numa_info[i].node_mem, SYSTEM_RAM); -+ offset += numa_info[i].node_mem; -+ phyAddr += numa_info[i].node_mem; -+ } -+ -+ fdt_add_fw_cfg_node(lsms); -+ ls3a5k_bios_init(lsms, ram_size, highram_size, highram_end_addr, -+ kernel_filename, kernel_cmdline, initrd_filename); -+ -+ lsms->machine_done.notify = loongarch_machine_done; -+ qemu_add_machine_init_done_notifier(&lsms->machine_done); -+ /*vmstate_register_ram_global(bios);*/ -+ -+ /* initialize hotplug memory address space */ -+ lsms->hotplug_memory_size = 0; -+ -+ /* always allocate the device memory information */ -+ machine->device_memory = g_malloc0(sizeof(*machine->device_memory)); -+ if (machine->ram_size < machine->maxram_size) { -+ int max_memslots; -+ -+ lsms->hotplug_memory_size = machine->maxram_size - machine->ram_size; -+ /* -+ * Limit the number of hotpluggable memory slots to half the number -+ * slots that KVM supports, leaving the other half for PCI and other -+ * devices. However ensure that number of slots doesn't drop below 32. -+ */ -+ max_memslots = LOONGARCH_MAX_RAM_SLOTS; -+ if (kvm_enabled()) { -+ max_memslots = kvm_get_max_memslots() / 2 ; -+ } -+ -+ if (machine->ram_slots == 0) -+ machine->ram_slots = lsms->hotplug_memory_size / -+ LOONGARCH_HOTPLUG_MEM_ALIGN; -+ -+ if (machine->ram_slots > max_memslots) { -+ error_report("Specified number of memory slots %" -+ PRIu64" exceeds max supported %d", -+ machine->ram_slots, max_memslots); -+ exit(1); -+ } -+ -+ lsms->ram_slots = machine->ram_slots; -+ -+ machine->device_memory->base = get_hotplug_membase(machine->ram_size); -+ memory_region_init(&machine->device_memory->mr, OBJECT(lsms), -+ "device-memory", lsms->hotplug_memory_size); -+ memory_region_add_subregion(get_system_memory(), -+ machine->device_memory->base, -+ &machine->device_memory->mr); -+ } -+ -+ memory_region_init_alias(isa_io, NULL, "isa-io", -+ get_system_io(), 0, LS_ISA_IO_SIZE); -+ memory_region_init(isa_mem, NULL, "isa-mem", LS_ISA_MEM_SIZE); -+ memory_region_add_subregion(get_system_memory(), lsmc->isa_io_base, isa_io); -+ memory_region_add_subregion(get_system_memory(), LS_ISA_MEM_BASE, isa_mem); -+ -+ if (!strcmp(lsmc->bridge_name, "ls7a")) { -+ /*Initialize the 7A IO interrupt subsystem*/ -+ DeviceState *ls7a_dev; -+ lsms->apic_xrupt_override = kvm_irqchip_in_kernel(); -+ ls7a_apic = ls3a_intctl_init(machine, cpu_states); -+ if (!ls7a_apic) { -+ perror("Init 7A APIC failed\n"); -+ exit(1); -+ } -+ pci_bus = ls7a_init(machine, ls7a_apic, &ls7a_dev); -+ -+ object_property_add_link(OBJECT(machine), -+ LOONGARCH_MACHINE_ACPI_DEVICE_PROP, -+ TYPE_HOTPLUG_HANDLER, -+ (Object **)&lsms->acpi_dev, -+ object_property_allow_set_link, -+ OBJ_PROP_LINK_STRONG); -+ object_property_set_link(OBJECT(machine), LOONGARCH_MACHINE_ACPI_DEVICE_PROP, -+ OBJECT(ls7a_dev), &error_abort); -+ -+#ifdef CONFIG_KVM -+ if (kvm_enabled()) { -+ kvm_direct_msi_allowed = (kvm_check_extension(kvm_state, -+ KVM_CAP_SIGNAL_MSI) > 0); -+ } else { -+ kvm_direct_msi_allowed = 0; -+ } -+ msi_nonbroken = kvm_direct_msi_allowed; -+#else -+ msi_nonbroken = true; -+#endif -+ sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE, -+ ls7a_apic[LS7A_RTC_IRQ - LOONGARCH_PCH_IRQ_BASE]); -+ } -+ -+ /*Initialize the CPU serial device*/ -+ -+ if (serial_hd(0)) { -+ pirq = qemu_allocate_irqs(legacy_set_irq, ls7a_apic + -+ (LS7A_UART_IRQ - LOONGARCH_PCH_IRQ_BASE), 1); -+ serial_mm_init(address_space_mem, LS7A_UART_BASE, 0, pirq[0], -+ 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); -+ } -+ -+ /*network card*/ -+ network_init(pci_bus); -+ /* VGA setup. Don't bother loading the bios. */ -+ pci_vga_init(pci_bus); -+ -+ sysbus_realize_and_unref(SYS_BUS_DEVICE(qdev_new("iocsr")), &error_fatal); -+ -+#ifdef CONFIG_TCG -+ int nb_nodes = (smp_cpus - 1) / 4; -+ for (i = 0; i <= nb_nodes; i++) { -+ uint64_t off = (uint64_t)i << 44; -+ SIMPLE_OPS(((hwaddr)0x1fe00180 | off), 0x8); -+ SIMPLE_OPS(((hwaddr)0x1fe0019c | off), 0x8); -+ SIMPLE_OPS(((hwaddr)0x1fe001d0 | off), 0x8); -+ SIMPLE_OPS(((hwaddr)FEATURE_REG | off), 0x8); -+ SIMPLE_OPS(((hwaddr)VENDOR_REG | off), 0x8); -+ SIMPLE_OPS(((hwaddr)CPUNAME_REG | off), 0x8); -+ SIMPLE_OPS(((hwaddr)OTHER_FUNC_REG | off), 0x8); -+ } -+ -+ SIMPLE_OPS(0x1001041c, 0x4); -+ SIMPLE_OPS(0x10002000, 0x14); -+ SIMPLE_OPS(0x10013ffc, 0x4); -+#endif -+ -+ fdt_add_pcie_node(lsms); -+ -+ /* load fdt */ -+ MemoryRegion *fdt_rom = g_new(MemoryRegion, 1); -+ memory_region_init_rom(fdt_rom, NULL, "fdt", LS_FDT_SIZE, &error_fatal); -+ memory_region_add_subregion(get_system_memory(), LS_FDT_BASE, fdt_rom); -+ rom_add_blob_fixed("fdt", lsms->fdt, lsms->fdt_size, LS_FDT_BASE); -+} -+ -+static const CPUArchIdList *loongarch_possible_cpu_arch_ids(MachineState *ms) -+{ -+ int i; -+ int max_cpus = ms->smp.max_cpus; -+ -+ if (ms->possible_cpus) { -+ /* -+ * make sure that max_cpus hasn't changed since the first use, i.e. -+ * -smp hasn't been parsed after it -+ */ -+ assert(ms->possible_cpus->len == max_cpus); -+ return ms->possible_cpus; -+ } -+ -+ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + -+ sizeof(CPUArchId) * max_cpus); -+ ms->possible_cpus->len = max_cpus; -+ for (i = 0; i < ms->possible_cpus->len; i++) { -+ ms->possible_cpus->cpus[i].type = ms->cpu_type; -+ ms->possible_cpus->cpus[i].vcpus_count = 1; -+ ms->possible_cpus->cpus[i].props.has_core_id = true; -+ ms->possible_cpus->cpus[i].props.core_id = i; -+ ms->possible_cpus->cpus[i].arch_id = i; -+ } -+ return ms->possible_cpus; -+ -+} -+ -+static PFlashCFI01 *loongarch_pflash_create(LoongarchMachineState *lsms, -+ const char *name, -+ const char *alias_prop_name) -+{ -+ DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); -+ -+ qdev_prop_set_uint64(dev, "sector-length", FLASH_SECTOR_SIZE); -+ qdev_prop_set_uint8(dev, "width", 1); -+ qdev_prop_set_string(dev, "name", name); -+ object_property_add_child(OBJECT(lsms), name, OBJECT(dev)); -+ object_property_add_alias(OBJECT(lsms), alias_prop_name, -+ OBJECT(dev), "drive"); -+ return PFLASH_CFI01(dev); -+} -+ -+ -+static void loongarch_system_flash_create(LoongarchMachineState *lsms) -+{ -+ lsms->flash[0] = loongarch_pflash_create(lsms, "system.flash0", -+ "pflash0"); -+ lsms->flash[1] = loongarch_pflash_create(lsms, "system.flash1", -+ "pflash1"); -+} -+ -+static void loongarch_machine_initfn(Object *obj) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(obj); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ lsms->acpi_build_enabled = lsmc->has_acpi_build; -+ loongarch_system_flash_create(lsms); -+ lsms->oem_id = g_strndup(EFI_ACPI_OEM_ID, 6); -+ lsms->oem_table_id = g_strndup(EFI_ACPI_OEM_TABLE_ID, 6); -+} -+ -+static void ls3a5k_ls7a_machine_options(MachineClass *m) -+{ -+ char *cpu_name = get_host_cpu_model_name(); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_CLASS(m); -+ m->desc = "Loongarch3a5k LS7A1000 machine"; -+ m->max_cpus = LOONGARCH_MAX_VCPUS; -+ m->alias = "loongson7a"; -+ m->is_default = 1; -+ lsmc->isa_io_base = LS3A5K_ISA_IO_BASE; -+ lsmc->ht1lo_pcicfg_base = LS3A5K_HT1LO_PCICFG_BASE; -+ lsmc->pciecfg_base = LS_PCIECFG_BASE; -+ lsmc->ls7a_ioapic_reg_base = LS3A5K_LS7A_IOAPIC_REG_BASE; -+ lsmc->node_shift = 44; -+ strncpy(lsmc->cpu_name, cpu_name, sizeof(lsmc->cpu_name) - 1); -+ lsmc->cpu_name[sizeof(lsmc->cpu_name) - 1] = 0; -+ strncpy(lsmc->bridge_name, "ls7a", sizeof(lsmc->bridge_name) - 1); -+ lsmc->bridge_name[sizeof(lsmc->bridge_name) - 1] = 0; -+ compat_props_add(m->compat_props, loongarch_compat, loongarch_compat_len); -+} -+ -+static void ls3a_board_reset(MachineState *ms) -+{ -+ qemu_devices_reset(); -+#ifdef CONFIG_KVM -+ struct loongarch_kvm_irqchip *chip; -+ int length; -+ -+ if (!kvm_enabled()) { -+ return; -+ } -+ length = sizeof(struct loongarch_kvm_irqchip) + -+ sizeof(struct loongarch_gipiState); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS3A_GIPI; -+ chip->len = length; -+ kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct ls7a_ioapic_state); -+ chip = g_realloc(chip, length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS7A_IOAPIC; -+ chip->len = length; -+ kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ -+ g_free(chip); -+#endif -+} -+ -+static CpuInstanceProperties ls3a_cpu_index_to_props(MachineState *ms, unsigned cpu_index) -+{ -+ MachineClass *mc = MACHINE_GET_CLASS(ms); -+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); -+ -+ assert(cpu_index < possible_cpus->len); -+ return possible_cpus->cpus[cpu_index].props; -+} -+ -+static int64_t ls3a_get_default_cpu_node_id(const MachineState *ms, int idx) -+{ -+ int nb_numa_nodes = ms->numa_state->num_nodes; -+ int smp_cores = ms->smp.cores; -+ return idx / smp_cores % nb_numa_nodes; -+} -+ -+static void loongarch_class_init(ObjectClass *oc, void *data) -+{ -+ MachineClass *mc = MACHINE_CLASS(oc); -+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_CLASS(oc); -+ -+ lsmc->get_hotplug_handler = mc->get_hotplug_handler; -+ lsmc->has_acpi_build = true; -+ mc->get_hotplug_handler = loongarch_get_hotpug_handler; -+ mc->has_hotpluggable_cpus = true; -+ mc->cpu_index_to_instance_props = ls3a_cpu_index_to_props; -+ mc->possible_cpu_arch_ids = loongarch_possible_cpu_arch_ids; -+ mc->get_default_cpu_node_id = ls3a_get_default_cpu_node_id; -+ mc->default_ram_size = 1 * GiB; -+ mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000"); -+ mc->default_ram_id = "loongarch_ls3a.ram"; -+ -+ mc->reset = ls3a_board_reset; -+ mc->max_cpus = LOONGARCH_MAX_VCPUS; -+ hc->pre_plug = loongarch_machine_device_pre_plug; -+ hc->plug = loongarch_machine_device_plug; -+ hc->unplug = longson_machine_device_unplug; -+ hc->unplug_request = loongarch_machine_device_unplug_request; -+ -+ 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_info = { -+ .name = TYPE_LOONGARCH_MACHINE, -+ .parent = TYPE_MACHINE, -+ .abstract = true, -+ .instance_size = sizeof(LoongarchMachineState), -+ .instance_init = loongarch_machine_initfn, -+ .class_size = sizeof(LoongarchMachineClass), -+ .class_init = loongarch_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_HOTPLUG_HANDLER }, -+ { } -+ }, -+ -+}; -+ -+static void loongarch_machine_register_types(void) -+{ -+ type_register_static(&loongarch_info); -+} -+ -+type_init(loongarch_machine_register_types) -+ -+DEFINE_LS3A5K_MACHINE(loongson7a_v1_0, "loongson7a_v1.0", -+ ls3a5k_ls7a_machine_options); -diff --git a/hw/loongarch/larch_hotplug.c b/hw/loongarch/larch_hotplug.c -new file mode 100644 -index 000000000..7bce95712 ---- /dev/null -+++ b/hw/loongarch/larch_hotplug.c -@@ -0,0 +1,355 @@ -+/* -+ * Hotplug emulation on Loongarch system. -+ * -+ * Copyright (c) 2018 Loongarch Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 "qapi/error.h" -+#include "qemu-common.h" -+#include "qemu/queue.h" -+#include "qemu/units.h" -+#include "qemu/cutils.h" -+#include "qemu/bcd.h" -+#include "hw/hotplug.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/mem/memory-device.h" -+#include "sysemu/numa.h" -+#include "sysemu/cpus.h" -+#include "hw/loongarch/larch.h" -+#include "hw/cpu/core.h" -+#include "hw/nvram/fw_cfg.h" -+ -+/* find cpu slot in machine->possible_cpus by core_id */ -+static CPUArchId *loongarch_find_cpu_slot(MachineState *ms, uint32_t id, -+ int *idx) -+{ -+ int index = id; -+ -+ if (index >= ms->possible_cpus->len) { -+ return NULL; -+ } -+ if (idx) { -+ *idx = index; -+ } -+ return &ms->possible_cpus->cpus[index]; -+} -+ -+static void loongarch_memory_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ Error *local_err = NULL; -+ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); -+ HotplugHandlerClass *hhc; -+ uint64_t size; -+ -+ size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort); -+ if (size % LOONGARCH_HOTPLUG_MEM_ALIGN) { -+ error_setg(&local_err, "Hotplugged memory size must be a multiple of " -+ "%lld MB", LOONGARCH_HOTPLUG_MEM_ALIGN / MiB); -+ goto out; -+ } -+ -+ pc_dimm_plug(PC_DIMM(dev), MACHINE(lsms)); -+ -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->plug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &error_abort); -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_memory_unplug_request(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ Error *local_err = NULL; -+ HotplugHandlerClass *hhc; -+ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); -+ -+ if (!lsms->acpi_dev || !loongarch_is_acpi_enabled(lsms)) { -+ error_setg(&local_err, -+ "memory hotplug is not enabled: missing acpi device or acpi disabled"); -+ goto out; -+ } -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->unplug_request(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_cpu_unplug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ CPUArchId *found_cpu; -+ HotplugHandlerClass *hhc; -+ Error *local_err = NULL; -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->unplug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ -+ if (local_err) { -+ goto out; -+ } -+ -+ loongarch_cpu_destroy(machine, cpu); -+ -+ found_cpu = loongarch_find_cpu_slot(MACHINE(lsms), cpu->id, NULL); -+ found_cpu->cpu = NULL; -+ object_unparent(OBJECT(dev)); -+ lsms->hotpluged_cpu_num -= 1; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_memory_unplug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ Error *local_err = NULL; -+ HotplugHandlerClass *hhc; -+ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); -+ -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->unplug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ -+ if (local_err) { -+ goto out; -+ } -+ -+ pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev)); -+ object_unparent(OBJECT(dev)); -+ -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_cpu_pre_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ MachineState *ms = MACHINE(OBJECT(hotplug_dev)); -+ MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); -+ LoongarchMachineState *lsms = LoongarchMACHINE(ms); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ CPUArchId *cpu_slot; -+ Error *local_err = NULL; -+ int index; -+ int free_index = lsms->hotpluged_cpu_num + ms->smp.cpus; -+ int max_cpus = ms->smp.max_cpus; -+ -+ if (dev->hotplugged && !mc->has_hotpluggable_cpus) { -+ error_setg(&local_err, "CPU hotplug not supported for this machine"); -+ goto out; -+ } -+ -+ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { -+ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", -+ ms->cpu_type); -+ return; -+ } -+ -+ /* if ID is not set, set it based on core properties */ -+ if (cpu->id == UNASSIGNED_CPU_ID) { -+ if ((cpu->core_id) > (max_cpus - 1)) { -+ error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", -+ cpu->core_id, max_cpus - 1); -+ return; -+ } -+ -+ if (free_index > (max_cpus - 1)) { -+ error_setg(errp, "The maximum number of CPUs cannot exceed %u.", -+ max_cpus); -+ return; -+ } -+ -+ if (cpu->core_id != free_index) { -+ error_setg(errp, "Invalid CPU core-id: %u must be :%u", -+ cpu->core_id, free_index); -+ return; -+ } -+ -+ cpu->id = cpu->core_id; -+ } -+ -+ cpu_slot = loongarch_find_cpu_slot(MACHINE(hotplug_dev), cpu->id, &index); -+ if (!cpu_slot) { -+ error_setg(&local_err, "core id %d out of range", cpu->id); -+ goto out; -+ } -+ -+ if (cpu_slot->cpu) { -+ error_setg(&local_err, "core %d already populated", cpu->id); -+ goto out; -+ } -+ -+ numa_cpu_pre_plug(cpu_slot, dev, &local_err); -+ -+ return ; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ PCDIMMDevice *dimm = PC_DIMM(dev); -+ Error *local_err = NULL; -+ uint64_t size; -+ -+ if (!lsms->acpi_dev || !loongarch_is_acpi_enabled(lsms)) { -+ error_setg(errp, -+ "memory hotplug is not enabled: missing acpi device or acpi disabled"); -+ return; -+ } -+ -+ size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ if (size % LOONGARCH_HOTPLUG_MEM_ALIGN) { -+ error_setg(errp, "Hotplugged memory size must be a multiple of " -+ "%lld MB", LOONGARCH_HOTPLUG_MEM_ALIGN / MiB); -+ return; -+ } -+ -+ pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp); -+} -+ -+static void loongarch_cpu_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ CPUArchId *found_cpu; -+ HotplugHandlerClass *hhc; -+ Error *local_err = NULL; -+ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ -+ if (lsms->acpi_dev) { -+ loongarch_cpu_create(machine, cpu, errp); -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->plug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ } -+ -+ found_cpu = loongarch_find_cpu_slot(MACHINE(lsms), cpu->id, NULL); -+ found_cpu->cpu = OBJECT(dev); -+ lsms->hotpluged_cpu_num += 1; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_cpu_unplug_request(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ Error *local_err = NULL; -+ HotplugHandlerClass *hhc; -+ int idx = -1; -+ -+ if (!lsms->acpi_dev) { -+ error_setg(&local_err, "CPU hot unplug not supported without ACPI"); -+ goto out; -+ } -+ -+ loongarch_find_cpu_slot(MACHINE(lsms), cpu->id, &idx); -+ assert(idx != -1); -+ if (idx == 0) { -+ error_setg(&local_err, "Boot CPU is unpluggable"); -+ goto out; -+ } -+ -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->unplug_request(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ -+ if (local_err) { -+ goto out; -+ } -+ -+ out: -+ error_propagate(errp, local_err); -+} -+ -+void longson_machine_device_unplug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); -+ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ loongarch_memory_unplug(hotplug_dev, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ if (!mc->has_hotpluggable_cpus) { -+ error_setg(errp, "CPU hot unplug not supported on this machine"); -+ return; -+ } -+ loongarch_cpu_unplug(hotplug_dev, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+ -+ return; -+} -+ -+void loongarch_machine_device_unplug_request(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ loongarch_memory_unplug_request(hotplug_dev, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ loongarch_cpu_unplug_request(hotplug_dev, dev, errp); -+ } -+} -+ -+HotplugHandler *loongarch_get_hotpug_handler(MachineState *machine, -+ DeviceState *dev) -+{ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || -+ object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ return HOTPLUG_HANDLER(machine); -+ } -+ return NULL; -+} -+ -+void loongarch_machine_device_pre_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ loongarch_memory_pre_plug(hotplug_dev, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ loongarch_cpu_pre_plug(hotplug_dev, dev, errp); -+ } -+} -+ -+void loongarch_machine_device_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ loongarch_memory_plug(hotplug_dev, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ loongarch_cpu_plug(hotplug_dev, dev, errp); -+ } -+} -+ -diff --git a/hw/loongarch/larch_int.c b/hw/loongarch/larch_int.c -new file mode 100644 -index 000000000..ca073a19c ---- /dev/null -+++ b/hw/loongarch/larch_int.c -@@ -0,0 +1,91 @@ -+/* -+ * QEMU LOONGARCH interrupt support -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu/main-loop.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/loongarch/cpudevs.h" -+#include "cpu.h" -+#include "sysemu/kvm.h" -+#include "kvm_larch.h" -+#ifdef CONFIG_KVM -+#include -+#endif -+ -+static void cpu_irq_request(void *opaque, int irq, int level) -+{ -+ LOONGARCHCPU *cpu = opaque; -+ CPULOONGARCHState *env = &cpu->env; -+ CPUState *cs = CPU(cpu); -+ bool locked = false; -+ -+ if (irq < 0 || irq > 13) { -+ return; -+ } -+ -+ /* Make sure locking works even if BQL is already held by the caller */ -+ if (!qemu_mutex_iothread_locked()) { -+ locked = true; -+ qemu_mutex_lock_iothread(); -+ } -+ -+ if (level) { -+ env->CSR_ESTAT |= 1 << irq; -+ } else { -+ env->CSR_ESTAT &= ~(1 << irq); -+ } -+ -+ if (kvm_enabled()) { -+ if (irq == 2) { -+ kvm_loongarch_set_interrupt(cpu, irq, level); -+ } else if (irq == 3) { -+ kvm_loongarch_set_interrupt(cpu, irq, level); -+ } else if (irq == 12) { -+ kvm_loongarch_set_ipi_interrupt(cpu, irq, level); -+ } -+ } -+ -+ if (env->CSR_ESTAT & CSR_ESTAT_IPMASK) { -+ cpu_interrupt(cs, CPU_INTERRUPT_HARD); -+ } else { -+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); -+ } -+ -+ if (locked) { -+ qemu_mutex_unlock_iothread(); -+ } -+} -+ -+void cpu_init_irq(LOONGARCHCPU *cpu) -+{ -+ CPULOONGARCHState *env = &cpu->env; -+ qemu_irq *qi; -+ int i; -+ -+ qi = qemu_allocate_irqs(cpu_irq_request, loongarch_env_get_cpu(env), N_IRQS); -+ for (i = 0; i < N_IRQS; i++) { -+ env->irq[i] = qi[i]; -+ } -+} -+ -+ -diff --git a/hw/loongarch/ls7a_nb.c b/hw/loongarch/ls7a_nb.c -new file mode 100644 -index 000000000..5a500fbd5 ---- /dev/null -+++ b/hw/loongarch/ls7a_nb.c -@@ -0,0 +1,352 @@ -+/* -+ * Loongarch 7A1000 north bridge support -+ * -+ * Copyright (c) 2019 Loongarch Technology -+ * Authors: -+ * Zhu Chen -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+ -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/sysbus.h" -+#include "hw/pci/pci.h" -+#include "hw/i386/pc.h" -+#include "hw/pci/pci_host.h" -+#include "hw/pci/pcie_host.h" -+#include "sysemu/sysemu.h" -+#include "exec/address-spaces.h" -+#include "qapi/error.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/acpi/ls7a.h" -+#include "hw/i386/pc.h" -+#include "hw/isa/isa.h" -+#include "hw/boards.h" -+#include "qemu/log.h" -+#include "hw/loongarch/bios.h" -+#include "hw/loader.h" -+#include "elf.h" -+#include "exec/address-spaces.h" -+#include "exec/memory.h" -+#include "hw/pci/pci_bridge.h" -+#include "hw/pci/pci_bus.h" -+#include "linux/kvm.h" -+#include "sysemu/kvm.h" -+#include "sysemu/runstate.h" -+#include "sysemu/reset.h" -+#include "migration/vmstate.h" -+#include "hw/loongarch/larch.h" -+#include "hw/loongarch/ls7a.h" -+ -+#undef DEBUG_LS7A -+ -+#ifdef DEBUG_LS7A -+#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __func__, ##__VA_ARGS__) -+#else -+#define DPRINTF(fmt, ...) -+#endif -+ -+static void ls7a_reset(void *opaque) -+{ -+ uint64_t wmask; -+ wmask = ~(-1); -+ -+ PCIDevice *dev = opaque; -+ pci_set_word(dev->config + PCI_VENDOR_ID, 0x0014); -+ pci_set_word(dev->wmask + PCI_VENDOR_ID, wmask & 0xffff); -+ pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); -+ pci_set_word(dev->config + PCI_DEVICE_ID, 0x7a00); -+ pci_set_word(dev->wmask + PCI_DEVICE_ID, wmask & 0xffff); -+ pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff); -+ pci_set_word(dev->config + 0x4, 0x0000); -+ pci_set_word(dev->config + PCI_STATUS, 0x0010); -+ pci_set_word(dev->wmask + PCI_STATUS, wmask & 0xffff); -+ pci_set_word(dev->cmask + PCI_STATUS, 0xffff); -+ pci_set_byte(dev->config + PCI_REVISION_ID, 0x0); -+ pci_set_byte(dev->wmask + PCI_REVISION_ID, wmask & 0xff); -+ pci_set_byte(dev->cmask + PCI_REVISION_ID, 0xff); -+ pci_set_byte(dev->config + 0x9, 0x00); -+ pci_set_byte(dev->wmask + 0x9, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0x9, 0xff); -+ pci_set_byte(dev->config + 0xa, 0x00); -+ pci_set_byte(dev->wmask + 0xa, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0xa, 0xff); -+ pci_set_byte(dev->config + 0xb, 0x06); -+ pci_set_byte(dev->wmask + 0xb, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0xb, 0xff); -+ pci_set_byte(dev->config + 0xc, 0x00); -+ pci_set_byte(dev->wmask + 0xc, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0xc, 0xff); -+ pci_set_byte(dev->config + 0xe, 0x80); -+ pci_set_byte(dev->wmask + 0xe, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0xe, 0xff); -+} -+ -+static const VMStateDescription vmstate_ls7a_pcie = { -+ .name = "LS7A_PCIE", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_PCI_DEVICE(dev, LS7APCIState), -+ VMSTATE_STRUCT(pm, LS7APCIState, 0, vmstate_ls7a_pm, LS7APCIPMRegs), -+ VMSTATE_UINT32_ARRAY(regs, LS7APCIState, LS7A_REGS), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin) -+{ -+ PCIINTxRoute route; -+ -+ route.irq = pin; -+ route.mode = PCI_INTX_ENABLED; -+ return route; -+} -+ -+static int pci_ls7a_map_irq(PCIDevice *d, int irq_num) -+{ -+ int irq; -+ -+ irq = 16 + ((PCI_SLOT(d->devfn) * 4 + irq_num) & 0xf); -+ return irq; -+} -+ -+static void pci_ls7a_set_irq(void *opaque, int irq_num, int level) -+{ -+ qemu_irq *pic = opaque; -+ DPRINTF("------ %s irq %d %d\n", __func__, irq_num, level); -+ qemu_set_irq(pic[irq_num], level); -+} -+ -+/* -+static int ls7a_pciehost_initfn(SysBusDevice *dev) -+{ -+ return 0; -+}*/ -+ -+static void ls7a_pcie_realize(PCIDevice *dev, Error **errp) -+{ -+ LS7APCIState *s = PCIE_LS7A(dev); -+ /* Ls7a North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */ -+ pci_config_set_prog_interface(dev->config, 0x00); -+ -+ /* set the default value of north bridge pci config */ -+ qemu_register_reset(ls7a_reset, s); -+} -+ -+static void pci_ls7a_config_write(void *opaque, hwaddr addr, -+ uint64_t val, unsigned size) -+{ -+ hwaddr tmp_addr; -+ tmp_addr = addr & 0xffffff; -+ -+ pci_data_write(opaque, tmp_addr, val, size); -+} -+ -+static uint64_t pci_ls7a_config_read(void *opaque, -+ hwaddr addr, unsigned size) -+{ -+ uint64_t val; -+ hwaddr tmp_addr; -+ -+ tmp_addr = addr & 0xffffff; -+ val = pci_data_read(opaque, tmp_addr, size); -+ -+ if (addr & 0x3c) { -+ DPRINTF(TARGET_FMT_plx" val %lx\n", addr, val); -+ } -+ return val; -+} -+ -+static const MemoryRegionOps pci_ls7a_config_ops = { -+ .read = pci_ls7a_config_read, -+ .write = pci_ls7a_config_write, -+ /* Set to access 64bits data, because default to 32bits*/ -+ .valid = { -+ .min_access_size = 1, -+ .max_access_size = 4, -+ }, -+ /* Set to access 64bits data, because default to 32bits*/ -+ .impl = { -+ .min_access_size = 1, -+ .max_access_size = 4, -+ }, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+ -+}; -+ -+static AddressSpace *ls7a_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) -+{ -+ return &address_space_memory; -+} -+ -+static PCIBus *pci_ls7a_init(MachineState *machine, DeviceState *dev, -+ qemu_irq *pic) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ PCIExpressHost *e; -+ SysBusDevice *sysbus; -+ MemoryRegion *iomem = g_new(MemoryRegion, 1); -+ PCIHostState *phb; -+ -+ e = PCIE_HOST_BRIDGE(dev); -+ sysbus = SYS_BUS_DEVICE(e); -+ phb = PCI_HOST_BRIDGE(e); -+ phb->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq, -+ pci_ls7a_map_irq, pic, -+ get_system_memory(), get_system_io(), -+ (1 << 3), 128, TYPE_PCIE_BUS); -+ pcie_host_mmcfg_update(e, true, lsmc->pciecfg_base, LS_PCIECFG_SIZE); -+ DPRINTF("------ %d\n", __LINE__); -+ -+ pci_bus_set_route_irq_fn(phb->bus, ls7a_route_intx_pin_to_irq); -+ memory_region_init_io(iomem, NULL, &pci_ls7a_config_ops, phb->bus, -+ "ls7a_pci_conf", HT1LO_PCICFG_SIZE); -+ sysbus_init_mmio(sysbus, iomem); -+ sysbus_mmio_map(sysbus, 0, lsmc->ht1lo_pcicfg_base); -+ -+ return phb->bus; -+} -+ -+PCIBus *ls7a_init(MachineState *machine, qemu_irq *pic, DeviceState **ls7a_dev) -+{ -+ DeviceState *dev; -+ PCIHostState *phb; -+ LS7APCIState *pbs; -+ PCIDevice *pcid; -+ PCIBus *pci_bus; -+ PCIExpressHost *e; -+ -+ /*1. init the HT PCI CFG*/ -+ DPRINTF("------ %d\n", __LINE__); -+ dev = qdev_new(TYPE_LS7A_PCIE_HOST_BRIDGE); -+ e = PCIE_HOST_BRIDGE(dev); -+ phb = PCI_HOST_BRIDGE(e); -+ -+ DPRINTF("------ %d\n", __LINE__); -+ pci_bus = pci_ls7a_init(machine, dev, pic); -+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); -+ phb->bus = pci_bus; -+ /* set the pcihost pointer after rs780_pcihost_initfn is called */ -+ DPRINTF("------ %d\n", __LINE__); -+ pcid = pci_new(PCI_DEVFN(0, 0), TYPE_PCIE_LS7A); -+ pbs = PCIE_LS7A(pcid); -+ pbs->pciehost = LS7A_PCIE_HOST_BRIDGE(dev); -+ pbs->pciehost->pci_dev = pbs; -+ -+ if (ls7a_dev) { -+ *ls7a_dev = DEVICE(pcid); -+ } -+ -+ pci_realize_and_unref(pcid, phb->bus, &error_fatal); -+ -+ /* IOMMU */ -+ pci_setup_iommu(phb->bus, ls7a_pci_dma_iommu, NULL); -+ -+ ls7a_pm_init(&pbs->pm, pic); -+ DPRINTF("------ %d\n", __LINE__); -+ /*3. init the north bridge VGA,not do now*/ -+ return pci_bus; -+} -+ -+LS7APCIState *get_ls7a_type(Object *obj) -+{ -+ LS7APCIState *pbs; -+ -+ pbs = PCIE_LS7A(obj); -+ return pbs; -+} -+ -+static void ls7a_pcie_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); -+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); -+ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass); -+ -+ k->realize = ls7a_pcie_realize; -+ k->vendor_id = 0x0014; -+ k->device_id = 0x7a00; -+ k->revision = 0x00; -+ k->class_id = PCI_CLASS_BRIDGE_HOST; -+ dc->desc = "LS7A1000 PCIE Host bridge"; -+ dc->vmsd = &vmstate_ls7a_pcie; -+ /* -+ * PCI-facing part of the host bridge, not usable without the -+ * host-facing part, which can't be device_add'ed, yet. -+ */ -+ dc->user_creatable = false; -+ hc->plug = ls7a_pm_device_plug_cb; -+ hc->unplug_request = ls7a_pm_device_unplug_request_cb; -+ hc->unplug = ls7a_pm_device_unplug_cb; -+ adevc->ospm_status = ls7a_pm_ospm_status; -+ adevc->send_event = ls7a_send_gpe; -+ adevc->madt_cpu = ls7a_madt_cpu_entry; -+} -+ -+static void ls7a_pci_add_properties(LS7APCIState *ls7a) -+{ -+ ls7a_pm_add_properties(OBJECT(ls7a), &ls7a->pm, NULL); -+} -+ -+static void ls7a_pci_initfn(Object *obj) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ ls7a_pci_add_properties(ls7a); -+} -+ -+static const TypeInfo ls7a_pcie_device_info = { -+ .name = TYPE_PCIE_LS7A, -+ .parent = TYPE_PCI_DEVICE, -+ .instance_size = sizeof(LS7APCIState), -+ .class_init = ls7a_pcie_class_init, -+ .instance_init = ls7a_pci_initfn, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_HOTPLUG_HANDLER }, -+ { TYPE_ACPI_DEVICE_IF }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, -+}; -+ -+static void ls7a_pciehost_class_init(ObjectClass *klass, void *data) -+{ -+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); -+ k->parent_class.fw_name = "pci"; -+} -+ -+static const TypeInfo ls7a_pciehost_info = { -+ .name = TYPE_LS7A_PCIE_HOST_BRIDGE, -+ .parent = TYPE_PCIE_HOST_BRIDGE, -+ .instance_size = sizeof(LS7APCIEHost), -+ .class_init = ls7a_pciehost_class_init, -+}; -+ -+static void ls7a_register_types(void) -+{ -+ type_register_static(&ls7a_pciehost_info); -+ type_register_static(&ls7a_pcie_device_info); -+} -+ -+type_init(ls7a_register_types) -diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build -new file mode 100644 -index 000000000..81ee99a02 ---- /dev/null -+++ b/hw/loongarch/meson.build -@@ -0,0 +1,15 @@ -+loongarch_ss = ss.source_set() -+loongarch_ss.add(files('larch_3a.c'), fdt) -+loongarch_ss.add(files( -+ 'larch_int.c', -+ 'larch_hotplug.c', -+ 'ls7a_nb.c', -+ 'ioapic.c', -+ 'acpi-build.c', -+ 'ipi.c', -+ 'apic.c', -+ 'iocsr.c', -+)) -+ -+hw_arch += {'loongarch64': loongarch_ss} -+ -diff --git a/include/hw/loongarch/bios.h b/include/hw/loongarch/bios.h -new file mode 100644 -index 000000000..3677303bf ---- /dev/null -+++ b/include/hw/loongarch/bios.h -@@ -0,0 +1,5 @@ -+#include "qemu/units.h" -+#include "cpu.h" -+ -+#define BIOS_SIZE (4 * MiB) -+#define BIOS_FILENAME "loongarch_bios.bin" -diff --git a/include/hw/loongarch/cpudevs.h b/include/hw/loongarch/cpudevs.h -new file mode 100644 -index 000000000..c05ae7a7f ---- /dev/null -+++ b/include/hw/loongarch/cpudevs.h -@@ -0,0 +1,53 @@ -+#ifndef HW_LOONGARCH_CPUDEVS_H -+#define HW_LOONGARCH_CPUDEVS_H -+ -+#include "target/loongarch64/cpu-qom.h" -+ -+/* Definitions for LOONGARCH CPU internal devices. */ -+#define MAX_GIPI_CORE_NUM 256 -+#define MAX_GIPI_MBX_NUM 4 -+ -+#define LS3A_INTC_IP 8 -+#define MAX_CORES 256 -+#define EXTIOI_IRQS (256) -+#define EXTIOI_IRQS_BITMAP_SIZE (256 / 8) -+/* map to ipnum per 32 irqs */ -+#define EXTIOI_IRQS_IPMAP_SIZE (256 / 32) -+ -+typedef struct gipi_core { -+ uint32_t status; -+ uint32_t en; -+ uint32_t set; -+ uint32_t clear; -+ uint64_t buf[MAX_GIPI_MBX_NUM]; -+ qemu_irq irq; -+} gipi_core; -+ -+typedef struct gipiState { -+ gipi_core core[MAX_GIPI_CORE_NUM]; -+} gipiState; -+ -+typedef struct apicState { -+ /* hardware state */ -+ uint8_t ext_en[EXTIOI_IRQS_BITMAP_SIZE]; -+ uint8_t ext_bounce[EXTIOI_IRQS_BITMAP_SIZE]; -+ uint8_t ext_isr[EXTIOI_IRQS_BITMAP_SIZE]; -+ uint8_t ext_coreisr[MAX_CORES][EXTIOI_IRQS_BITMAP_SIZE]; -+ uint8_t ext_ipmap[EXTIOI_IRQS_IPMAP_SIZE]; -+ uint8_t ext_coremap[EXTIOI_IRQS]; -+ uint16_t ext_nodetype[16]; -+ uint64_t ext_control; -+ -+ /* software state */ -+ uint8_t ext_sw_ipmap[EXTIOI_IRQS]; -+ uint8_t ext_sw_coremap[EXTIOI_IRQS]; -+ uint8_t ext_ipisr[MAX_CORES * LS3A_INTC_IP][EXTIOI_IRQS_BITMAP_SIZE]; -+ -+ qemu_irq parent_irq[MAX_CORES][LS3A_INTC_IP]; -+ qemu_irq *irq; -+} apicState; -+ -+void cpu_init_irq(LOONGARCHCPU *cpu); -+void cpu_loongarch_clock_init(LOONGARCHCPU *cpu); -+ -+#endif -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -new file mode 100644 -index 000000000..0886ed52a ---- /dev/null -+++ b/include/hw/loongarch/larch.h -@@ -0,0 +1,163 @@ -+/* -+ * Hotplug emulation on Loongarch system. -+ * -+ * Copyright (c) 2018 Loongarch Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 . -+ */ -+ -+#ifndef HW_LOONGARCH_H -+#define HW_LOONGARCH_H -+ -+#include "target/loongarch64/cpu.h" -+#include "qemu-common.h" -+#include "exec/memory.h" -+#include "hw/mem/pc-dimm.h" -+#include "hw/hotplug.h" -+#include "hw/boards.h" -+#include "hw/acpi/acpi.h" -+#include "qemu/notify.h" -+#include "qemu/error-report.h" -+#include "qemu/queue.h" -+#include "hw/acpi/memory_hotplug.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/block/flash.h" -+ -+#define LOONGARCH_MAX_VCPUS 256 -+#define LOONGARCH_MAX_PFLASH 2 -+/* 256MB alignment for hotplug memory region */ -+#define LOONGARCH_HOTPLUG_MEM_ALIGN (1ULL << 28) -+#define LOONGARCH_MAX_RAM_SLOTS 10 -+ -+/* Memory types: */ -+#define SYSTEM_RAM 1 -+#define SYSTEM_RAM_RESERVED 2 -+#define ACPI_TABLE 3 -+#define ACPI_NVS 4 -+#define SYSTEM_PMEM 5 -+ -+#define MAX_MEM_MAP 128 -+ -+typedef struct LoongarchMachineClass { -+ /*< private >*/ -+ MachineClass parent_class; -+ -+ /* Methods: */ -+ HotplugHandler *(*get_hotplug_handler)(MachineState *machine, -+ DeviceState *dev); -+ -+ bool has_acpi_build; -+ -+ /* save different cpu address*/ -+ uint64_t isa_io_base; -+ uint64_t ht_control_regs_base; -+ uint64_t hpet_mmio_addr; -+ uint64_t smbus_cfg_base; -+ uint64_t ht1lo_pcicfg_base; -+ uint64_t pciecfg_base; -+ uint64_t ls7a_ioapic_reg_base; -+ uint32_t node_shift; -+ char cpu_name[40]; -+ char bridge_name[16]; -+ -+} LoongarchMachineClass; -+ -+typedef struct ResetData { -+ LOONGARCHCPU *cpu; -+ uint64_t vector; -+} ResetData; -+ -+typedef struct LoongarchMachineState { -+ /*< private >*/ -+ MachineState parent_obj; -+ -+ /* */ -+ ram_addr_t hotplug_memory_size; -+ -+ /* State for other subsystems/APIs: */ -+ Notifier machine_done; -+ /* Pointers to devices and objects: */ -+ HotplugHandler *acpi_dev; -+ int ram_slots; -+ ResetData *reset_info[LOONGARCH_MAX_VCPUS]; -+ DeviceState *rtc; -+ gipiState *gipi; -+ apicState *apic; -+ -+ FWCfgState *fw_cfg; -+ bool acpi_build_enabled; -+ bool apic_xrupt_override; -+ CPUArchIdList *possible_cpus; -+ PFlashCFI01 *flash[LOONGARCH_MAX_PFLASH]; -+ void *fdt; -+ int fdt_size; -+ unsigned int hotpluged_cpu_num; -+ OnOffAuto acpi; -+ char *oem_id; -+ char *oem_table_id; -+} LoongarchMachineState; -+ -+#define LOONGARCH_MACHINE_ACPI_DEVICE_PROP "loongarch-acpi-device" -+#define TYPE_LOONGARCH_MACHINE "loongarch-machine" -+ -+#define LoongarchMACHINE(obj) \ -+ OBJECT_CHECK(LoongarchMachineState, (obj), TYPE_LOONGARCH_MACHINE) -+#define LoongarchMACHINE_GET_CLASS(obj) \ -+ OBJECT_GET_CLASS(LoongarchMachineClass, (obj), TYPE_LOONGARCH_MACHINE) -+#define LoongarchMACHINE_CLASS(klass) \ -+ OBJECT_CLASS_CHECK(LoongarchMachineClass, (klass), TYPE_LOONGARCH_MACHINE) -+ -+#define DEFINE_LOONGARCH_MACHINE(suffix, namestr, initfn, optsfn) \ -+ static void loongarch_machine_##suffix##_class_init(ObjectClass *oc, void *data) \ -+ { \ -+ MachineClass *mc = MACHINE_CLASS(oc); \ -+ optsfn(mc); \ -+ mc->init = initfn; \ -+ } \ -+ static const TypeInfo loongarch_machine_type_##suffix = { \ -+ .name = namestr TYPE_MACHINE_SUFFIX, \ -+ .parent = TYPE_LOONGARCH_MACHINE, \ -+ .class_init = loongarch_machine_##suffix##_class_init, \ -+ }; \ -+ static void loongarch_machine_init_##suffix(void) \ -+ { \ -+ type_register(&loongarch_machine_type_##suffix); \ -+ } \ -+ type_init(loongarch_machine_init_##suffix) -+ -+void loongarch_machine_device_unplug_request(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+void longson_machine_device_unplug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+HotplugHandler *loongarch_get_hotpug_handler(MachineState *machine, -+ DeviceState *dev); -+void loongarch_machine_device_pre_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+void loongarch_machine_device_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+ -+LOONGARCHCPU *loongarch_cpu_create(MachineState *machine, LOONGARCHCPU *cpu, -+ Error **errp); -+void loongarch_cpu_destroy(MachineState *machine, LOONGARCHCPU *cpu); -+int cpu_init_ipi(LoongarchMachineState *ms, qemu_irq parent, int cpu); -+int cpu_init_apic(LoongarchMachineState *ms, CPULOONGARCHState *env, int cpu); -+int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type); -+bool loongarch_is_acpi_enabled(LoongarchMachineState *vms); -+ -+/* acpi-build.c */ -+void ls7a_madt_cpu_entry(AcpiDeviceIf *adev, int uid, -+ const CPUArchIdList *apic_ids, GArray *entry, bool force_enabled); -+void slave_cpu_reset(void *opaque); -+extern uint64_t host_cpufreq; -+#endif -diff --git a/include/hw/loongarch/ls7a.h b/include/hw/loongarch/ls7a.h -new file mode 100644 -index 000000000..686af763a ---- /dev/null -+++ b/include/hw/loongarch/ls7a.h -@@ -0,0 +1,152 @@ -+#ifndef HW_LS7A_H -+#define HW_LS7A_H -+ -+#include "hw/hw.h" -+#include "hw/isa/isa.h" -+#include "hw/sysbus.h" -+#include "hw/isa/apm.h" -+#include "hw/pci/pci.h" -+#include "hw/pci/pcie_host.h" -+#include "hw/pci/pci_bridge.h" -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/ls7a.h" -+#include "hw/pci/pci_bus.h" -+ -+/* LS7A PCH Registers (Misc, Confreg) */ -+#define LS7A_PCH_REG_BASE 0x10000000UL -+#define LS3A5K_LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE) -+#define LS7A_MISC_REG_BASE (LS7A_PCH_REG_BASE + 0x00080000) -+#define LS7A_ACPI_REG_BASE (LS7A_MISC_REG_BASE + 0x00050000) -+ -+#define LOONGARCH_PCH_IRQ_BASE 64 -+#define LS7A_UART_IRQ (LOONGARCH_PCH_IRQ_BASE + 2) -+#define LS7A_RTC_IRQ (LOONGARCH_PCH_IRQ_BASE + 3) -+#define LS7A_SCI_IRQ (LOONGARCH_PCH_IRQ_BASE + 4) -+#define LS7A_ACPI_IO_BASE 0x800 -+#define LS7A_ACPI_IO_SIZE 0x100 -+#define LS7A_PM_EVT_BLK (0x0C) /* 4 bytes */ -+#define LS7A_PM_CNT_BLK (0x14) /* 2 bytes */ -+#define LS7A_GPE0_STS_REG (0x28) /* 4 bytes */ -+#define LS7A_GPE0_ENA_REG (0x2C) /* 4 bytes */ -+#define LS7A_GPE0_RESET_REG (0x30) /* 4 bytes */ -+#define LS7A_PM_TMR_BLK (0x18) /* 4 bytes */ -+#define LS7A_GPE0_LEN (8) -+#define LS7A_RTC_REG_BASE (LS7A_MISC_REG_BASE + 0x00050100) -+#define LS7A_RTC_LEN (0x100) -+ -+#define ACPI_IO_BASE (LS7A_ACPI_REG_BASE) -+#define ACPI_GPE0_LEN (LS7A_GPE0_LEN) -+#define ACPI_IO_SIZE (LS7A_ACPI_IO_SIZE) -+#define ACPI_SCI_IRQ (LS7A_SCI_IRQ) -+ -+#define LS3A5K_ISA_IO_BASE 0x18000000UL -+#define LS_ISA_MEM_BASE 0x40000000 -+#define LS3A5K_HT1LO_PCICFG_BASE 0x1a000000 -+#define HT1LO_PCICFG_SIZE 0x02000000 -+#define LS_BIOS_BASE 0x1c000000 -+#define LS_BIOS_VAR_BASE 0x1c3a0000 -+#define LS_BIOS_SIZE (4 * 1024 * 1024) -+ -+#define FW_CFG_ADDR 0x1e020000 -+#define LS7A_REG_BASE 0x1FE00000 -+#define LS7A_PCICONFIG_BASE (LS7A_REG_BASE + 0x30) -+#define LS7A_PCICONFIG_SIZE (0x100) -+#define LS7A_INTERNAL_REG_BASE (LS7A_REG_BASE + 0x100) -+#define LS7A_INTERNAL_REG_SIZE (0xE0) -+#define LS7A_REGS (0xE0 >> 2) -+#define LS7A_UART_BASE 0x1fe001e0 -+#define LS7A_UART_LEN 0x8 -+ -+#define LS_FDT_BASE 0x1c400000 -+#define LS_FDT_SIZE 0x100000 -+ -+#define LS_PCIECFG_BASE 0x20000000 -+#define LS_PCIECFG_SIZE 0x08000000 -+#define MSI_ADDR_LOW 0x2FF00000 -+#define MSI_ADDR_HI 0x0 -+ -+#define SMP_GIPI_MAILBOX 0x1f000000ULL -+#define CORE0_STATUS_OFF 0x000 -+#define CORE0_EN_OFF 0x004 -+#define CORE0_SET_OFF 0x008 -+#define CORE0_CLEAR_OFF 0x00c -+#define CORE0_BUF_20 0x020 -+#define CORE0_BUF_28 0x028 -+#define CORE0_BUF_30 0x030 -+#define CORE0_BUF_38 0x038 -+#define CORE0_IPI_SEND 0x040 -+#define CORE0_MAIL_SEND 0x048 -+ -+#define INT_ROUTER_REGS_BASE 0x1fe01400UL -+#define INT_ROUTER_REGS_SIZE 0x100 -+#define INT_ROUTER_REGS_SYS_INT0 0x00 -+#define INT_ROUTER_REGS_SYS_INT1 0x01 -+#define INT_ROUTER_REGS_SYS_INT2 0x02 -+#define INT_ROUTER_REGS_SYS_INT3 0x03 -+#define INT_ROUTER_REGS_PCI_INT0 0x04 -+#define INT_ROUTER_REGS_PCI_INT1 0x05 -+#define INT_ROUTER_REGS_PCI_INT2 0x06 -+#define INT_ROUTER_REGS_PCI_INT3 0x07 -+#define INT_ROUTER_REGS_MATRIX_INT0 0x08 -+#define INT_ROUTER_REGS_MATRIX_INT1 0x09 -+#define INT_ROUTER_REGS_LPC_INT 0x0a -+#define INT_ROUTER_REGS_MC0 0x0b -+#define INT_ROUTER_REGS_MC1 0x0c -+#define INT_ROUTER_REGS_BARRIER 0x0d -+#define INT_ROUTER_REGS_THSENS_INT 0x0e -+#define INT_ROUTER_REGS_PCI_PERR 0x0f -+#define INT_ROUTER_REGS_HT0_INT0 0x10 -+#define INT_ROUTER_REGS_HT0_INT1 0x11 -+#define INT_ROUTER_REGS_HT0_INT2 0x12 -+#define INT_ROUTER_REGS_HT0_INT3 0x13 -+#define INT_ROUTER_REGS_HT0_INT4 0x14 -+#define INT_ROUTER_REGS_HT0_INT5 0x15 -+#define INT_ROUTER_REGS_HT0_INT6 0x16 -+#define INT_ROUTER_REGS_HT0_INT7 0x17 -+#define INT_ROUTER_REGS_HT1_INT0 0x18 -+#define INT_ROUTER_REGS_HT1_INT1 0x19 -+#define INT_ROUTER_REGS_HT1_INT2 0x1a -+#define INT_ROUTER_REGS_HT1_INT3 0x1b -+#define INT_ROUTER_REGS_HT1_INT4 0x1c -+#define INT_ROUTER_REGS_HT1_INT5 0x1d -+#define INT_ROUTER_REGS_HT1_INT6 0x1e -+#define INT_ROUTER_REGS_HT1_INT7 0x1f -+#define INT_ROUTER_REGS_ISR 0x20 -+#define INT_ROUTER_REGS_EN 0x24 -+#define INT_ROUTER_REGS_EN_SET 0x28 -+#define INT_ROUTER_REGS_EN_CLR 0x2c -+#define INT_ROUTER_REGS_EDGE 0x38 -+#define INT_ROUTER_REGS_CORE0_INTISR 0x40 -+#define INT_ROUTER_REGS_CORE1_INTISR 0x48 -+#define INT_ROUTER_REGS_CORE2_INTISR 0x50 -+#define INT_ROUTER_REGS_CORE3_INTISR 0x58 -+ -+typedef struct LS7APCIState LS7APCIState; -+typedef struct LS7APCIEHost { -+ PCIExpressHost parent_obj; -+ LS7APCIState *pci_dev; -+} LS7APCIEHost; -+ -+struct LS7APCIState { -+ PCIDevice dev; -+ -+ LS7APCIEHost *pciehost; -+ uint32_t regs[LS7A_REGS]; -+ -+ /* LS7A registers */ -+ MemoryRegion iomem; -+ LS7APCIPMRegs pm; -+}; -+ -+#define TYPE_LS7A_PCIE_HOST_BRIDGE "ls7a1000-pciehost" -+#define LS7A_PCIE_HOST_BRIDGE(obj) \ -+ OBJECT_CHECK(LS7APCIEHost, (obj), TYPE_LS7A_PCIE_HOST_BRIDGE) -+ -+#define TYPE_PCIE_LS7A "ls7a1000_pcie" -+#define PCIE_LS7A(obj) \ -+ OBJECT_CHECK(LS7APCIState, (obj), TYPE_PCIE_LS7A) -+ -+PCIBus *ls7a_init(MachineState *machine, qemu_irq *irq, DeviceState **ls7a_dev); -+LS7APCIState *get_ls7a_type(Object *obj); -+ -+#endif /* HW_LS7A_H */ --- -2.43.5 - diff --git a/0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch b/0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch deleted file mode 100644 index ba1f14a..0000000 --- a/0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 6dcfcd61e610da4e8d7dcfb6c3eefd7fc8a67c45 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Wed, 25 Aug 2021 09:59:16 +0800 -Subject: [PATCH 3/8] anolis: csv/i386: add command to load data to guest - memory - -The KVM_CSV_LAUNCH_ENCRYPT_DATA command is used to load data to an -encrypted guest memory in an isolated memory region that guest owns. - -Signed-off-by: Xin Jiang -Change-Id: I6d4bea4969a0afa87fb8f2e52fb7ab02ec0db2ed ---- - linux-headers/linux/kvm.h | 7 ++++ - target/i386/csv-sysemu-stub.c | 5 +++ - target/i386/csv.c | 69 +++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 2 + - target/i386/trace-events | 3 ++ - 5 files changed, 86 insertions(+) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index b15b8f5550..53f9202ffb 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1813,6 +1813,13 @@ enum csv_cmd_id { - KVM_CSV_NR_MIN = 0xc0, - - KVM_CSV_INIT = KVM_CSV_NR_MIN, -+ KVM_CSV_LAUNCH_ENCRYPT_DATA, -+}; -+ -+struct kvm_csv_launch_encrypt_data { -+ __u64 gpa; -+ __u64 uaddr; -+ __u32 len; - }; - - struct kvm_csv_init_data { -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index dbd710dc6f..236a6909d2 100644 ---- a/target/i386/csv-sysemu-stub.c -+++ b/target/i386/csv-sysemu-stub.c -@@ -19,3 +19,8 @@ int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - { - return 0; - } -+ -+int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) -+{ -+ g_assert_not_reached(); -+} -diff --git a/target/i386/csv.c b/target/i386/csv.c -index c11f59f30c..3b3dff5174 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -14,11 +14,13 @@ - #include "qemu/osdep.h" - - #include -+#include "qapi/error.h" - - #ifdef CONFIG_NUMA - #include - #endif - -+#include "trace.h" - #include "cpu.h" - #include "sev.h" - #include "csv.h" -@@ -93,3 +95,70 @@ csv_enabled(void) - - return sev_es_enabled() && (csv_guest.policy & GUEST_POLICY_CSV_BIT); - } -+ -+static bool -+csv_check_state(SevState state) -+{ -+ return *((SevState *)csv_guest.state) == state ? true : false; -+} -+ -+static int -+csv_ioctl(int cmd, void *data, int *error) -+{ -+ if (csv_guest.sev_ioctl) -+ return csv_guest.sev_ioctl(csv_guest.sev_fd, cmd, data, error); -+ else -+ return -1; -+} -+ -+static const char * -+fw_error_to_str(int code) -+{ -+ if (csv_guest.fw_error_to_str) -+ return csv_guest.fw_error_to_str(code); -+ else -+ return NULL; -+} -+ -+static int -+csv_launch_encrypt_data(uint64_t gpa, uint8_t *addr, uint64_t len) -+{ -+ int ret, fw_error; -+ struct kvm_csv_launch_encrypt_data update; -+ -+ if (!addr || !len) { -+ return 1; -+ } -+ -+ update.gpa = (__u64)gpa; -+ update.uaddr = (__u64)(unsigned long)addr; -+ update.len = len; -+ trace_kvm_csv_launch_encrypt_data(gpa, addr, len); -+ ret = csv_ioctl(KVM_CSV_LAUNCH_ENCRYPT_DATA, &update, &fw_error); -+ if (ret) { -+ error_report("%s: CSV LAUNCH_ENCRYPT_DATA ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ } -+ -+ return ret; -+} -+ -+int -+csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) -+{ -+ int ret = 0; -+ -+ if (!csv_enabled()) { -+ error_setg(errp, "%s: CSV is not enabled", __func__); -+ return -1; -+ } -+ -+ /* if CSV is in update state then load the data to secure memory */ -+ if (csv_check_state(SEV_STATE_LAUNCH_UPDATE)) { -+ ret = csv_launch_encrypt_data(gpa, ptr, len); -+ if (ret) -+ error_setg(errp, "%s: CSV fail to encrypt data", __func__); -+ } -+ -+ return ret; -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 886dbb2613..6f7b112d96 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -35,4 +35,6 @@ typedef struct CsvGuestState CsvGuestState; - extern struct CsvGuestState csv_guest; - extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); - -+int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); -+ - #endif -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 2cd8726eeb..b7da9bd748 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -11,3 +11,6 @@ kvm_sev_launch_measurement(const char *value) "data %s" - kvm_sev_launch_finish(void) "" - kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d" - kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s" -+ -+# csv.c -+kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 --- -2.17.1 - diff --git a/0004-Add-target-loongarch64.patch b/0004-Add-target-loongarch64.patch deleted file mode 100644 index bca350b..0000000 --- a/0004-Add-target-loongarch64.patch +++ /dev/null @@ -1,15917 +0,0 @@ -From 73e64c37b5d0f8a12bad7562c4d442f95ee361b8 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:44:33 -0400 -Subject: [PATCH 04/28] Add target/loongarch64. - -Change-Id: Idd3ed114968c4a1f1be5fe19dc279028775eb89d -Signed-off-by: lixianglai ---- - target/Kconfig | 1 + - target/loongarch64/Kconfig | 2 + - target/loongarch64/arch_dump.c | 174 ++ - target/loongarch64/cpu-csr.h | 869 ++++++++ - target/loongarch64/cpu-param.h | 30 + - target/loongarch64/cpu-qom.h | 54 + - target/loongarch64/cpu.c | 576 +++++ - target/loongarch64/cpu.h | 326 +++ - target/loongarch64/csr_helper.c | 704 ++++++ - target/loongarch64/fpu.c | 28 + - target/loongarch64/fpu_helper.c | 952 ++++++++ - target/loongarch64/fpu_helper.h | 129 ++ - target/loongarch64/gdbstub.c | 109 + - target/loongarch64/helper.c | 727 +++++++ - target/loongarch64/helper.h | 168 ++ - target/loongarch64/insn.decode | 514 +++++ - target/loongarch64/instmap.h | 216 ++ - target/loongarch64/internal.h | 184 ++ - target/loongarch64/kvm.c | 1622 ++++++++++++++ - target/loongarch64/kvm_larch.h | 41 + - target/loongarch64/larch-defs.h | 27 + - target/loongarch64/machine.c | 416 ++++ - target/loongarch64/meson.build | 35 + - target/loongarch64/op_helper.c | 533 +++++ - target/loongarch64/stabletimer.c | 122 ++ - target/loongarch64/tlb_helper.c | 729 +++++++ - target/loongarch64/trace-events | 3 + - target/loongarch64/trans.inc.c | 3472 ++++++++++++++++++++++++++++++ - target/loongarch64/translate.c | 2892 +++++++++++++++++++++++++ - target/meson.build | 1 + - 30 files changed, 15656 insertions(+) - create mode 100644 target/loongarch64/Kconfig - create mode 100644 target/loongarch64/arch_dump.c - create mode 100644 target/loongarch64/cpu-csr.h - create mode 100644 target/loongarch64/cpu-param.h - create mode 100644 target/loongarch64/cpu-qom.h - create mode 100644 target/loongarch64/cpu.c - create mode 100644 target/loongarch64/cpu.h - create mode 100644 target/loongarch64/csr_helper.c - create mode 100644 target/loongarch64/fpu.c - create mode 100644 target/loongarch64/fpu_helper.c - create mode 100644 target/loongarch64/fpu_helper.h - create mode 100644 target/loongarch64/gdbstub.c - create mode 100644 target/loongarch64/helper.c - create mode 100644 target/loongarch64/helper.h - create mode 100644 target/loongarch64/insn.decode - create mode 100644 target/loongarch64/instmap.h - create mode 100644 target/loongarch64/internal.h - create mode 100644 target/loongarch64/kvm.c - create mode 100644 target/loongarch64/kvm_larch.h - create mode 100644 target/loongarch64/larch-defs.h - create mode 100644 target/loongarch64/machine.c - create mode 100644 target/loongarch64/meson.build - create mode 100644 target/loongarch64/op_helper.c - create mode 100644 target/loongarch64/stabletimer.c - create mode 100644 target/loongarch64/tlb_helper.c - create mode 100644 target/loongarch64/trace-events - create mode 100644 target/loongarch64/trans.inc.c - create mode 100644 target/loongarch64/translate.c - -diff --git a/target/Kconfig b/target/Kconfig -index ae7f24fc6..50b46d048 100644 ---- a/target/Kconfig -+++ b/target/Kconfig -@@ -4,6 +4,7 @@ source avr/Kconfig - source cris/Kconfig - source hppa/Kconfig - source i386/Kconfig -+source loongarch64/Kconfig - source m68k/Kconfig - source microblaze/Kconfig - source mips/Kconfig -diff --git a/target/loongarch64/Kconfig b/target/loongarch64/Kconfig -new file mode 100644 -index 000000000..46b26b1a8 ---- /dev/null -+++ b/target/loongarch64/Kconfig -@@ -0,0 +1,2 @@ -+config LOONGARCH64 -+ bool -diff --git a/target/loongarch64/arch_dump.c b/target/loongarch64/arch_dump.c -new file mode 100644 -index 000000000..7b8708fdf ---- /dev/null -+++ b/target/loongarch64/arch_dump.c -@@ -0,0 +1,174 @@ -+/* Support for writing ELF notes for RM architectures -+ * -+ * Copyright (C) 2015 Red Hat Inc. -+ * -+ * Author: Andrew Jones -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program 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 General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "cpu.h" -+#include "elf.h" -+#include "sysemu/dump.h" -+#include "internal.h" -+ -+/* struct user_pt_regs from arch/loongarch/include/uapi/asm/ptrace.h */ -+struct loongarch_user_regs { -+ uint64_t gpr[32]; -+ uint64_t lo; -+ uint64_t hi; -+ uint64_t csr_era; -+ uint64_t csr_badvaddr; -+ uint64_t csr_crmd; -+ uint64_t csr_ecfg; -+ uint64_t pad[7]; -+} QEMU_PACKED; -+ -+QEMU_BUILD_BUG_ON(sizeof(struct loongarch_user_regs) != 360); -+ -+/* struct elf_prstatus from include/uapi/linux/elfcore.h */ -+struct loongarch_elf_prstatus { -+ char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */ -+ uint32_t pr_pid; -+ char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) - -+ offsetof(struct elf_prstatus, pr_ppid) */ -+ struct loongarch_user_regs pr_reg; -+ uint32_t pr_fpvalid; -+ char pad3[4]; -+} QEMU_PACKED; -+ -+QEMU_BUILD_BUG_ON(sizeof(struct loongarch_elf_prstatus) != 480); -+ -+/* struct user_fpsimd_state from arch/arm64/include/uapi/asm/ptrace.h -+ * -+ * While the vregs member of user_fpsimd_state is of type __uint128_t, -+ * QEMU uses an array of uint64_t, where the high half of the 128-bit -+ * value is always in the 2n+1'th index. Thus we also break the 128- -+ * bit values into two halves in this reproduction of user_fpsimd_state. -+ */ -+ -+struct loongarch_fpu_struct { -+ uint64_t fpr[32]; -+ unsigned int fir; -+ unsigned int fcsr; -+} QEMU_PACKED; -+ -+QEMU_BUILD_BUG_ON(sizeof(struct loongarch_fpu_struct) != 264); -+ -+struct loongarch_note { -+ Elf64_Nhdr hdr; -+ char name[8]; /* align_up(sizeof("CORE"), 4) */ -+ union { -+ struct loongarch_elf_prstatus prstatus; -+ struct loongarch_fpu_struct fpu; -+ }; -+} QEMU_PACKED; -+ -+#define LOONGARCH_NOTE_HEADER_SIZE offsetof(struct loongarch_note, prstatus) -+#define LOONGARCH_PRSTATUS_NOTE_SIZE (LOONGARCH_NOTE_HEADER_SIZE + \ -+ sizeof(struct loongarch_elf_prstatus)) -+#define LOONGARCH_PRFPREG_NOTE_SIZE (LOONGARCH_NOTE_HEADER_SIZE + \ -+ sizeof(struct loongarch_fpu_struct)) -+ -+static void loongarch_note_init(struct loongarch_note *note, DumpState *s, -+ const char *name, Elf64_Word namesz, -+ Elf64_Word type, Elf64_Word descsz) -+{ -+ memset(note, 0, sizeof(*note)); -+ -+ note->hdr.n_namesz = cpu_to_dump32(s, namesz); -+ note->hdr.n_descsz = cpu_to_dump32(s, descsz); -+ note->hdr.n_type = cpu_to_dump32(s, type); -+ -+ memcpy(note->name, name, namesz); -+} -+ -+static int loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f, -+ CPULOONGARCHState *env, int cpuid, -+ DumpState *s) -+{ -+ struct loongarch_note note; -+ int ret, i; -+ -+ loongarch_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.fpu)); -+ -+ note.fpu.fcsr = cpu_to_dump64(s, env->active_fpu.fcsr0); -+ -+ for (i = 0; i < 32; ++i) { -+ note.fpu.fpr[i] = cpu_to_dump64(s, env->active_fpu.fpr[i].fd); -+ } -+ -+ ret = f(¬e, LOONGARCH_PRFPREG_NOTE_SIZE, s); -+ if (ret < 0) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, -+ int cpuid, DumpState *s) -+{ -+ struct loongarch_note note; -+ CPULOONGARCHState *env = &LOONGARCH_CPU(cs)->env; -+ int ret, i; -+ -+ loongarch_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus)); -+ -+ note.prstatus.pr_pid = cpu_to_dump32(s, cpuid); -+ note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1); -+ -+ for (i = 0; i < 32; ++i) { -+ note.prstatus.pr_reg.gpr[i] = cpu_to_dump64(s, env->active_tc.gpr[i]); -+ } -+ note.prstatus.pr_reg.csr_era = cpu_to_dump64(s, env->CSR_ERA); -+ note.prstatus.pr_reg.csr_badvaddr = cpu_to_dump64(s, env->CSR_BADV); -+ note.prstatus.pr_reg.csr_crmd = cpu_to_dump64(s, env->CSR_CRMD); -+ note.prstatus.pr_reg.csr_ecfg = cpu_to_dump64(s, env->CSR_ECFG); -+ -+ ret = f(¬e, LOONGARCH_PRSTATUS_NOTE_SIZE, s); -+ if (ret < 0) { -+ return -1; -+ } -+ -+ ret = loongarch_write_elf64_fprpreg(f, env, cpuid, s); -+ if (ret < 0) { -+ return -1; -+ } -+ -+ return ret; -+} -+ -+int cpu_get_dump_info(ArchDumpInfo *info, -+ const GuestPhysBlockList *guest_phys_blocks) -+{ -+ info->d_machine = EM_LOONGARCH; -+ info->d_endian = ELFDATA2LSB; -+ info->d_class = ELFCLASS64; -+ -+ return 0; -+} -+ -+ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) -+{ -+ size_t note_size = 0; -+ -+ if (class == ELFCLASS64) { -+ note_size = LOONGARCH_PRSTATUS_NOTE_SIZE + LOONGARCH_PRFPREG_NOTE_SIZE; -+ } -+ -+ return note_size * nr_cpus; -+} -+ -diff --git a/target/loongarch64/cpu-csr.h b/target/loongarch64/cpu-csr.h -new file mode 100644 -index 000000000..e549bb46b ---- /dev/null -+++ b/target/loongarch64/cpu-csr.h -@@ -0,0 +1,869 @@ -+#ifndef _CPU_CSR_H_ -+#define _CPU_CSR_H_ -+ -+/* basic CSR register */ -+#define LOONGARCH_CSR_CRMD 0x0 /* 32 current mode info */ -+#define CSR_CRMD_DACM_SHIFT 7 -+#define CSR_CRMD_DACM_WIDTH 2 -+#define CSR_CRMD_DACM (0x3UL << CSR_CRMD_DACM_SHIFT) -+#define CSR_CRMD_DACF_SHIFT 5 -+#define CSR_CRMD_DACF_WIDTH 2 -+#define CSR_CRMD_DACF (0x3UL << CSR_CRMD_DACF_SHIFT) -+#define CSR_CRMD_PG_SHIFT 4 -+#define CSR_CRMD_PG (0x1UL << CSR_CRMD_PG_SHIFT) -+#define CSR_CRMD_DA_SHIFT 3 -+#define CSR_CRMD_DA (0x1UL << CSR_CRMD_DA_SHIFT) -+#define CSR_CRMD_IE_SHIFT 2 -+#define CSR_CRMD_IE (0x1UL << CSR_CRMD_IE_SHIFT) -+#define CSR_CRMD_PLV_SHIFT 0 -+#define CSR_CRMD_PLV_WIDTH 2 -+#define CSR_CRMD_PLV (0x3UL << CSR_CRMD_PLV_SHIFT) -+ -+#define PLV_USER 3 -+#define PLV_KERN 0 -+#define PLV_MASK 0x3 -+ -+#define LOONGARCH_CSR_PRMD 0x1 /* 32 prev-exception mode info */ -+#define CSR_PRMD_PIE_SHIFT 2 -+#define CSR_PRMD_PIE (0x1UL << CSR_PRMD_PIE_SHIFT) -+#define CSR_PRMD_PPLV_SHIFT 0 -+#define CSR_PRMD_PPLV_WIDTH 2 -+#define CSR_PRMD_PPLV (0x3UL << CSR_PRMD_PPLV_SHIFT) -+ -+#define LOONGARCH_CSR_EUEN 0x2 /* 32 coprocessor enable */ -+#define CSR_EUEN_LBTEN_SHIFT 3 -+#define CSR_EUEN_LBTEN (0x1UL << CSR_EUEN_LBTEN_SHIFT) -+#define CSR_EUEN_LASXEN_SHIFT 2 -+#define CSR_EUEN_LASXEN (0x1UL << CSR_EUEN_LASXEN_SHIFT) -+#define CSR_EUEN_LSXEN_SHIFT 1 -+#define CSR_EUEN_LSXEN (0x1UL << CSR_EUEN_LSXEN_SHIFT) -+#define CSR_EUEN_FPEN_SHIFT 0 -+#define CSR_EUEN_FPEN (0x1UL << CSR_EUEN_FPEN_SHIFT) -+ -+#define LOONGARCH_CSR_MISC 0x3 /* 32 misc config */ -+ -+#define LOONGARCH_CSR_ECFG 0x4 /* 32 exception config */ -+#define CSR_ECFG_VS_SHIFT 16 -+#define CSR_ECFG_VS_WIDTH 3 -+#define CSR_ECFG_VS (0x7UL << CSR_ECFG_VS_SHIFT) -+#define CSR_ECFG_IM_SHIFT 0 -+#define CSR_ECFG_IM_WIDTH 13 -+#define CSR_ECFG_IM (0x1fffUL << CSR_ECFG_IM_SHIFT) -+ -+#define CSR_ECFG_IPMASK 0x00001fff -+ -+#define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ -+#define CSR_ESTAT_ESUBCODE_SHIFT 22 -+#define CSR_ESTAT_ESUBCODE_WIDTH 9 -+#define CSR_ESTAT_ESUBCODE (0x1ffULL << CSR_ESTAT_ESUBCODE_SHIFT) -+#define CSR_ESTAT_EXC_SH 16 -+#define CSR_ESTAT_EXC_WIDTH 5 -+#define CSR_ESTAT_EXC (0x1fULL << CSR_ESTAT_EXC_SH) -+#define CSR_ESTAT_IS_SHIFT 0 -+#define CSR_ESTAT_IS_WIDTH 15 -+#define CSR_ESTAT_IS (0x7fffULL << CSR_ESTAT_IS_SHIFT) -+ -+#define CSR_ESTAT_IPMASK 0x00001fff -+ -+#define EXCODE_IP 64 -+#define EXCCODE_RSV 0 -+#define EXCCODE_TLBL 1 -+#define EXCCODE_TLBS 2 -+#define EXCCODE_TLBI 3 -+#define EXCCODE_MOD 4 -+#define EXCCODE_TLBRI 5 -+#define EXCCODE_TLBXI 6 -+#define EXCCODE_TLBPE 7 -+#define EXCCODE_ADE 8 -+#define EXCCODE_UNALIGN 9 -+#define EXCCODE_OOB 10 -+#define EXCCODE_SYS 11 -+#define EXCCODE_BP 12 -+#define EXCCODE_RI 13 -+#define EXCCODE_IPE 14 -+#define EXCCODE_FPDIS 15 -+#define EXCCODE_LSXDIS 16 -+#define EXCCODE_LASXDIS 17 -+#define EXCCODE_FPE 18 -+#define EXCCODE_WATCH 19 -+#define EXCCODE_BTDIS 20 -+#define EXCCODE_BTE 21 -+#define EXCCODE_PSI 22 -+#define EXCCODE_HYP 23 -+#define EXCCODE_FC 24 -+#define EXCCODE_SE 25 -+ -+#define LOONGARCH_CSR_ERA 0x6 /* 64 error PC */ -+ -+#define LOONGARCH_CSR_BADV 0x7 /* 64 bad virtual address */ -+ -+#define LOONGARCH_CSR_BADI 0x8 /* 32 bad instruction */ -+ -+#define LOONGARCH_CSR_EEPN 0xc /* 64 exception enter base address */ -+#define LOONGARCH_EEPN_CPUID (0x3ffULL << 0) -+ -+#define CU_FPE 1 -+#define CU_LSXE (1 << 1) -+#define CU_LASXE (1 << 2) -+#define CU_LBTE (1 << 3) -+ -+/* TLB related CSR register : start with TLB if no pagewalk */ -+/* 32 TLB Index, EHINV, PageSize, is_gtlb */ -+#define LOONGARCH_CSR_TLBIDX 0x10 -+#define CSR_TLBIDX_EHINV_SHIFT 31 -+#define CSR_TLBIDX_EHINV (0x1ULL << CSR_TLBIDX_EHINV_SHIFT) -+#define CSR_TLBIDX_PS_SHIFT 24 -+#define CSR_TLBIDX_PS_WIDTH 6 -+#define CSR_TLBIDX_PS (0x3fULL << CSR_TLBIDX_PS_SHIFT) -+#define CSR_TLBIDX_IDX_SHIFT 0 -+#define CSR_TLBIDX_IDX_WIDTH 12 -+#define CSR_TLBIDX_IDX (0xfffULL << CSR_TLBIDX_IDX_SHIFT) -+#define CSR_TLBIDX_SIZEM 0x3f000000 -+#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT -+#define CSR_TLBIDX_IDXM 0xfff -+ -+#define LOONGARCH_CSR_TLBEHI 0x11 /* 64 TLB EntryHi without ASID */ -+ -+#define LOONGARCH_CSR_TLBELO0 0x12 /* 64 TLB EntryLo0 */ -+#define CSR_TLBLO0_RPLV_SHIFT 63 -+#define CSR_TLBLO0_RPLV (0x1ULL << CSR_TLBLO0_RPLV_SHIFT) -+#define CSR_TLBLO0_XI_SHIFT 62 -+#define CSR_TLBLO0_XI (0x1ULL << CSR_TLBLO0_XI_SHIFT) -+#define CSR_TLBLO0_RI_SHIFT 61 -+#define CSR_TLBLO0_RI (0x1ULL << CSR_TLBLO0_RI_SHIFT) -+#define CSR_TLBLO0_PPN_SHIFT 12 -+#define CSR_TLBLO0_PPN_WIDTH 36 /* ignore lower 12bits */ -+#define CSR_TLBLO0_PPN (0xfffffffffULL << CSR_TLBLO0_PPN_SHIFT) -+#define CSR_TLBLO0_GLOBAL_SHIFT 6 -+#define CSR_TLBLO0_GLOBAL (0x1ULL << CSR_TLBLO0_GLOBAL_SHIFT) -+#define CSR_TLBLO0_CCA_SHIFT 4 -+#define CSR_TLBLO0_CCA_WIDTH 2 -+#define CSR_TLBLO0_CCA (0x3ULL << CSR_TLBLO0_CCA_SHIFT) -+#define CSR_TLBLO0_PLV_SHIFT 2 -+#define CSR_TLBLO0_PLV_WIDTH 2 -+#define CSR_TLBLO0_PLV (0x3ULL << CSR_TLBLO0_PLV_SHIFT) -+#define CSR_TLBLO0_WE_SHIFT 1 -+#define CSR_TLBLO0_WE (0x1ULL << CSR_TLBLO0_WE_SHIFT) -+#define CSR_TLBLO0_V_SHIFT 0 -+#define CSR_TLBLO0_V (0x1ULL << CSR_TLBLO0_V_SHIFT) -+ -+#define LOONGARCH_CSR_TLBELO1 0x13 /* 64 TLB EntryLo1 */ -+#define CSR_TLBLO1_RPLV_SHIFT 63 -+#define CSR_TLBLO1_RPLV (0x1ULL << CSR_TLBLO1_RPLV_SHIFT) -+#define CSR_TLBLO1_XI_SHIFT 62 -+#define CSR_TLBLO1_XI (0x1ULL << CSR_TLBLO1_XI_SHIFT) -+#define CSR_TLBLO1_RI_SHIFT 61 -+#define CSR_TLBLO1_RI (0x1ULL << CSR_TLBLO1_RI_SHIFT) -+#define CSR_TLBLO1_PPN_SHIFT 12 -+#define CSR_TLBLO1_PPN_WIDTH 36 /* ignore lower 12bits */ -+#define CSR_TLBLO1_PPN (0xfffffffffULL << CSR_TLBLO1_PPN_SHIFT) -+#define CSR_TLBLO1_GLOBAL_SHIFT 6 -+#define CSR_TLBLO1_GLOBAL (0x1ULL << CSR_TLBLO1_GLOBAL_SHIFT) -+#define CSR_TLBLO1_CCA_SHIFT 4 -+#define CSR_TLBLO1_CCA_WIDTH 2 -+#define CSR_TLBLO1_CCA (0x3ULL << CSR_TLBLO1_CCA_SHIFT) -+#define CSR_TLBLO1_PLV_SHIFT 2 -+#define CSR_TLBLO1_PLV_WIDTH 2 -+#define CSR_TLBLO1_PLV (0x3ULL << CSR_TLBLO1_PLV_SHIFT) -+#define CSR_TLBLO1_WE_SHIFT 1 -+#define CSR_TLBLO1_WE (0x1ULL << CSR_TLBLO1_WE_SHIFT) -+#define CSR_TLBLO1_V_SHIFT 0 -+#define CSR_TLBLO1_V (0x1ULL << CSR_TLBLO1_V_SHIFT) -+ -+#define LOONGARCH_ENTRYLO_RI (1ULL << 61) -+#define LOONGARCH_ENTRYLO_XI (1ULL << 62) -+ -+#define LOONGARCH_CSR_TLBWIRED 0x14 /* 32 TLB wired */ -+#define LOONGARCH_CSR_GTLBC 0x15 /* guest-related TLB */ -+#define CSR_GTLBC_RID_SHIFT 16 -+#define CSR_GTLBC_RID_WIDTH 8 -+#define CSR_GTLBC_RID (0xffULL << CSR_GTLBC_RID_SHIFT) -+#define CSR_GTLBC_TOTI_SHIFT 13 -+#define CSR_GTLBC_TOTI (0x1ULL << CSR_GTLBC_TOTI_SHIFT) -+#define CSR_GTLBC_USERID_SHIFT 12 -+#define CSR_GTLBC_USERID (0x1ULL << CSR_GTLBC_USERID_SHIFT) -+#define CSR_GTLBC_GMTLBSZ_SHIFT 0 -+#define CSR_GTLBC_GMTLBSZ_WIDTH 6 -+#define CSR_GTLBC_GMTLBSZ (0x3fULL << CSR_GTLBC_GVTLBSZ_SHIFT) -+ -+#define LOONGARCH_CSR_TRGP 0x16 /* guest-related TLB */ -+#define CSR_TRGP_RID_SHIFT 16 -+#define CSR_TRGP_RID_WIDTH 8 -+#define CSR_TRGP_RID (0xffULL << CSR_TRGP_RID_SHIFT) -+#define CSR_TRGP_GTLB_SHIFT 0 -+#define CSR_TRGP_GTLB (1 << CSR_TRGP_GTLB_SHIFT) -+ -+#define LOONGARCH_CSR_ASID 0x18 /* 64 ASID */ -+#define CSR_ASID_BIT_SHIFT 16 /* ASIDBits */ -+#define CSR_ASID_BIT_WIDTH 8 -+#define CSR_ASID_BIT (0xffULL << CSR_ASID_BIT_SHIFT) -+#define CSR_ASID_ASID_SHIFT 0 -+#define CSR_ASID_ASID_WIDTH 10 -+#define CSR_ASID_ASID (0x3ffULL << CSR_ASID_ASID_SHIFT) -+ -+/* 64 page table base address when badv[47] = 0 */ -+#define LOONGARCH_CSR_PGDL 0x19 -+/* 64 page table base address when badv[47] = 1 */ -+#define LOONGARCH_CSR_PGDH 0x1a -+ -+#define LOONGARCH_CSR_PGD 0x1b /* 64 page table base */ -+ -+#define LOONGARCH_CSR_PWCTL0 0x1c /* 64 PWCtl0 */ -+#define CSR_PWCTL0_PTEW_SHIFT 30 -+#define CSR_PWCTL0_PTEW_WIDTH 2 -+#define CSR_PWCTL0_PTEW (0x3ULL << CSR_PWCTL0_PTEW_SHIFT) -+#define CSR_PWCTL0_DIR1WIDTH_SHIFT 25 -+#define CSR_PWCTL0_DIR1WIDTH_WIDTH 5 -+#define CSR_PWCTL0_DIR1WIDTH (0x1fULL << CSR_PWCTL0_DIR1WIDTH_SHIFT) -+#define CSR_PWCTL0_DIR1BASE_SHIFT 20 -+#define CSR_PWCTL0_DIR1BASE_WIDTH 5 -+#define CSR_PWCTL0_DIR1BASE (0x1fULL << CSR_PWCTL0_DIR1BASE_SHIFT) -+#define CSR_PWCTL0_DIR0WIDTH_SHIFT 15 -+#define CSR_PWCTL0_DIR0WIDTH_WIDTH 5 -+#define CSR_PWCTL0_DIR0WIDTH (0x1fULL << CSR_PWCTL0_DIR0WIDTH_SHIFT) -+#define CSR_PWCTL0_DIR0BASE_SHIFT 10 -+#define CSR_PWCTL0_DIR0BASE_WIDTH 5 -+#define CSR_PWCTL0_DIR0BASE (0x1fULL << CSR_PWCTL0_DIR0BASE_SHIFT) -+#define CSR_PWCTL0_PTWIDTH_SHIFT 5 -+#define CSR_PWCTL0_PTWIDTH_WIDTH 5 -+#define CSR_PWCTL0_PTWIDTH (0x1fULL << CSR_PWCTL0_PTWIDTH_SHIFT) -+#define CSR_PWCTL0_PTBASE_SHIFT 0 -+#define CSR_PWCTL0_PTBASE_WIDTH 5 -+#define CSR_PWCTL0_PTBASE (0x1fULL << CSR_PWCTL0_PTBASE_SHIFT) -+ -+#define LOONGARCH_CSR_PWCTL1 0x1d /* 64 PWCtl1 */ -+#define CSR_PWCTL1_DIR3WIDTH_SHIFT 18 -+#define CSR_PWCTL1_DIR3WIDTH_WIDTH 5 -+#define CSR_PWCTL1_DIR3WIDTH (0x1fULL << CSR_PWCTL1_DIR3WIDTH_SHIFT) -+#define CSR_PWCTL1_DIR3BASE_SHIFT 12 -+#define CSR_PWCTL1_DIR3BASE_WIDTH 5 -+#define CSR_PWCTL1_DIR3BASE (0x1fULL << CSR_PWCTL0_DIR3BASE_SHIFT) -+#define CSR_PWCTL1_DIR2WIDTH_SHIFT 6 -+#define CSR_PWCTL1_DIR2WIDTH_WIDTH 5 -+#define CSR_PWCTL1_DIR2WIDTH (0x1fULL << CSR_PWCTL1_DIR2WIDTH_SHIFT) -+#define CSR_PWCTL1_DIR2BASE_SHIFT 0 -+#define CSR_PWCTL1_DIR2BASE_WIDTH 5 -+#define CSR_PWCTL1_DIR2BASE (0x1fULL << CSR_PWCTL0_DIR2BASE_SHIFT) -+ -+#define LOONGARCH_CSR_STLBPGSIZE 0x1e /* 64 */ -+#define CSR_STLBPGSIZE_PS_WIDTH 6 -+#define CSR_STLBPGSIZE_PS (0x3f) -+ -+#define LOONGARCH_CSR_RVACFG 0x1f -+#define CSR_RVACFG_RDVA_WIDTH 4 -+#define CSR_RVACFG_RDVA (0xf) -+ -+/* read only CSR register : start with CPU */ -+#define LOONGARCH_CSR_CPUID 0x20 /* 32 CPU core number */ -+#define CSR_CPUID_CID_WIDTH 9 -+#define CSR_CPUID_CID (0x1ff) -+ -+#define LOONGARCH_CSR_PRCFG1 0x21 /* 32 CPU info */ -+#define CSR_CONF1_VSMAX_SHIFT 12 -+#define CSR_CONF1_VSMAX_WIDTH 3 -+#define CSR_CONF1_VSMAX (7ULL << CSR_CONF1_VSMAX_SHIFT) -+/* stable timer bits - 1, 0x2f = 47*/ -+#define CSR_CONF1_TMRBITS_SHIFT 4 -+#define CSR_CONF1_TMRBITS_WIDTH 8 -+#define CSR_CONF1_TMRBITS (0xffULL << CSR_CONF1_TMRBITS_SHIFT) -+#define CSR_CONF1_KSNUM_SHIFT 0 -+#define CSR_CONF1_KSNUM_WIDTH 4 -+#define CSR_CONF1_KSNUM (0x8) -+ -+#define LOONGARCH_CSR_PRCFG2 0x22 -+#define CSR_CONF2_PGMASK_SUPP 0x3ffff000 -+ -+#define LOONGARCH_CSR_PRCFG3 0x23 -+#define CSR_CONF3_STLBIDX_SHIFT 20 -+#define CSR_CONF3_STLBIDX_WIDTH 6 -+#define CSR_CONF3_STLBIDX (0x3fULL << CSR_CONF3_STLBIDX_SHIFT) -+#define CSR_STLB_SETS 256 -+#define CSR_CONF3_STLBWAYS_SHIFT 12 -+#define CSR_CONF3_STLBWAYS_WIDTH 8 -+#define CSR_CONF3_STLBWAYS (0xffULL << CSR_CONF3_STLBWAYS_SHIFT) -+#define CSR_STLBWAYS_SIZE 8 -+#define CSR_CONF3_MTLBSIZE_SHIFT 4 -+#define CSR_CONF3_MTLBSIZE_WIDTH 8 -+#define CSR_CONF3_MTLBSIZE (0xffULL << CSR_CONF3_MTLBSIZE_SHIFT) -+/* mean VTLB 64 index */ -+#define CSR_MTLB_SIZE 64 -+#define CSR_CONF3_TLBORG_SHIFT 0 -+#define CSR_CONF3_TLBORG_WIDTH 4 -+#define CSR_CONF3_TLBORG (0xfULL << CSR_CONF3_TLBORG_SHIFT) -+/* mean use MTLB+STLB */ -+#define TLB_ORG 2 -+ -+/* Kscratch : start with KS */ -+#define LOONGARCH_CSR_KS0 0x30 /* 64 */ -+#define LOONGARCH_CSR_KS1 0x31 /* 64 */ -+#define LOONGARCH_CSR_KS2 0x32 /* 64 */ -+#define LOONGARCH_CSR_KS3 0x33 /* 64 */ -+#define LOONGARCH_CSR_KS4 0x34 /* 64 */ -+#define LOONGARCH_CSR_KS5 0x35 /* 64 */ -+#define LOONGARCH_CSR_KS6 0x36 /* 64 */ -+#define LOONGARCH_CSR_KS7 0x37 /* 64 */ -+#define LOONGARCH_CSR_KS8 0x38 /* 64 */ -+ -+/* timer : start with TM */ -+#define LOONGARCH_CSR_TMID 0x40 /* 32 timer ID */ -+ -+#define LOONGARCH_CSR_TCFG 0x41 /* 64 timer config */ -+#define CSR_TCFG_VAL_SHIFT 2 -+#define CSR_TCFG_VAL_WIDTH 48 -+#define CSR_TCFG_VAL (0x3fffffffffffULL << CSR_TCFG_VAL_SHIFT) -+#define CSR_TCFG_PERIOD_SHIFT 1 -+#define CSR_TCFG_PERIOD (0x1ULL << CSR_TCFG_PERIOD_SHIFT) -+#define CSR_TCFG_EN (0x1) -+ -+#define LOONGARCH_CSR_TVAL 0x42 /* 64 timer ticks remain */ -+ -+#define LOONGARCH_CSR_CNTC 0x43 /* 64 timer offset */ -+ -+#define LOONGARCH_CSR_TINTCLR 0x44 /* 64 timer interrupt clear */ -+#define CSR_TINTCLR_TI_SHIFT 0 -+#define CSR_TINTCLR_TI (1 << CSR_TINTCLR_TI_SHIFT) -+ -+/* guest : start with GST */ -+#define LOONGARCH_CSR_GSTAT 0x50 /* 32 basic guest info */ -+#define CSR_GSTAT_GID_SHIFT 16 -+#define CSR_GSTAT_GID_WIDTH 8 -+#define CSR_GSTAT_GID (0xffULL << CSR_GSTAT_GID_SHIFT) -+#define CSR_GSTAT_GIDBIT_SHIFT 4 -+#define CSR_GSTAT_GIDBIT_WIDTH 6 -+#define CSR_GSTAT_GIDBIT (0x3fULL << CSR_GSTAT_GIDBIT_SHIFT) -+#define CSR_GSTAT_PVM_SHIFT 1 -+#define CSR_GSTAT_PVM (0x1ULL << CSR_GSTAT_PVM_SHIFT) -+#define CSR_GSTAT_VM_SHIFT 0 -+#define CSR_GSTAT_VM (0x1ULL << CSR_GSTAT_VM_SHIFT) -+ -+#define LOONGARCH_CSR_GCFG 0x51 /* 32 guest config */ -+#define CSR_GCFG_GPERF_SHIFT 24 -+#define CSR_GCFG_GPERF_WIDTH 3 -+#define CSR_GCFG_GPERF (0x7ULL << CSR_GCFG_GPERF_SHIFT) -+#define CSR_GCFG_GCI_SHIFT 20 -+#define CSR_GCFG_GCI_WIDTH 2 -+#define CSR_GCFG_GCI (0x3ULL << CSR_GCFG_GCI_SHIFT) -+#define CSR_GCFG_GCI_ALL (0x0ULL << CSR_GCFG_GCI_SHIFT) -+#define CSR_GCFG_GCI_HIT (0x1ULL << CSR_GCFG_GCI_SHIFT) -+#define CSR_GCFG_GCI_SECURE (0x2ULL << CSR_GCFG_GCI_SHIFT) -+#define CSR_GCFG_GCIP_SHIFT 16 -+#define CSR_GCFG_GCIP (0xfULL << CSR_GCFG_GCIP_SHIFT) -+#define CSR_GCFG_GCIP_ALL (0x1ULL << CSR_GCFG_GCIP_SHIFT) -+#define CSR_GCFG_GCIP_HIT (0x1ULL << (CSR_GCFG_GCIP_SHIFT + 1)) -+#define CSR_GCFG_GCIP_SECURE (0x1ULL << (CSR_GCFG_GCIP_SHIFT + 2)) -+#define CSR_GCFG_TORU_SHIFT 15 -+#define CSR_GCFG_TORU (0x1ULL << CSR_GCFG_TORU_SHIFT) -+#define CSR_GCFG_TORUP_SHIFT 14 -+#define CSR_GCFG_TORUP (0x1ULL << CSR_GCFG_TORUP_SHIFT) -+#define CSR_GCFG_TOP_SHIFT 13 -+#define CSR_GCFG_TOP (0x1ULL << CSR_GCFG_TOP_SHIFT) -+#define CSR_GCFG_TOPP_SHIFT 12 -+#define CSR_GCFG_TOPP (0x1ULL << CSR_GCFG_TOPP_SHIFT) -+#define CSR_GCFG_TOE_SHIFT 11 -+#define CSR_GCFG_TOE (0x1ULL << CSR_GCFG_TOE_SHIFT) -+#define CSR_GCFG_TOEP_SHIFT 10 -+#define CSR_GCFG_TOEP (0x1ULL << CSR_GCFG_TOEP_SHIFT) -+#define CSR_GCFG_TIT_SHIFT 9 -+#define CSR_GCFG_TIT (0x1ULL << CSR_GCFG_TIT_SHIFT) -+#define CSR_GCFG_TITP_SHIFT 8 -+#define CSR_GCFG_TITP (0x1ULL << CSR_GCFG_TITP_SHIFT) -+#define CSR_GCFG_SIT_SHIFT 7 -+#define CSR_GCFG_SIT (0x1ULL << CSR_GCFG_SIT_SHIFT) -+#define CSR_GCFG_SITP_SHIFT 6 -+#define CSR_GCFG_SITP (0x1ULL << CSR_GCFG_SITP_SHIFT) -+#define CSR_GCFG_CACTRL_SHIFT 4 -+#define CSR_GCFG_CACTRL_WIDTH 2 -+#define CSR_GCFG_CACTRL (0x3ULL << CSR_GCFG_CACTRL_SHIFT) -+#define CSR_GCFG_CACTRL_GUEST (0x0ULL << CSR_GCFG_CACTRL_SHIFT) -+#define CSR_GCFG_CACTRL_ROOT (0x1ULL << CSR_GCFG_CACTRL_SHIFT) -+#define CSR_GCFG_CACTRL_NEST (0x2ULL << CSR_GCFG_CACTRL_SHIFT) -+#define CSR_GCFG_CCCP_WIDTH 4 -+#define CSR_GCFG_CCCP (0xf) -+#define CSR_GCFG_CCCP_GUEST (0x1ULL << 0) -+#define CSR_GCFG_CCCP_ROOT (0x1ULL << 1) -+#define CSR_GCFG_CCCP_NEST (0x1ULL << 2) -+ -+#define LOONGARCH_CSR_GINTC 0x52 /* 64 guest exception control */ -+#define CSR_GINTC_HC_SHIFT 16 -+#define CSR_GINTC_HC_WIDTH 8 -+#define CSR_GINTC_HC (0xffULL << CSR_GINTC_HC_SHIFT) -+#define CSR_GINTC_PIP_SHIFT 8 -+#define CSR_GINTC_PIP_WIDTH 8 -+#define CSR_GINTC_PIP (0xffULL << CSR_GINTC_PIP_SHIFT) -+#define CSR_GINTC_VIP_SHIFT 0 -+#define CSR_GINTC_VIP_WIDTH 8 -+#define CSR_GINTC_VIP (0xff) -+ -+#define LOONGARCH_CSR_GCNTC 0x53 /* 64 guest timer offset */ -+ -+/* LLBCTL */ -+#define LOONGARCH_CSR_LLBCTL 0x60 /* 32 csr number to be changed */ -+#define CSR_LLBCTL_ROLLB_SHIFT 0 -+#define CSR_LLBCTL_ROLLB (1ULL << CSR_LLBCTL_ROLLB_SHIFT) -+#define CSR_LLBCTL_WCLLB_SHIFT 1 -+#define CSR_LLBCTL_WCLLB (1ULL << CSR_LLBCTL_WCLLB_SHIFT) -+#define CSR_LLBCTL_KLO_SHIFT 2 -+#define CSR_LLBCTL_KLO (1ULL << CSR_LLBCTL_KLO_SHIFT) -+ -+/* implement dependent */ -+#define LOONGARCH_CSR_IMPCTL1 0x80 /* 32 loongarch config */ -+#define CSR_MISPEC_SHIFT 20 -+#define CSR_MISPEC_WIDTH 8 -+#define CSR_MISPEC (0xffULL << CSR_MISPEC_SHIFT) -+#define CSR_SSEN_SHIFT 18 -+#define CSR_SSEN (1ULL << CSR_SSEN_SHIFT) -+#define CSR_SCRAND_SHIFT 17 -+#define CSR_SCRAND (1ULL << CSR_SCRAND_SHIFT) -+#define CSR_LLEXCL_SHIFT 16 -+#define CSR_LLEXCL (1ULL << CSR_LLEXCL_SHIFT) -+#define CSR_DISVC_SHIFT 15 -+#define CSR_DISVC (1ULL << CSR_DISVC_SHIFT) -+#define CSR_VCLRU_SHIFT 14 -+#define CSR_VCLRU (1ULL << CSR_VCLRU_SHIFT) -+#define CSR_DCLRU_SHIFT 13 -+#define CSR_DCLRU (1ULL << CSR_DCLRU_SHIFT) -+#define CSR_FASTLDQ_SHIFT 12 -+#define CSR_FASTLDQ (1ULL << CSR_FASTLDQ_SHIFT) -+#define CSR_USERCAC_SHIFT 11 -+#define CSR_USERCAC (1ULL << CSR_USERCAC_SHIFT) -+#define CSR_ANTI_MISPEC_SHIFT 10 -+#define CSR_ANTI_MISPEC (1ULL << CSR_ANTI_MISPEC_SHIFT) -+#define CSR_ANTI_FLUSHSFB_SHIFT 9 -+#define CSR_ANTI_FLUSHSFB (1ULL << CSR_ANTI_FLUSHSFB_SHIFT) -+#define CSR_STFILL_SHIFT 8 -+#define CSR_STFILL (1ULL << CSR_STFILL_SHIFT) -+#define CSR_LIFEP_SHIFT 7 -+#define CSR_LIFEP (1ULL << CSR_LIFEP_SHIFT) -+#define CSR_LLSYNC_SHIFT 6 -+#define CSR_LLSYNC (1ULL << CSR_LLSYNC_SHIFT) -+#define CSR_BRBTDIS_SHIFT 5 -+#define CSR_BRBTDIS (1ULL << CSR_BRBTDIS_SHIFT) -+#define CSR_RASDIS_SHIFT 4 -+#define CSR_RASDIS (1ULL << CSR_RASDIS_SHIFT) -+#define CSR_STPRE_SHIFT 2 -+#define CSR_STPRE_WIDTH 2 -+#define CSR_STPRE (3ULL << CSR_STPRE_SHIFT) -+#define CSR_INSTPRE_SHIFT 1 -+#define CSR_INSTPRE (1ULL << CSR_INSTPRE_SHIFT) -+#define CSR_DATAPRE_SHIFT 0 -+#define CSR_DATAPRE (1ULL << CSR_DATAPRE_SHIFT) -+ -+#define LOONGARCH_CSR_IMPCTL2 0x81 /* 32 Flush */ -+#define CSR_IMPCTL2_MTLB_SHIFT 0 -+#define CSR_IMPCTL2_MTLB (1ULL << CSR_IMPCTL2_MTLB_SHIFT) -+#define CSR_IMPCTL2_STLB_SHIFT 1 -+#define CSR_IMPCTL2_STLB (1ULL << CSR_IMPCTL2_STLB_SHIFT) -+#define CSR_IMPCTL2_DTLB_SHIFT 2 -+#define CSR_IMPCTL2_DTLB (1ULL << CSR_IMPCTL2_DTLB_SHIFT) -+#define CSR_IMPCTL2_ITLB_SHIFT 3 -+#define CSR_IMPCTL2_ITLB (1ULL << CSR_IMPCTL2_ITLB_SHIFT) -+#define CSR_IMPCTL2_BTAC_SHIFT 4 -+#define CSR_IMPCTL2_BTAC (1ULL << CSR_IMPCTL2_BTAC_SHIFT) -+ -+#define LOONGARCH_FLUSH_VTLB 1 -+#define LOONGARCH_FLUSH_FTLB (1 << 1) -+#define LOONGARCH_FLUSH_DTLB (1 << 2) -+#define LOONGARCH_FLUSH_ITLB (1 << 3) -+#define LOONGARCH_FLUSH_BTAC (1 << 4) -+ -+#define LOONGARCH_CSR_GNMI 0x82 -+ -+/* TLB Refill Only */ -+#define LOONGARCH_CSR_TLBRENT 0x88 /* 64 TLB refill exception address */ -+#define LOONGARCH_CSR_TLBRBADV 0x89 /* 64 TLB refill badvaddr */ -+#define LOONGARCH_CSR_TLBRERA 0x8a /* 64 TLB refill ERA */ -+#define LOONGARCH_CSR_TLBRSAVE 0x8b /* 64 KScratch for TLB refill */ -+#define LOONGARCH_CSR_TLBRELO0 0x8c /* 64 TLB refill entrylo0 */ -+#define LOONGARCH_CSR_TLBRELO1 0x8d /* 64 TLB refill entrylo1 */ -+#define LOONGARCH_CSR_TLBREHI 0x8e /* 64 TLB refill entryhi */ -+#define LOONGARCH_CSR_TLBRPRMD 0x8f /* 64 TLB refill mode info */ -+ -+/* error related */ -+#define LOONGARCH_CSR_ERRCTL 0x90 /* 32 ERRCTL */ -+#define LOONGARCH_CSR_ERRINFO 0x91 -+#define LOONGARCH_CSR_ERRINFO1 0x92 -+#define LOONGARCH_CSR_ERRENT 0x93 /* 64 error exception base */ -+#define LOONGARCH_CSR_ERRERA 0x94 /* 64 error exception PC */ -+#define LOONGARCH_CSR_ERRSAVE 0x95 /* 64 KScratch for error exception */ -+ -+#define LOONGARCH_CSR_CTAG 0x98 /* 64 TagLo + TagHi */ -+ -+/* direct map windows */ -+#define LOONGARCH_CSR_DMWIN0 0x180 /* 64 direct map win0: MEM & IF */ -+#define LOONGARCH_CSR_DMWIN1 0x181 /* 64 direct map win1: MEM & IF */ -+#define LOONGARCH_CSR_DMWIN2 0x182 /* 64 direct map win2: MEM */ -+#define LOONGARCH_CSR_DMWIN3 0x183 /* 64 direct map win3: MEM */ -+#define CSR_DMW_PLV0 0x1 -+#define CSR_DMW_PLV1 0x2 -+#define CSR_DMW_PLV2 0x4 -+#define CSR_DMW_PLV3 0x8 -+#define CSR_DMW_BASE_SH 48 -+#define dmwin_va2pa(va) \ -+ (va & (((unsigned long)1 << CSR_DMW_BASE_SH) - 1)) -+ -+/* performance counter */ -+#define LOONGARCH_CSR_PERFCTRL0 0x200 /* 32 perf event 0 config */ -+#define LOONGARCH_CSR_PERFCNTR0 0x201 /* 64 perf event 0 count value */ -+#define LOONGARCH_CSR_PERFCTRL1 0x202 /* 32 perf event 1 config */ -+#define LOONGARCH_CSR_PERFCNTR1 0x203 /* 64 perf event 1 count value */ -+#define LOONGARCH_CSR_PERFCTRL2 0x204 /* 32 perf event 2 config */ -+#define LOONGARCH_CSR_PERFCNTR2 0x205 /* 64 perf event 2 count value */ -+#define LOONGARCH_CSR_PERFCTRL3 0x206 /* 32 perf event 3 config */ -+#define LOONGARCH_CSR_PERFCNTR3 0x207 /* 64 perf event 3 count value */ -+#define CSR_PERFCTRL_PLV0 (1ULL << 16) -+#define CSR_PERFCTRL_PLV1 (1ULL << 17) -+#define CSR_PERFCTRL_PLV2 (1ULL << 18) -+#define CSR_PERFCTRL_PLV3 (1ULL << 19) -+#define CSR_PERFCTRL_IE (1ULL << 20) -+#define CSR_PERFCTRL_EVENT 0x3ff -+ -+/* debug */ -+#define LOONGARCH_CSR_MWPC 0x300 /* data breakpoint config */ -+#define LOONGARCH_CSR_MWPS 0x301 /* data breakpoint status */ -+ -+#define LOONGARCH_CSR_DB0ADDR 0x310 /* data breakpoint 0 address */ -+#define LOONGARCH_CSR_DB0MASK 0x311 /* data breakpoint 0 mask */ -+#define LOONGARCH_CSR_DB0CTL 0x312 /* data breakpoint 0 control */ -+#define LOONGARCH_CSR_DB0ASID 0x313 /* data breakpoint 0 asid */ -+ -+#define LOONGARCH_CSR_DB1ADDR 0x318 /* data breakpoint 1 address */ -+#define LOONGARCH_CSR_DB1MASK 0x319 /* data breakpoint 1 mask */ -+#define LOONGARCH_CSR_DB1CTL 0x31a /* data breakpoint 1 control */ -+#define LOONGARCH_CSR_DB1ASID 0x31b /* data breakpoint 1 asid */ -+ -+#define LOONGARCH_CSR_DB2ADDR 0x320 /* data breakpoint 2 address */ -+#define LOONGARCH_CSR_DB2MASK 0x321 /* data breakpoint 2 mask */ -+#define LOONGARCH_CSR_DB2CTL 0x322 /* data breakpoint 2 control */ -+#define LOONGARCH_CSR_DB2ASID 0x323 /* data breakpoint 2 asid */ -+ -+#define LOONGARCH_CSR_DB3ADDR 0x328 /* data breakpoint 3 address */ -+#define LOONGARCH_CSR_DB3MASK 0x329 /* data breakpoint 3 mask */ -+#define LOONGARCH_CSR_DB3CTL 0x32a /* data breakpoint 3 control */ -+#define LOONGARCH_CSR_DB3ASID 0x32b /* data breakpoint 3 asid */ -+ -+#define LOONGARCH_CSR_FWPC 0x380 /* instruction breakpoint config */ -+#define LOONGARCH_CSR_FWPS 0x381 /* instruction breakpoint status */ -+ -+#define LOONGARCH_CSR_IB0ADDR 0x390 /* inst breakpoint 0 address */ -+#define LOONGARCH_CSR_IB0MASK 0x391 /* inst breakpoint 0 mask */ -+#define LOONGARCH_CSR_IB0CTL 0x392 /* inst breakpoint 0 control */ -+#define LOONGARCH_CSR_IB0ASID 0x393 /* inst breakpoint 0 asid */ -+#define LOONGARCH_CSR_IB1ADDR 0x398 /* inst breakpoint 1 address */ -+#define LOONGARCH_CSR_IB1MASK 0x399 /* inst breakpoint 1 mask */ -+#define LOONGARCH_CSR_IB1CTL 0x39a /* inst breakpoint 1 control */ -+#define LOONGARCH_CSR_IB1ASID 0x39b /* inst breakpoint 1 asid */ -+ -+#define LOONGARCH_CSR_IB2ADDR 0x3a0 /* inst breakpoint 2 address */ -+#define LOONGARCH_CSR_IB2MASK 0x3a1 /* inst breakpoint 2 mask */ -+#define LOONGARCH_CSR_IB2CTL 0x3a2 /* inst breakpoint 2 control */ -+#define LOONGARCH_CSR_IB2ASID 0x3a3 /* inst breakpoint 2 asid */ -+ -+#define LOONGARCH_CSR_IB3ADDR 0x3a8 /* inst breakpoint 3 address */ -+#define LOONGARCH_CSR_IB3MASK 0x3a9 /* inst breakpoint 3 mask */ -+#define LOONGARCH_CSR_IB3CTL 0x3aa /* inst breakpoint 3 control */ -+#define LOONGARCH_CSR_IB3ASID 0x3ab /* inst breakpoint 3 asid */ -+ -+#define LOONGARCH_CSR_IB4ADDR 0x3b0 /* inst breakpoint 4 address */ -+#define LOONGARCH_CSR_IB4MASK 0x3b1 /* inst breakpoint 4 mask */ -+#define LOONGARCH_CSR_IB4CTL 0x3b2 /* inst breakpoint 4 control */ -+#define LOONGARCH_CSR_IB4ASID 0x3b3 /* inst breakpoint 4 asid */ -+ -+#define LOONGARCH_CSR_IB5ADDR 0x3b8 /* inst breakpoint 5 address */ -+#define LOONGARCH_CSR_IB5MASK 0x3b9 /* inst breakpoint 5 mask */ -+#define LOONGARCH_CSR_IB5CTL 0x3ba /* inst breakpoint 5 control */ -+#define LOONGARCH_CSR_IB5ASID 0x3bb /* inst breakpoint 5 asid */ -+ -+#define LOONGARCH_CSR_IB6ADDR 0x3c0 /* inst breakpoint 6 address */ -+#define LOONGARCH_CSR_IB6MASK 0x3c1 /* inst breakpoint 6 mask */ -+#define LOONGARCH_CSR_IB6CTL 0x3c2 /* inst breakpoint 6 control */ -+#define LOONGARCH_CSR_IB6ASID 0x3c3 /* inst breakpoint 6 asid */ -+ -+#define LOONGARCH_CSR_IB7ADDR 0x3c8 /* inst breakpoint 7 address */ -+#define LOONGARCH_CSR_IB7MASK 0x3c9 /* inst breakpoint 7 mask */ -+#define LOONGARCH_CSR_IB7CTL 0x3ca /* inst breakpoint 7 control */ -+#define LOONGARCH_CSR_IB7ASID 0x3cb /* inst breakpoint 7 asid */ -+ -+#define LOONGARCH_CSR_DEBUG 0x500 /* debug config */ -+#define CSR_DEBUG_DM 0 -+#define CSR_DEBUG_DMVER 1 -+#define CSR_DEBUG_DINT 8 -+#define CSR_DEBUG_DBP 9 -+#define CSR_DEBUG_DIB 10 -+#define CSR_DEBUG_DDB 11 -+ -+#define LOONGARCH_CSR_DERA 0x501 /* debug era */ -+#define LOONGARCH_CSR_DESAVE 0x502 /* debug save */ -+ -+#define LOONGARCH_CSR_PRID 0xc0 /* 32 LOONGARCH CP0 PRID */ -+ -+#define LOONGARCH_CPUCFG0 0x0 -+#define CPUCFG0_3A5000_PRID 0x0014c010 -+ -+#define LOONGARCH_CPUCFG1 0x1 -+#define CPUCFG1_ISGR32 BIT(0) -+#define CPUCFG1_ISGR64 BIT(1) -+#define CPUCFG1_PAGING BIT(2) -+#define CPUCFG1_IOCSR BIT(3) -+#define CPUCFG1_PABITS (47 << 4) -+#define CPUCFG1_VABITS (47 << 12) -+#define CPUCFG1_UAL BIT(20) -+#define CPUCFG1_RI BIT(21) -+#define CPUCFG1_XI BIT(22) -+#define CPUCFG1_RPLV BIT(23) -+#define CPUCFG1_HUGEPG BIT(24) -+#define CPUCFG1_IOCSRBRD BIT(25) -+#define CPUCFG1_MSGINT BIT(26) -+ -+#define LOONGARCH_CPUCFG2 0x2 -+#define CPUCFG2_FP BIT(0) -+#define CPUCFG2_FPSP BIT(1) -+#define CPUCFG2_FPDP BIT(2) -+#define CPUCFG2_FPVERS (0 << 3) -+#define CPUCFG2_LSX BIT(6) -+#define CPUCFG2_LASX BIT(7) -+#define CPUCFG2_COMPLEX BIT(8) -+#define CPUCFG2_CRYPTO BIT(9) -+#define CPUCFG2_LVZP BIT(10) -+#define CPUCFG2_LVZVER (0 << 11) -+#define CPUCFG2_LLFTP BIT(14) -+#define CPUCFG2_LLFTPREV (1 << 15) -+#define CPUCFG2_X86BT BIT(18) -+#define CPUCFG2_ARMBT BIT(19) -+#define CPUCFG2_MIPSBT BIT(20) -+#define CPUCFG2_LSPW BIT(21) -+#define CPUCFG2_LAM BIT(22) -+ -+#define LOONGARCH_CPUCFG3 0x3 -+#define CPUCFG3_CCDMA BIT(0) -+#define CPUCFG3_SFB BIT(1) -+#define CPUCFG3_UCACC BIT(2) -+#define CPUCFG3_LLEXC BIT(3) -+#define CPUCFG3_SCDLY BIT(4) -+#define CPUCFG3_LLDBAR BIT(5) -+#define CPUCFG3_ITLBT BIT(6) -+#define CPUCFG3_ICACHET BIT(7) -+#define CPUCFG3_SPW_LVL (4 << 8) -+#define CPUCFG3_SPW_HG_HF BIT(11) -+#define CPUCFG3_RVA BIT(12) -+#define CPUCFG3_RVAMAX (7 << 13) -+ -+#define LOONGARCH_CPUCFG4 0x4 -+#define CCFREQ_100M 100000000 /* 100M */ -+ -+#define LOONGARCH_CPUCFG5 0x5 -+#define CPUCFG5_CCMUL 1 -+#define CPUCFG5_CCDIV (1 << 16) -+ -+#define LOONGARCH_CPUCFG6 0x6 -+#define CPUCFG6_PMP BIT(0) -+#define CPUCFG6_PAMVER (1 << 1) -+#define CPUCFG6_PMNUM (3 << 4) -+#define CPUCFG6_PMBITS (63 << 8) -+#define CPUCFG6_UPM BIT(14) -+ -+#define LOONGARCH_CPUCFG16 0x10 -+#define CPUCFG16_L1_IUPRE BIT(0) -+#define CPUCFG16_L1_UNIFY BIT(1) -+#define CPUCFG16_L1_DPRE BIT(2) -+#define CPUCFG16_L2_IUPRE BIT(3) -+#define CPUCFG16_L2_IUUNIFY BIT(4) -+#define CPUCFG16_L2_IUPRIV BIT(5) -+#define CPUCFG16_L2_IUINCL BIT(6) -+#define CPUCFG16_L2_DPRE BIT(7) -+#define CPUCFG16_L2_DPRIV BIT(8) -+#define CPUCFG16_L2_DINCL BIT(9) -+#define CPUCFG16_L3_IUPRE BIT(10) -+#define CPUCFG16_L3_IUUNIFY BIT(11) -+#define CPUCFG16_L3_IUPRIV BIT(12) -+#define CPUCFG16_L3_IUINCL BIT(13) -+#define CPUCFG16_L3_DPRE BIT(14) -+#define CPUCFG16_L3_DPRIV BIT(15) -+#define CPUCFG16_L3_DINCL BIT(16) -+ -+#define LOONGARCH_CPUCFG17 0x11 -+#define CPUCFG17_L1I_WAYS_M (3 << 0) -+#define CPUCFG17_L1I_SETS_M (8 << 16) -+#define CPUCFG17_L1I_SIZE_M (6 << 24) -+ -+#define LOONGARCH_CPUCFG18 0x12 -+#define CPUCFG18_L1D_WAYS_M (3 << 0) -+#define CPUCFG18_L1D_SETS_M (8 << 16) -+#define CPUCFG18_L1D_SIZE_M (6 << 24) -+ -+#define LOONGARCH_CPUCFG19 0x13 -+#define CPUCFG19_L2_WAYS_M (0xf << 0) -+#define CPUCFG19_L2_SETS_M (8 << 16) -+#define CPUCFG19_L2_SIZE_M (6 << 24) -+ -+#define LOONGARCH_CPUCFG20 0x14 -+#define CPUCFG20_L3_WAYS_M (0xf << 0) -+#define CPUCFG20_L3_SETS_M (0xe << 16) -+#define CPUCFG20_L3_SIZE_M (0x6 << 24) -+ -+#define LOONGARCH_PAGE_HUGE 0x40 -+#define LOONGARCH_HUGE_GLOBAL 0x1000 -+#define LOONGARCH_HUGE_GLOBAL_SH 12 -+ -+/* All CSR register -+ * -+ * default value in target/loongarch/cpu.c -+ * reset function in target/loongarch/translate.c:cpu_state_reset() -+ * -+ * This macro will be used only twice. -+ * > In target/loongarch/cpu.h:CPULOONGARCHState -+ * > In target/loongarch/internal.h:loongarch_def_t -+ * -+ * helper_function to rd/wr: -+ * > declare in target/loongarch/helper.h -+ * > realize in target/loongarch/op_helper.c -+ * -+ * during translate: -+ * > gen_csr_rdl() -+ * > gen_csr_wrl() -+ * > gen_csr_rdq() -+ * > gen_csr_wrq() -+ */ -+#define CPU_LOONGARCH_CSR \ -+ uint64_t CSR_CRMD; \ -+ uint64_t CSR_PRMD; \ -+ uint64_t CSR_EUEN; \ -+ uint64_t CSR_MISC; \ -+ uint64_t CSR_ECFG; \ -+ uint64_t CSR_ESTAT; \ -+ uint64_t CSR_ERA; \ -+ uint64_t CSR_BADV; \ -+ uint64_t CSR_BADI; \ -+ uint64_t CSR_EEPN; \ -+ uint64_t CSR_TLBIDX; \ -+ uint64_t CSR_TLBEHI; \ -+ uint64_t CSR_TLBELO0; \ -+ uint64_t CSR_TLBELO1; \ -+ uint64_t CSR_TLBWIRED; \ -+ uint64_t CSR_GTLBC; \ -+ uint64_t CSR_TRGP; \ -+ uint64_t CSR_ASID; \ -+ uint64_t CSR_PGDL; \ -+ uint64_t CSR_PGDH; \ -+ uint64_t CSR_PGD; \ -+ uint64_t CSR_PWCTL0; \ -+ uint64_t CSR_PWCTL1; \ -+ uint64_t CSR_STLBPGSIZE; \ -+ uint64_t CSR_RVACFG; \ -+ uint64_t CSR_CPUID; \ -+ uint64_t CSR_PRCFG1; \ -+ uint64_t CSR_PRCFG2; \ -+ uint64_t CSR_PRCFG3; \ -+ uint64_t CSR_KS0; \ -+ uint64_t CSR_KS1; \ -+ uint64_t CSR_KS2; \ -+ uint64_t CSR_KS3; \ -+ uint64_t CSR_KS4; \ -+ uint64_t CSR_KS5; \ -+ uint64_t CSR_KS6; \ -+ uint64_t CSR_KS7; \ -+ uint64_t CSR_KS8; \ -+ uint64_t CSR_TMID; \ -+ uint64_t CSR_TCFG; \ -+ uint64_t CSR_TVAL; \ -+ uint64_t CSR_CNTC; \ -+ uint64_t CSR_TINTCLR; \ -+ uint64_t CSR_GSTAT; \ -+ uint64_t CSR_GCFG; \ -+ uint64_t CSR_GINTC; \ -+ uint64_t CSR_GCNTC; \ -+ uint64_t CSR_LLBCTL; \ -+ uint64_t CSR_IMPCTL1; \ -+ uint64_t CSR_IMPCTL2; \ -+ uint64_t CSR_GNMI; \ -+ uint64_t CSR_TLBRENT; \ -+ uint64_t CSR_TLBRBADV; \ -+ uint64_t CSR_TLBRERA; \ -+ uint64_t CSR_TLBRSAVE; \ -+ uint64_t CSR_TLBRELO0; \ -+ uint64_t CSR_TLBRELO1; \ -+ uint64_t CSR_TLBREHI; \ -+ uint64_t CSR_TLBRPRMD; \ -+ uint64_t CSR_ERRCTL; \ -+ uint64_t CSR_ERRINFO; \ -+ uint64_t CSR_ERRINFO1; \ -+ uint64_t CSR_ERRENT; \ -+ uint64_t CSR_ERRERA; \ -+ uint64_t CSR_ERRSAVE; \ -+ uint64_t CSR_CTAG; \ -+ uint64_t CSR_DMWIN0; \ -+ uint64_t CSR_DMWIN1; \ -+ uint64_t CSR_DMWIN2; \ -+ uint64_t CSR_DMWIN3; \ -+ uint64_t CSR_PERFCTRL0; \ -+ uint64_t CSR_PERFCNTR0; \ -+ uint64_t CSR_PERFCTRL1; \ -+ uint64_t CSR_PERFCNTR1; \ -+ uint64_t CSR_PERFCTRL2; \ -+ uint64_t CSR_PERFCNTR2; \ -+ uint64_t CSR_PERFCTRL3; \ -+ uint64_t CSR_PERFCNTR3; \ -+ uint64_t CSR_MWPC; \ -+ uint64_t CSR_MWPS; \ -+ uint64_t CSR_DB0ADDR; \ -+ uint64_t CSR_DB0MASK; \ -+ uint64_t CSR_DB0CTL; \ -+ uint64_t CSR_DB0ASID; \ -+ uint64_t CSR_DB1ADDR; \ -+ uint64_t CSR_DB1MASK; \ -+ uint64_t CSR_DB1CTL; \ -+ uint64_t CSR_DB1ASID; \ -+ uint64_t CSR_DB2ADDR; \ -+ uint64_t CSR_DB2MASK; \ -+ uint64_t CSR_DB2CTL; \ -+ uint64_t CSR_DB2ASID; \ -+ uint64_t CSR_DB3ADDR; \ -+ uint64_t CSR_DB3MASK; \ -+ uint64_t CSR_DB3CTL; \ -+ uint64_t CSR_DB3ASID; \ -+ uint64_t CSR_FWPC; \ -+ uint64_t CSR_FWPS; \ -+ uint64_t CSR_IB0ADDR; \ -+ uint64_t CSR_IB0MASK; \ -+ uint64_t CSR_IB0CTL; \ -+ uint64_t CSR_IB0ASID; \ -+ uint64_t CSR_IB1ADDR; \ -+ uint64_t CSR_IB1MASK; \ -+ uint64_t CSR_IB1CTL; \ -+ uint64_t CSR_IB1ASID; \ -+ uint64_t CSR_IB2ADDR; \ -+ uint64_t CSR_IB2MASK; \ -+ uint64_t CSR_IB2CTL; \ -+ uint64_t CSR_IB2ASID; \ -+ uint64_t CSR_IB3ADDR; \ -+ uint64_t CSR_IB3MASK; \ -+ uint64_t CSR_IB3CTL; \ -+ uint64_t CSR_IB3ASID; \ -+ uint64_t CSR_IB4ADDR; \ -+ uint64_t CSR_IB4MASK; \ -+ uint64_t CSR_IB4CTL; \ -+ uint64_t CSR_IB4ASID; \ -+ uint64_t CSR_IB5ADDR; \ -+ uint64_t CSR_IB5MASK; \ -+ uint64_t CSR_IB5CTL; \ -+ uint64_t CSR_IB5ASID; \ -+ uint64_t CSR_IB6ADDR; \ -+ uint64_t CSR_IB6MASK; \ -+ uint64_t CSR_IB6CTL; \ -+ uint64_t CSR_IB6ASID; \ -+ uint64_t CSR_IB7ADDR; \ -+ uint64_t CSR_IB7MASK; \ -+ uint64_t CSR_IB7CTL; \ -+ uint64_t CSR_IB7ASID; \ -+ uint64_t CSR_DEBUG; \ -+ uint64_t CSR_DERA; \ -+ uint64_t CSR_DESAVE; \ -+ -+#define LOONGARCH_CSR_32(_R, _S) \ -+ (KVM_REG_LOONGARCH_CSR | KVM_REG_SIZE_U32 | (8 * (_R) + (_S))) -+ -+#define LOONGARCH_CSR_64(_R, _S) \ -+ (KVM_REG_LOONGARCH_CSR | KVM_REG_SIZE_U64 | (8 * (_R) + (_S))) -+ -+#define KVM_IOC_CSRID(id) LOONGARCH_CSR_64(id, 0) -+ -+#endif -diff --git a/target/loongarch64/cpu-param.h b/target/loongarch64/cpu-param.h -new file mode 100644 -index 000000000..24ca458af ---- /dev/null -+++ b/target/loongarch64/cpu-param.h -@@ -0,0 +1,30 @@ -+#ifndef CPU_PARAM_H -+#define CPU_PARAM_H -+ -+/* If we want to use host float regs... */ -+/* #define USE_HOST_FLOAT_REGS */ -+ -+/* Real pages are variable size... */ -+#define TARGET_PAGE_BITS 14 -+ -+#define LOONGARCH_TLB_MAX 2112 -+ -+#define TARGET_LONG_BITS 64 -+#define TARGET_PHYS_ADDR_SPACE_BITS 48 -+#define TARGET_VIRT_ADDR_SPACE_BITS 48 -+ -+/* -+ * bit definitions for insn_flags (ISAs/ASEs flags) -+ * ------------------------------------------------ -+ */ -+#define ISA_LARCH32 0x00000001ULL -+#define ISA_LARCH64 0x00000002ULL -+#define INSN_LOONGARCH 0x00010000ULL -+ -+#define CPU_LARCH32 (ISA_LARCH32) -+#define CPU_LARCH64 (ISA_LARCH32 | ISA_LARCH64) -+ -+#define NB_MMU_MODES 4 -+ -+#endif /* QEMU_LOONGARCH_DEFS_H */ -+ -diff --git a/target/loongarch64/cpu-qom.h b/target/loongarch64/cpu-qom.h -new file mode 100644 -index 000000000..ee9c1de57 ---- /dev/null -+++ b/target/loongarch64/cpu-qom.h -@@ -0,0 +1,54 @@ -+/* -+ * QEMU LOONGARCH CPU -+ * -+ * Copyright (c) 2012 SUSE LINUX Products GmbH -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * 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 -+ * -+ */ -+#ifndef QEMU_LOONGARCH_CPU_QOM_H -+#define QEMU_LOONGARCH_CPU_QOM_H -+ -+#include "hw/core/cpu.h" -+ -+#define TYPE_LOONGARCH_CPU "loongarch-cpu" -+ -+#define LOONGARCH_CPU_CLASS(klass) \ -+ OBJECT_CLASS_CHECK(LOONGARCHCPUClass, (klass), TYPE_LOONGARCH_CPU) -+#define LOONGARCH_CPU(obj) \ -+ OBJECT_CHECK(LOONGARCHCPU, (obj), TYPE_LOONGARCH_CPU) -+#define LOONGARCH_CPU_GET_CLASS(obj) \ -+ OBJECT_GET_CLASS(LOONGARCHCPUClass, (obj), TYPE_LOONGARCH_CPU) -+ -+/** -+ * LOONGARCHCPUClass: -+ * @parent_realize: The parent class' realize handler. -+ * @parent_reset: The parent class' reset handler. -+ * -+ * A LOONGARCH CPU model. -+ */ -+typedef struct LOONGARCHCPUClass { -+ /*< private >*/ -+ CPUClass parent_class; -+ /*< public >*/ -+ -+ DeviceRealize parent_realize; -+ DeviceUnrealize parent_unrealize; -+ DeviceReset parent_reset; -+ const struct loongarch_def_t *cpu_def; -+} LOONGARCHCPUClass; -+ -+typedef struct LOONGARCHCPU LOONGARCHCPU; -+ -+#endif -diff --git a/target/loongarch64/cpu.c b/target/loongarch64/cpu.c -new file mode 100644 -index 000000000..a4535d34a ---- /dev/null -+++ b/target/loongarch64/cpu.c -@@ -0,0 +1,576 @@ -+/* -+ * QEMU LOONGARCH CPU -+ * -+ * Copyright (c) 2012 SUSE LINUX Products GmbH -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * 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 "qapi/error.h" -+#include "qapi/visitor.h" -+#include "cpu.h" -+#include "internal.h" -+#include "kvm_larch.h" -+#include "qemu-common.h" -+#include "hw/qdev-properties.h" -+#include "sysemu/kvm.h" -+#include "exec/exec-all.h" -+#include "sysemu/arch_init.h" -+#include "cpu-csr.h" -+#include "qemu/qemu-print.h" -+#include "qapi/qapi-commands-machine-target.h" -+#ifdef CONFIG_TCG -+#include "hw/core/tcg-cpu-ops.h" -+#endif /* CONFIG_TCG */ -+ -+#define LOONGARCH_CONFIG1 \ -+((0x8 << CSR_CONF1_KSNUM_SHIFT) | (0x2f << CSR_CONF1_TMRBITS_SHIFT) | \ -+ (0x7 << CSR_CONF1_VSMAX_SHIFT)) -+ -+#define LOONGARCH_CONFIG3 \ -+((0x2 << CSR_CONF3_TLBORG_SHIFT) | (0x3f << CSR_CONF3_MTLBSIZE_SHIFT) | \ -+ (0x7 << CSR_CONF3_STLBWAYS_SHIFT) | (0x8 << CSR_CONF3_STLBIDX_SHIFT)) -+ -+/*****************************************************************************/ -+/* LOONGARCH CPU definitions */ -+const loongarch_def_t loongarch_defs[] = { -+ { -+ .name = "Loongson-3A5000", -+ -+ /* for LoongISA CSR */ -+ .CSR_PRCFG1 = LOONGARCH_CONFIG1, -+ .CSR_PRCFG2 = 0x3ffff000, -+ .CSR_PRCFG3 = LOONGARCH_CONFIG3, -+ .CSR_CRMD = (0 << CSR_CRMD_PLV_SHIFT) | (0 << CSR_CRMD_IE_SHIFT) | -+ (1 << CSR_CRMD_DA_SHIFT) | (0 << CSR_CRMD_PG_SHIFT) | -+ (1 << CSR_CRMD_DACF_SHIFT) | (1 << CSR_CRMD_DACM_SHIFT) , -+ .CSR_ECFG = 0x7 << 16, -+ .CSR_STLBPGSIZE = 0xe, -+ .CSR_RVACFG = 0x0, -+ .CSR_ASID = 0xa0000, -+ .FCSR0 = 0x0, -+ .FCSR0_rw_bitmask = 0x1f1f03df, -+ .PABITS = 48, -+ .insn_flags = CPU_LARCH64 | INSN_LOONGARCH, -+ .mmu_type = MMU_TYPE_LS3A5K, -+ }, -+ { -+ .name = "host", -+ -+ /* for LoongISA CSR */ -+ .CSR_PRCFG1 = LOONGARCH_CONFIG1, -+ .CSR_PRCFG2 = 0x3ffff000, -+ .CSR_PRCFG3 = LOONGARCH_CONFIG3, -+ .CSR_CRMD = (0 << CSR_CRMD_PLV_SHIFT) | (0 << CSR_CRMD_IE_SHIFT) | -+ (1 << CSR_CRMD_DA_SHIFT) | (0 << CSR_CRMD_PG_SHIFT) | -+ (1 << CSR_CRMD_DACF_SHIFT) | (1 << CSR_CRMD_DACM_SHIFT) , -+ .CSR_ECFG = 0x7 << 16, -+ .CSR_STLBPGSIZE = 0xe, -+ .CSR_RVACFG = 0x0, -+ .FCSR0 = 0x0, -+ .FCSR0_rw_bitmask = 0x1f1f03df, -+ .PABITS = 48, -+ .insn_flags = CPU_LARCH64 | INSN_LOONGARCH, -+ .mmu_type = MMU_TYPE_LS3A5K, -+ }, -+}; -+const int loongarch_defs_number = ARRAY_SIZE(loongarch_defs); -+ -+void loongarch_cpu_list(void) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(loongarch_defs); i++) { -+ qemu_printf("LOONGARCH '%s'\n", -+ loongarch_defs[i].name); -+ } -+} -+ -+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) -+{ -+ CpuDefinitionInfoList *cpu_list = NULL; -+ const loongarch_def_t *def; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(loongarch_defs); i++) { -+ CpuDefinitionInfoList *entry; -+ CpuDefinitionInfo *info; -+ -+ def = &loongarch_defs[i]; -+ info = g_malloc0(sizeof(*info)); -+ info->name = g_strdup(def->name); -+ -+ entry = g_malloc0(sizeof(*entry)); -+ entry->value = info; -+ entry->next = cpu_list; -+ cpu_list = entry; -+ } -+ -+ return cpu_list; -+} -+ -+static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ env->active_tc.PC = value & ~(target_ulong)1; -+} -+ -+static bool loongarch_cpu_has_work(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ bool has_work = false; -+ -+ /* It is implementation dependent if non-enabled -+ interrupts wake-up the CPU, however most of the implementations only -+ check for interrupts that can be taken. */ -+ if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && -+ cpu_loongarch_hw_interrupts_pending(env)) { -+ has_work = true; -+ } -+ -+ return has_work; -+} -+ -+const char * const regnames[] = { -+ "r0", "ra", "tp", "sp", "a0", "a1", "a2", "a3", -+ "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", -+ "t4", "t5", "t6", "t7", "t8", "x0", "fp", "s0", -+ "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", -+}; -+ -+const char * const fregnames[] = { -+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", -+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", -+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", -+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", -+}; -+ -+static void fpu_dump_state(CPULOONGARCHState *env, FILE *f, -+ fprintf_function fpu_fprintf, int flags) -+{ -+ int i; -+ int is_fpu64 = 1; -+ -+#define printfpr(fp) \ -+ do { \ -+ if (is_fpu64) \ -+ fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ -+ " fd:%13g fs:%13g psu: %13g\n", \ -+ (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ -+ (double)(fp)->fd, \ -+ (double)(fp)->fs[FP_ENDIAN_IDX], \ -+ (double)(fp)->fs[!FP_ENDIAN_IDX]); \ -+ else { \ -+ fpr_t tmp; \ -+ tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ -+ tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ -+ fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ -+ " fd:%13g fs:%13g psu:%13g\n", \ -+ tmp.w[FP_ENDIAN_IDX], tmp.d, \ -+ (double)tmp.fd, \ -+ (double)tmp.fs[FP_ENDIAN_IDX], \ -+ (double)tmp.fs[!FP_ENDIAN_IDX]); \ -+ } \ -+ } while (0) -+ -+ -+ fpu_fprintf(f, "FCSR0 0x%08x SR.FR %d fp_status 0x%02x\n", -+ env->active_fpu.fcsr0, is_fpu64, -+ get_float_exception_flags(&env->active_fpu.fp_status)); -+ for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { -+ fpu_fprintf(f, "%3s: ", fregnames[i]); -+ printfpr(&env->active_fpu.fpr[i]); -+ } -+ -+#undef printfpr -+} -+ -+void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int i; -+ -+ qemu_fprintf(f, "pc:\t %lx\n", env->active_tc.PC); -+ for (i = 0; i < 32; i++) { -+ if ((i & 3) == 0) { -+ qemu_fprintf(f, "GPR%02d:", i); -+ } -+ qemu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], -+ env->active_tc.gpr[i]); -+ if ((i & 3) == 3) { -+ qemu_fprintf(f, "\n"); -+ } -+ } -+ qemu_fprintf(f, "EUEN 0x%lx\n", env->CSR_EUEN); -+ qemu_fprintf(f, "ESTAT 0x%lx\n", env->CSR_ESTAT); -+ qemu_fprintf(f, "ERA 0x%lx\n", env->CSR_ERA); -+ qemu_fprintf(f, "CRMD 0x%lx\n", env->CSR_CRMD); -+ qemu_fprintf(f, "PRMD 0x%lx\n", env->CSR_PRMD); -+ qemu_fprintf(f, "BadVAddr 0x%lx\n", env->CSR_BADV); -+ qemu_fprintf(f, "TLB refill ERA 0x%lx\n", env->CSR_TLBRERA); -+ qemu_fprintf(f, "TLB refill BadV 0x%lx\n", env->CSR_TLBRBADV); -+ qemu_fprintf(f, "EEPN 0x%lx\n", env->CSR_EEPN); -+ qemu_fprintf(f, "BadInstr 0x%lx\n", env->CSR_BADI); -+ qemu_fprintf(f, "PRCFG1 0x%lx\nPRCFG2 0x%lx\nPRCFG3 0x%lx\n", -+ env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); -+ if ((flags & CPU_DUMP_FPU) && (env->hflags & LARCH_HFLAG_FPU)) { -+ fpu_dump_state(env, f, qemu_fprintf, flags); -+ } -+} -+ -+void cpu_state_reset(CPULOONGARCHState *env) -+{ -+ LOONGARCHCPU *cpu = loongarch_env_get_cpu(env); -+ CPUState *cs = CPU(cpu); -+ -+ /* Reset registers to their default values */ -+ env->CSR_PRCFG1 = env->cpu_model->CSR_PRCFG1; -+ env->CSR_PRCFG2 = env->cpu_model->CSR_PRCFG2; -+ env->CSR_PRCFG3 = env->cpu_model->CSR_PRCFG3; -+ env->CSR_CRMD = env->cpu_model->CSR_CRMD; -+ env->CSR_ECFG = env->cpu_model->CSR_ECFG; -+ env->CSR_STLBPGSIZE = env->cpu_model->CSR_STLBPGSIZE; -+ env->CSR_RVACFG = env->cpu_model->CSR_RVACFG; -+ env->CSR_ASID = env->cpu_model->CSR_ASID; -+ -+ env->current_tc = 0; -+ env->active_fpu.fcsr0_rw_bitmask = env->cpu_model->FCSR0_rw_bitmask; -+ env->active_fpu.fcsr0 = env->cpu_model->FCSR0; -+ env->insn_flags = env->cpu_model->insn_flags; -+ -+#if !defined(CONFIG_USER_ONLY) -+ env->CSR_ERA = env->active_tc.PC; -+ env->active_tc.PC = env->exception_base; -+#ifdef CONFIG_TCG -+ env->tlb->tlb_in_use = env->tlb->nb_tlb; -+#endif -+ env->CSR_TLBWIRED = 0; -+ env->CSR_TMID = cs->cpu_index; -+ env->CSR_CPUID = (cs->cpu_index & 0x1ff); -+ env->CSR_EEPN |= (uint64_t)0x80000000; -+ env->CSR_TLBRENT |= (uint64_t)0x80000000; -+#endif -+ -+ /* Count register increments in debug mode, EJTAG version 1 */ -+ env->CSR_DEBUG = (1 << CSR_DEBUG_DINT) | (0x1 << CSR_DEBUG_DMVER); -+ -+ compute_hflags(env); -+ restore_fp_status(env); -+ cs->exception_index = EXCP_NONE; -+} -+ -+/* CPUClass::reset() */ -+static void loongarch_cpu_reset(DeviceState *dev) -+{ -+ CPUState *s = CPU(dev); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(s); -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(cpu); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ mcc->parent_reset(dev); -+ -+ memset(env, 0, offsetof(CPULOONGARCHState, end_reset_fields)); -+ -+ cpu_state_reset(env); -+ -+#ifndef CONFIG_USER_ONLY -+ if (kvm_enabled()) { -+ kvm_loongarch_reset_vcpu(cpu); -+ } -+#endif -+} -+ -+static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) -+{ -+ info->print_insn = print_insn_loongarch; -+} -+ -+static void fpu_init(CPULOONGARCHState *env, const loongarch_def_t *def) -+{ -+ memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu)); -+} -+ -+void cpu_loongarch_realize_env(CPULOONGARCHState *env) -+{ -+ env->exception_base = 0x1C000000; -+ -+#ifdef CONFIG_TCG -+#ifndef CONFIG_USER_ONLY -+ mmu_init(env, env->cpu_model); -+#endif -+#endif -+ fpu_init(env, env->cpu_model); -+} -+ -+static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) -+{ -+ CPUState *cs = CPU(dev); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(dev); -+ Error *local_err = NULL; -+ -+ cpu_exec_realizefn(cs, &local_err); -+ if (local_err != NULL) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ cpu_loongarch_realize_env(&cpu->env); -+ -+ loongarch_cpu_register_gdb_regs_for_features(cs); -+ -+ cpu_reset(cs); -+ qemu_init_vcpu(cs); -+ -+ mcc->parent_realize(dev, errp); -+ cpu->hotplugged = 1; -+} -+ -+static void loongarch_cpu_unrealizefn(DeviceState *dev) -+{ -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(dev); -+ -+#ifndef CONFIG_USER_ONLY -+ cpu_remove_sync(CPU(dev)); -+#endif -+ -+ mcc->parent_unrealize(dev); -+} -+static void loongarch_cpu_initfn(Object *obj) -+{ -+ CPUState *cs = CPU(obj); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(obj); -+ CPULOONGARCHState *env = &cpu->env; -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(obj); -+ cpu_set_cpustate_pointers(cpu); -+ cs->env_ptr = env; -+ env->cpu_model = mcc->cpu_def; -+ cs->halted = 1; -+ cpu->dtb_compatible = "loongarch,Loongson-3A5000"; -+} -+ -+static char *loongarch_cpu_type_name(const char *cpu_model) -+{ -+ return g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model); -+} -+ -+static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) -+{ -+ ObjectClass *oc; -+ char *typename; -+ -+ typename = loongarch_cpu_type_name(cpu_model); -+ oc = object_class_by_name(typename); -+ g_free(typename); -+ return oc; -+} -+ -+static int64_t loongarch_cpu_get_arch_id(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ -+ return cpu->id; -+} -+ -+static Property loongarch_cpu_properties[] = { -+ DEFINE_PROP_INT32("core-id", LOONGARCHCPU, core_id, -1), -+ DEFINE_PROP_INT32("id", LOONGARCHCPU, id, UNASSIGNED_CPU_ID), -+ DEFINE_PROP_INT32("node-id", LOONGARCHCPU, node_id, CPU_UNSET_NUMA_NODE_ID), -+ -+ DEFINE_PROP_END_OF_LIST() -+}; -+ -+#ifdef CONFIG_TCG -+static void loongarch_cpu_synchronize_from_tb(CPUState *cs,const TranslationBlock *tb) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ env->active_tc.PC = tb->pc; -+ env->hflags &= ~LARCH_HFLAG_BMASK; -+ env->hflags |= tb->flags & LARCH_HFLAG_BMASK; -+} -+ -+static const struct TCGCPUOps loongarch_tcg_ops = { -+ .initialize = loongarch_tcg_init, -+ .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, -+ -+ .tlb_fill = loongarch_cpu_tlb_fill, -+ .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, -+ .do_interrupt = loongarch_cpu_do_interrupt, -+ -+#ifndef CONFIG_USER_ONLY -+ .do_unaligned_access = loongarch_cpu_do_unaligned_access, -+#endif /* !CONFIG_USER_ONLY */ -+}; -+#endif /* CONFIG_TCG */ -+ -+ -+#if !defined(CONFIG_USER_ONLY) -+static int get_physical_address(CPULOONGARCHState *env, hwaddr *physical, -+ int *prot, target_ulong real_address, -+ int rw, int access_type, int mmu_idx) -+{ -+ int user_mode = mmu_idx == LARCH_HFLAG_UM; -+ int kernel_mode = !user_mode; -+ unsigned plv, base_c, base_v, tmp; -+ -+ /* effective address (modified for KVM T&E kernel segments) */ -+ target_ulong address = real_address; -+ -+ /* Check PG */ -+ if (!(env->CSR_CRMD & CSR_CRMD_PG)) { -+ /* DA mode */ -+ *physical = address & 0xffffffffffffUL; -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ -+ plv = kernel_mode | (user_mode << 3); -+ base_v = address >> CSR_DMW_BASE_SH; -+ /* Check direct map window 0 */ -+ base_c = env->CSR_DMWIN0 >> CSR_DMW_BASE_SH; -+ if ((plv & env->CSR_DMWIN0) && (base_c == base_v)) { -+ *physical = dmwin_va2pa(address); -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ /* Check direct map window 1 */ -+ base_c = env->CSR_DMWIN1 >> CSR_DMW_BASE_SH; -+ if ((plv & env->CSR_DMWIN1) && (base_c == base_v)) { -+ *physical = dmwin_va2pa(address); -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ /* Check valid extension */ -+ tmp = address >> 47; -+ if (!(tmp == 0 || tmp == 0x1ffff)) { -+ return TLBRET_BADADDR; -+ } -+ /* mapped address */ -+ return env->tlb->map_address(env, physical, prot, real_address, rw, -+ access_type); -+} -+ -+hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ hwaddr phys_addr; -+ int prot; -+ -+ if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT, -+ cpu_mmu_index(env, false)) != 0) { -+ return -1; -+ } -+ return phys_addr; -+} -+#endif -+ -+ -+#ifndef CONFIG_USER_ONLY -+#include "hw/core/sysemu-cpu-ops.h" -+ -+static const struct SysemuCPUOps loongarch_sysemu_ops = { -+ .write_elf64_note = loongarch_cpu_write_elf64_note, -+ .get_phys_page_debug = loongarch_cpu_get_phys_page_debug, -+ .legacy_vmsd = &vmstate_loongarch_cpu, -+}; -+#endif -+ -+ -+static void loongarch_cpu_class_init(ObjectClass *c, void *data) -+{ -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_CLASS(c); -+ CPUClass *cc = CPU_CLASS(c); -+ DeviceClass *dc = DEVICE_CLASS(c); -+ -+ device_class_set_props(dc, loongarch_cpu_properties); -+ device_class_set_parent_realize(dc, loongarch_cpu_realizefn, -+ &mcc->parent_realize); -+ -+ device_class_set_parent_unrealize(dc, loongarch_cpu_unrealizefn, -+ &mcc->parent_unrealize); -+ -+ device_class_set_parent_reset(dc, loongarch_cpu_reset, &mcc->parent_reset); -+ cc->get_arch_id = loongarch_cpu_get_arch_id; -+ -+ cc->class_by_name = loongarch_cpu_class_by_name; -+ cc->has_work = loongarch_cpu_has_work; -+ cc->dump_state = loongarch_cpu_dump_state; -+ cc->set_pc = loongarch_cpu_set_pc; -+ cc->gdb_read_register = loongarch_cpu_gdb_read_register; -+ cc->gdb_write_register = loongarch_cpu_gdb_write_register; -+ cc->disas_set_info = loongarch_cpu_disas_set_info; -+#ifndef CONFIG_USER_ONLY -+ cc->sysemu_ops = &loongarch_sysemu_ops; -+#endif /* !CONFIG_USER_ONLY */ -+ -+ cc->gdb_num_core_regs = 33; -+ cc->gdb_core_xml_file = "loongarch-base64.xml"; -+ cc->gdb_stop_before_watchpoint = true; -+ -+ dc->user_creatable = true; -+#ifdef CONFIG_TCG -+ cc->tcg_ops = &loongarch_tcg_ops; -+#endif /* CONFIG_TCG */ -+} -+ -+static const TypeInfo loongarch_cpu_type_info = { -+ .name = TYPE_LOONGARCH_CPU, -+ .parent = TYPE_CPU, -+ .instance_size = sizeof(LOONGARCHCPU), -+ .instance_init = loongarch_cpu_initfn, -+ .abstract = true, -+ .class_size = sizeof(LOONGARCHCPUClass), -+ .class_init = loongarch_cpu_class_init, -+}; -+ -+static void loongarch_cpu_cpudef_class_init(ObjectClass *oc, void *data) -+{ -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_CLASS(oc); -+ mcc->cpu_def = data; -+} -+ -+static void loongarch_register_cpudef_type(const struct loongarch_def_t *def) -+{ -+ char *typename = loongarch_cpu_type_name(def->name); -+ TypeInfo ti = { -+ .name = typename, -+ .parent = TYPE_LOONGARCH_CPU, -+ .class_init = loongarch_cpu_cpudef_class_init, -+ .class_data = (void *)def, -+ }; -+ -+ type_register(&ti); -+ g_free(typename); -+} -+ -+static void loongarch_cpu_register_types(void) -+{ -+ int i; -+ -+ type_register_static(&loongarch_cpu_type_info); -+ for (i = 0; i < loongarch_defs_number; i++) { -+ loongarch_register_cpudef_type(&loongarch_defs[i]); -+ } -+} -+ -+type_init(loongarch_cpu_register_types) -diff --git a/target/loongarch64/cpu.h b/target/loongarch64/cpu.h -new file mode 100644 -index 000000000..10facb3b7 ---- /dev/null -+++ b/target/loongarch64/cpu.h -@@ -0,0 +1,326 @@ -+#ifndef LOONGARCH_CPU_H -+#define LOONGARCH_CPU_H -+ -+ -+#define CPUArchState struct CPULOONGARCHState -+ -+#include "qemu-common.h" -+#include "cpu-qom.h" -+#include "larch-defs.h" -+#include "exec/cpu-defs.h" -+#include "fpu/softfloat.h" -+#include "sysemu/sysemu.h" -+#include "cpu-csr.h" -+ -+#define TCG_GUEST_DEFAULT_MO (0) -+ -+struct CPULOONGARCHState; -+typedef LOONGARCHCPU ArchCPU; -+typedef struct CPULOONGARCHTLBContext CPULOONGARCHTLBContext; -+ -+#define LASX_REG_WIDTH (256) -+typedef union lasx_reg_t lasx_reg_t; -+union lasx_reg_t { -+ int64_t val64[LASX_REG_WIDTH / 64]; -+}; -+ -+typedef union fpr_t fpr_t; -+union fpr_t { -+ float64 fd; /* ieee double precision */ -+ float32 fs[2];/* ieee single precision */ -+ uint64_t d; /* binary double fixed-point */ -+ uint32_t w[2]; /* binary single fixed-point */ -+/* FPU/LASX register mapping is not tested on big-endian hosts. */ -+ lasx_reg_t lasx; /* vector data */ -+}; -+/* define FP_ENDIAN_IDX to access the same location -+ * in the fpr_t union regardless of the host endianness -+ */ -+#if defined(HOST_WORDS_BIGENDIAN) -+# define FP_ENDIAN_IDX 1 -+#else -+# define FP_ENDIAN_IDX 0 -+#endif -+ -+typedef struct CPULOONGARCHFPUContext { -+ /* Floating point registers */ -+ fpr_t fpr[32]; -+ float_status fp_status; -+ -+ bool cf[8]; -+ /* fcsr0 -+ * 31:29 |28:24 |23:21 |20:16 |15:10 |9:8 |7 |6 |5 |4:0 -+ * Cause Flags RM DAE TM Enables -+ */ -+ uint32_t fcsr0; -+ uint32_t fcsr0_rw_bitmask; -+ uint32_t vcsr16; -+} CPULOONGARCHFPUContext; -+ -+/* fp control and status register definition */ -+#define FCSR0_M1 0xdf /* DAE, TM and Enables */ -+#define FCSR0_M2 0x1f1f0000 /* Cause and Flags */ -+#define FCSR0_M3 0x300 /* Round Mode */ -+#define FCSR0_RM 8 /* Round Mode bit num on fcsr0 */ -+#define GET_FP_CAUSE(reg) (((reg) >> 24) & 0x1f) -+#define GET_FP_ENABLE(reg) (((reg) >> 0) & 0x1f) -+#define GET_FP_FLAGS(reg) (((reg) >> 16) & 0x1f) -+#define SET_FP_CAUSE(reg, v) do { (reg) = ((reg) & ~(0x1f << 24)) | \ -+ ((v & 0x1f) << 24); \ -+ } while (0) -+#define SET_FP_ENABLE(reg, v) do { (reg) = ((reg) & ~(0x1f << 0)) | \ -+ ((v & 0x1f) << 0); \ -+ } while (0) -+#define SET_FP_FLAGS(reg, v) do { (reg) = ((reg) & ~(0x1f << 16)) | \ -+ ((v & 0x1f) << 16); \ -+ } while (0) -+#define UPDATE_FP_FLAGS(reg, v) do { (reg) |= ((v & 0x1f) << 16); } while (0) -+#define FP_INEXACT 1 -+#define FP_UNDERFLOW 2 -+#define FP_OVERFLOW 4 -+#define FP_DIV0 8 -+#define FP_INVALID 16 -+ -+#define TARGET_INSN_START_EXTRA_WORDS 2 -+ -+typedef struct loongarch_def_t loongarch_def_t; -+ -+#define LOONGARCH_FPU_MAX 1 -+#define LOONGARCH_KSCRATCH_NUM 8 -+ -+typedef struct TCState TCState; -+struct TCState { -+ target_ulong gpr[32]; -+ target_ulong PC; -+}; -+ -+#define N_IRQS 14 -+#define IRQ_TIMER 11 -+#define IRQ_IPI 12 -+#define IRQ_UART 2 -+ -+typedef struct CPULOONGARCHState CPULOONGARCHState; -+struct CPULOONGARCHState { -+ TCState active_tc; -+ CPULOONGARCHFPUContext active_fpu; -+ -+ uint32_t current_tc; -+ uint64_t scr[4]; -+ uint32_t PABITS; -+ -+ /* LoongISA CSR register */ -+ CPU_LOONGARCH_CSR -+ uint64_t lladdr; -+ target_ulong llval; -+ uint64_t llval_wp; -+ uint32_t llnewval_wp; -+ -+ CPULOONGARCHFPUContext fpus[LOONGARCH_FPU_MAX]; -+ /* QEMU */ -+ int error_code; -+#define EXCP_TLB_NOMATCH 0x1 -+#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ -+ uint32_t hflags; /* CPU State */ -+ /* TMASK defines different execution modes */ -+#define LARCH_HFLAG_TMASK 0x5F5807FF -+ /* -+ * The KSU flags must be the lowest bits in hflags. The flag order -+ * must be the same as defined for CP0 Status. This allows to use -+ * the bits as the value of mmu_idx. -+ */ -+#define LARCH_HFLAG_KSU 0x00003 /* kernel/user mode mask */ -+#define LARCH_HFLAG_UM 0x00003 /* user mode flag */ -+#define LARCH_HFLAG_KM 0x00000 /* kernel mode flag */ -+#define LARCH_HFLAG_64 0x00008 /* 64-bit instructions enabled */ -+#define LARCH_HFLAG_FPU 0x00020 /* FPU enabled */ -+#define LARCH_HFLAG_AWRAP 0x00200 /* 32-bit compatibility address wrapping */ -+ /* If translation is interrupted between the branch instruction and -+ * the delay slot, record what type of branch it is so that we can -+ * resume translation properly. It might be possible to reduce -+ * this from three bits to two. */ -+#define LARCH_HFLAG_BMASK 0x03800 -+#define LARCH_HFLAG_B 0x00800 /* Unconditional branch */ -+#define LARCH_HFLAG_BC 0x01000 /* Conditional branch */ -+#define LARCH_HFLAG_BR 0x02000 /* branch to register (can't link TB) */ -+#define LARCH_HFLAG_LSX 0x1000000 -+#define LARCH_HFLAG_LASX 0x2000000 -+#define LARCH_HFLAG_LBT 0x40000000 -+ target_ulong btarget; /* Jump / branch target */ -+ target_ulong bcond; /* Branch condition (if needed) */ -+ -+ uint64_t insn_flags; /* Supported instruction set */ -+ int cpu_cfg[64]; -+ -+ /* Fields up to this point are cleared by a CPU reset */ -+ struct {} end_reset_fields; -+ -+ /* Fields from here on are preserved across CPU reset. */ -+#if !defined(CONFIG_USER_ONLY) -+ CPULOONGARCHTLBContext *tlb; -+#endif -+ -+ const loongarch_def_t *cpu_model; -+ void *irq[N_IRQS]; -+ QEMUTimer *timer; /* Internal timer */ -+ MemoryRegion *itc_tag; /* ITC Configuration Tags */ -+ target_ulong exception_base; /* ExceptionBase input to the core */ -+ struct { -+ uint64_t guest_addr; -+ } st; -+}; -+ -+ -+/* CPU can't have 0xFFFFFFFF APIC ID, use that value to distinguish -+ * that ID hasn't been set yet -+ */ -+#define UNASSIGNED_CPU_ID 0xFFFFFFFF -+ -+/** -+ * LOONGARCHCPU: -+ * @env: #CPULOONGARCHState -+ * -+ * A LOONGARCH CPU. -+ */ -+struct LOONGARCHCPU { -+ /*< private >*/ -+ CPUState parent_obj; -+ /*< public >*/ -+ CPUNegativeOffsetState neg; -+ CPULOONGARCHState env; -+ int32_t id; -+ int hotplugged; -+ uint8_t online_vcpus; -+ uint8_t is_migrate; -+ uint64_t counter_value; -+ uint32_t cpu_freq; -+ uint32_t count_ctl; -+ uint64_t pending_exceptions; -+ uint64_t pending_exceptions_clr; -+ uint64_t core_ext_ioisr[4]; -+ VMChangeStateEntry *cpuStateEntry; -+ int32_t node_id; /* NUMA node this CPU belongs to */ -+ int32_t core_id; -+ struct kvm_msrs *kvm_msr_buf; -+ /* 'compatible' string for this CPU for Linux device trees */ -+ const char *dtb_compatible; -+}; -+ -+static inline LOONGARCHCPU *loongarch_env_get_cpu(CPULOONGARCHState *env) -+{ -+ return container_of(env, LOONGARCHCPU, env); -+} -+ -+#define ENV_GET_CPU(e) CPU(loongarch_env_get_cpu(e)) -+ -+#define ENV_OFFSET offsetof(LOONGARCHCPU, env) -+ -+void loongarch_cpu_list(void); -+ -+#define cpu_signal_handler cpu_loongarch_signal_handler -+#define cpu_list loongarch_cpu_list -+ -+/* MMU modes definitions. We carefully match the indices with our -+ hflags layout. */ -+#define MMU_MODE0_SUFFIX _kernel -+#define MMU_MODE1_SUFFIX _super -+#define MMU_MODE2_SUFFIX _user -+#define MMU_MODE3_SUFFIX _error -+#define MMU_USER_IDX 3 -+ -+static inline int hflags_mmu_index(uint32_t hflags) -+{ -+ return hflags & LARCH_HFLAG_KSU; -+} -+ -+static inline int cpu_mmu_index(CPULOONGARCHState *env, bool ifetch) -+{ -+ return hflags_mmu_index(env->hflags); -+} -+ -+#include "exec/cpu-all.h" -+ -+/* Memory access type : -+ * may be needed for precise access rights control and precise exceptions. -+ */ -+enum { -+ /* 1 bit to define user level / supervisor access */ -+ ACCESS_USER = 0x00, -+ ACCESS_SUPER = 0x01, -+ /* 1 bit to indicate direction */ -+ ACCESS_STORE = 0x02, -+ /* Type of instruction that generated the access */ -+ ACCESS_CODE = 0x10, /* Code fetch access */ -+ ACCESS_INT = 0x20, /* Integer load/store access */ -+ ACCESS_FLOAT = 0x30, /* floating point load/store access */ -+}; -+ -+/* Exceptions */ -+enum { -+ EXCP_NONE = -1, -+ EXCP_RESET = 0, -+ EXCP_SRESET, -+ EXCP_DINT, -+ EXCP_NMI, -+ EXCP_EXT_INTERRUPT, /* 7 */ -+ EXCP_AdEL, -+ EXCP_AdES, -+ EXCP_TLBF, -+ EXCP_IBE, -+ EXCP_SYSCALL, -+ EXCP_BREAK, -+ EXCP_FPDIS, -+ EXCP_LSXDIS, -+ EXCP_LASXDIS, -+ EXCP_RI, -+ EXCP_OVERFLOW, -+ EXCP_TRAP, -+ EXCP_FPE, -+ EXCP_LTLBL, -+ EXCP_TLBL, -+ EXCP_TLBS, -+ EXCP_DBE, -+ EXCP_TLBXI, -+ EXCP_TLBRI, -+ EXCP_TLBPE, -+ EXCP_BTDIS, -+ -+ EXCP_LAST = EXCP_BTDIS, -+}; -+ -+/* -+ * This is an internally generated WAKE request line. -+ * It is driven by the CPU itself. Raised when the MT -+ * block wants to wake a VPE from an inactive state and -+ * cleared when VPE goes from active to inactive. -+ */ -+#define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 -+ -+int cpu_loongarch_signal_handler(int host_signum, void *pinfo, void *puc); -+ -+#define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU -+#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX -+#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU -+ -+/* helper.c */ -+target_ulong exception_resume_pc(CPULOONGARCHState *env); -+ -+/* gdbstub.c */ -+void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs); -+void mmu_init(CPULOONGARCHState *env, const loongarch_def_t *def); -+ -+static inline void cpu_get_tb_cpu_state(CPULOONGARCHState *env, target_ulong *pc, -+ target_ulong *cs_base, uint32_t *flags) -+{ -+ *pc = env->active_tc.PC; -+ *cs_base = 0; -+ *flags = env->hflags & (LARCH_HFLAG_TMASK | LARCH_HFLAG_BMASK); -+} -+ -+static inline bool cpu_refill_state(CPULOONGARCHState *env) -+{ -+ return env->CSR_TLBRERA & 0x1; -+} -+ -+extern const char * const regnames[]; -+extern const char * const fregnames[]; -+#endif /* LOONGARCH_CPU_H */ -diff --git a/target/loongarch64/csr_helper.c b/target/loongarch64/csr_helper.c -new file mode 100644 -index 000000000..182e59e92 ---- /dev/null -+++ b/target/loongarch64/csr_helper.c -@@ -0,0 +1,704 @@ -+/* -+ * loongarch tlb emulation helpers for qemu. -+ * -+ * Copyright (c) 2020 - 2021 -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 "qemu/main-loop.h" -+#include "cpu.h" -+#include "internal.h" -+#include "qemu/host-utils.h" -+#include "exec/helper-proto.h" -+#include "exec/exec-all.h" -+#include "exec/cpu_ldst.h" -+#include "sysemu/kvm.h" -+#include "hw/irq.h" -+#include "cpu-csr.h" -+#include "instmap.h" -+ -+#ifndef CONFIG_USER_ONLY -+target_ulong helper_csr_rdq(CPULOONGARCHState *env, uint64_t csr) -+{ -+ int64_t v; -+ -+#define CASE_CSR_RDQ(csr) \ -+ case LOONGARCH_CSR_ ## csr: \ -+ { \ -+ v = env->CSR_ ## csr; \ -+ break; \ -+ }; \ -+ -+ switch (csr) { -+ CASE_CSR_RDQ(CRMD) -+ CASE_CSR_RDQ(PRMD) -+ CASE_CSR_RDQ(EUEN) -+ CASE_CSR_RDQ(MISC) -+ CASE_CSR_RDQ(ECFG) -+ CASE_CSR_RDQ(ESTAT) -+ CASE_CSR_RDQ(ERA) -+ CASE_CSR_RDQ(BADV) -+ CASE_CSR_RDQ(BADI) -+ CASE_CSR_RDQ(EEPN) -+ CASE_CSR_RDQ(TLBIDX) -+ CASE_CSR_RDQ(TLBEHI) -+ CASE_CSR_RDQ(TLBELO0) -+ CASE_CSR_RDQ(TLBELO1) -+ CASE_CSR_RDQ(TLBWIRED) -+ CASE_CSR_RDQ(GTLBC) -+ CASE_CSR_RDQ(TRGP) -+ CASE_CSR_RDQ(ASID) -+ CASE_CSR_RDQ(PGDL) -+ CASE_CSR_RDQ(PGDH) -+ CASE_CSR_RDQ(PGD) -+ CASE_CSR_RDQ(PWCTL0) -+ CASE_CSR_RDQ(PWCTL1) -+ CASE_CSR_RDQ(STLBPGSIZE) -+ CASE_CSR_RDQ(RVACFG) -+ CASE_CSR_RDQ(CPUID) -+ CASE_CSR_RDQ(PRCFG1) -+ CASE_CSR_RDQ(PRCFG2) -+ CASE_CSR_RDQ(PRCFG3) -+ CASE_CSR_RDQ(KS0) -+ CASE_CSR_RDQ(KS1) -+ CASE_CSR_RDQ(KS2) -+ CASE_CSR_RDQ(KS3) -+ CASE_CSR_RDQ(KS4) -+ CASE_CSR_RDQ(KS5) -+ CASE_CSR_RDQ(KS6) -+ CASE_CSR_RDQ(KS7) -+ CASE_CSR_RDQ(KS8) -+ CASE_CSR_RDQ(TMID) -+ CASE_CSR_RDQ(TCFG) -+ case LOONGARCH_CSR_TVAL: -+ v = cpu_loongarch_get_stable_timer_ticks(env); -+ break; -+ CASE_CSR_RDQ(CNTC) -+ CASE_CSR_RDQ(TINTCLR) -+ CASE_CSR_RDQ(GSTAT) -+ CASE_CSR_RDQ(GCFG) -+ CASE_CSR_RDQ(GINTC) -+ CASE_CSR_RDQ(GCNTC) -+ CASE_CSR_RDQ(LLBCTL) -+ CASE_CSR_RDQ(IMPCTL1) -+ CASE_CSR_RDQ(IMPCTL2) -+ CASE_CSR_RDQ(GNMI) -+ CASE_CSR_RDQ(TLBRENT) -+ CASE_CSR_RDQ(TLBRBADV) -+ CASE_CSR_RDQ(TLBRERA) -+ CASE_CSR_RDQ(TLBRSAVE) -+ CASE_CSR_RDQ(TLBRELO0) -+ CASE_CSR_RDQ(TLBRELO1) -+ CASE_CSR_RDQ(TLBREHI) -+ CASE_CSR_RDQ(TLBRPRMD) -+ CASE_CSR_RDQ(ERRCTL) -+ CASE_CSR_RDQ(ERRINFO) -+ CASE_CSR_RDQ(ERRINFO1) -+ CASE_CSR_RDQ(ERRENT) -+ CASE_CSR_RDQ(ERRERA) -+ CASE_CSR_RDQ(ERRSAVE) -+ CASE_CSR_RDQ(CTAG) -+ CASE_CSR_RDQ(DMWIN0) -+ CASE_CSR_RDQ(DMWIN1) -+ CASE_CSR_RDQ(DMWIN2) -+ CASE_CSR_RDQ(DMWIN3) -+ CASE_CSR_RDQ(PERFCTRL0) -+ CASE_CSR_RDQ(PERFCNTR0) -+ CASE_CSR_RDQ(PERFCTRL1) -+ CASE_CSR_RDQ(PERFCNTR1) -+ CASE_CSR_RDQ(PERFCTRL2) -+ CASE_CSR_RDQ(PERFCNTR2) -+ CASE_CSR_RDQ(PERFCTRL3) -+ CASE_CSR_RDQ(PERFCNTR3) -+ /* debug */ -+ CASE_CSR_RDQ(MWPC) -+ CASE_CSR_RDQ(MWPS) -+ CASE_CSR_RDQ(DB0ADDR) -+ CASE_CSR_RDQ(DB0MASK) -+ CASE_CSR_RDQ(DB0CTL) -+ CASE_CSR_RDQ(DB0ASID) -+ CASE_CSR_RDQ(DB1ADDR) -+ CASE_CSR_RDQ(DB1MASK) -+ CASE_CSR_RDQ(DB1CTL) -+ CASE_CSR_RDQ(DB1ASID) -+ CASE_CSR_RDQ(DB2ADDR) -+ CASE_CSR_RDQ(DB2MASK) -+ CASE_CSR_RDQ(DB2CTL) -+ CASE_CSR_RDQ(DB2ASID) -+ CASE_CSR_RDQ(DB3ADDR) -+ CASE_CSR_RDQ(DB3MASK) -+ CASE_CSR_RDQ(DB3CTL) -+ CASE_CSR_RDQ(DB3ASID) -+ CASE_CSR_RDQ(FWPC) -+ CASE_CSR_RDQ(FWPS) -+ CASE_CSR_RDQ(IB0ADDR) -+ CASE_CSR_RDQ(IB0MASK) -+ CASE_CSR_RDQ(IB0CTL) -+ CASE_CSR_RDQ(IB0ASID) -+ CASE_CSR_RDQ(IB1ADDR) -+ CASE_CSR_RDQ(IB1MASK) -+ CASE_CSR_RDQ(IB1CTL) -+ CASE_CSR_RDQ(IB1ASID) -+ CASE_CSR_RDQ(IB2ADDR) -+ CASE_CSR_RDQ(IB2MASK) -+ CASE_CSR_RDQ(IB2CTL) -+ CASE_CSR_RDQ(IB2ASID) -+ CASE_CSR_RDQ(IB3ADDR) -+ CASE_CSR_RDQ(IB3MASK) -+ CASE_CSR_RDQ(IB3CTL) -+ CASE_CSR_RDQ(IB3ASID) -+ CASE_CSR_RDQ(IB4ADDR) -+ CASE_CSR_RDQ(IB4MASK) -+ CASE_CSR_RDQ(IB4CTL) -+ CASE_CSR_RDQ(IB4ASID) -+ CASE_CSR_RDQ(IB5ADDR) -+ CASE_CSR_RDQ(IB5MASK) -+ CASE_CSR_RDQ(IB5CTL) -+ CASE_CSR_RDQ(IB5ASID) -+ CASE_CSR_RDQ(IB6ADDR) -+ CASE_CSR_RDQ(IB6MASK) -+ CASE_CSR_RDQ(IB6CTL) -+ CASE_CSR_RDQ(IB6ASID) -+ CASE_CSR_RDQ(IB7ADDR) -+ CASE_CSR_RDQ(IB7MASK) -+ CASE_CSR_RDQ(IB7CTL) -+ CASE_CSR_RDQ(IB7ASID) -+ CASE_CSR_RDQ(DEBUG) -+ CASE_CSR_RDQ(DERA) -+ CASE_CSR_RDQ(DESAVE) -+ default : -+ assert(0); -+ } -+ -+#undef CASE_CSR_RDQ -+ compute_hflags(env); -+ return v; -+} -+ -+target_ulong helper_csr_wrq(CPULOONGARCHState *env, target_ulong val, -+ uint64_t csr) -+{ -+ int64_t old_v, v; -+ old_v = -1; -+ v = val; -+ -+#define CASE_CSR_WRQ(csr) \ -+ case LOONGARCH_CSR_ ## csr: \ -+ { \ -+ old_v = env->CSR_ ## csr; \ -+ env->CSR_ ## csr = v; \ -+ break; \ -+ }; \ -+ -+ switch (csr) { -+ CASE_CSR_WRQ(CRMD) -+ CASE_CSR_WRQ(PRMD) -+ CASE_CSR_WRQ(EUEN) -+ CASE_CSR_WRQ(MISC) -+ CASE_CSR_WRQ(ECFG) -+ CASE_CSR_WRQ(ESTAT) -+ CASE_CSR_WRQ(ERA) -+ CASE_CSR_WRQ(BADV) -+ CASE_CSR_WRQ(BADI) -+ CASE_CSR_WRQ(EEPN) -+ CASE_CSR_WRQ(TLBIDX) -+ CASE_CSR_WRQ(TLBEHI) -+ CASE_CSR_WRQ(TLBELO0) -+ CASE_CSR_WRQ(TLBELO1) -+ CASE_CSR_WRQ(TLBWIRED) -+ CASE_CSR_WRQ(GTLBC) -+ CASE_CSR_WRQ(TRGP) -+ CASE_CSR_WRQ(ASID) -+ CASE_CSR_WRQ(PGDL) -+ CASE_CSR_WRQ(PGDH) -+ CASE_CSR_WRQ(PGD) -+ CASE_CSR_WRQ(PWCTL0) -+ CASE_CSR_WRQ(PWCTL1) -+ CASE_CSR_WRQ(STLBPGSIZE) -+ CASE_CSR_WRQ(RVACFG) -+ CASE_CSR_WRQ(CPUID) -+ CASE_CSR_WRQ(PRCFG1) -+ CASE_CSR_WRQ(PRCFG2) -+ CASE_CSR_WRQ(PRCFG3) -+ CASE_CSR_WRQ(KS0) -+ CASE_CSR_WRQ(KS1) -+ CASE_CSR_WRQ(KS2) -+ CASE_CSR_WRQ(KS3) -+ CASE_CSR_WRQ(KS4) -+ CASE_CSR_WRQ(KS5) -+ CASE_CSR_WRQ(KS6) -+ CASE_CSR_WRQ(KS7) -+ CASE_CSR_WRQ(KS8) -+ CASE_CSR_WRQ(TMID) -+ case LOONGARCH_CSR_TCFG: -+ old_v = env->CSR_TCFG; -+ cpu_loongarch_store_stable_timer_config(env, v); -+ break; -+ CASE_CSR_WRQ(TVAL) -+ CASE_CSR_WRQ(CNTC) -+ case LOONGARCH_CSR_TINTCLR: -+ old_v = 0; -+ qemu_irq_lower(env->irq[IRQ_TIMER]); -+ break; -+ CASE_CSR_WRQ(GSTAT) -+ CASE_CSR_WRQ(GCFG) -+ CASE_CSR_WRQ(GINTC) -+ CASE_CSR_WRQ(GCNTC) -+ CASE_CSR_WRQ(LLBCTL) -+ CASE_CSR_WRQ(IMPCTL1) -+ case LOONGARCH_CSR_IMPCTL2: -+ if (v & CSR_IMPCTL2_MTLB) { -+ ls3a5k_flush_vtlb(env); -+ } -+ if (v & CSR_IMPCTL2_STLB) { -+ ls3a5k_flush_ftlb(env); -+ } -+ break; -+ CASE_CSR_WRQ(GNMI) -+ CASE_CSR_WRQ(TLBRENT) -+ CASE_CSR_WRQ(TLBRBADV) -+ CASE_CSR_WRQ(TLBRERA) -+ CASE_CSR_WRQ(TLBRSAVE) -+ CASE_CSR_WRQ(TLBRELO0) -+ CASE_CSR_WRQ(TLBRELO1) -+ CASE_CSR_WRQ(TLBREHI) -+ CASE_CSR_WRQ(TLBRPRMD) -+ CASE_CSR_WRQ(ERRCTL) -+ CASE_CSR_WRQ(ERRINFO) -+ CASE_CSR_WRQ(ERRINFO1) -+ CASE_CSR_WRQ(ERRENT) -+ CASE_CSR_WRQ(ERRERA) -+ CASE_CSR_WRQ(ERRSAVE) -+ CASE_CSR_WRQ(CTAG) -+ CASE_CSR_WRQ(DMWIN0) -+ CASE_CSR_WRQ(DMWIN1) -+ CASE_CSR_WRQ(DMWIN2) -+ CASE_CSR_WRQ(DMWIN3) -+ CASE_CSR_WRQ(PERFCTRL0) -+ CASE_CSR_WRQ(PERFCNTR0) -+ CASE_CSR_WRQ(PERFCTRL1) -+ CASE_CSR_WRQ(PERFCNTR1) -+ CASE_CSR_WRQ(PERFCTRL2) -+ CASE_CSR_WRQ(PERFCNTR2) -+ CASE_CSR_WRQ(PERFCTRL3) -+ CASE_CSR_WRQ(PERFCNTR3) -+ /* debug */ -+ CASE_CSR_WRQ(MWPC) -+ CASE_CSR_WRQ(MWPS) -+ CASE_CSR_WRQ(DB0ADDR) -+ CASE_CSR_WRQ(DB0MASK) -+ CASE_CSR_WRQ(DB0CTL) -+ CASE_CSR_WRQ(DB0ASID) -+ CASE_CSR_WRQ(DB1ADDR) -+ CASE_CSR_WRQ(DB1MASK) -+ CASE_CSR_WRQ(DB1CTL) -+ CASE_CSR_WRQ(DB1ASID) -+ CASE_CSR_WRQ(DB2ADDR) -+ CASE_CSR_WRQ(DB2MASK) -+ CASE_CSR_WRQ(DB2CTL) -+ CASE_CSR_WRQ(DB2ASID) -+ CASE_CSR_WRQ(DB3ADDR) -+ CASE_CSR_WRQ(DB3MASK) -+ CASE_CSR_WRQ(DB3CTL) -+ CASE_CSR_WRQ(DB3ASID) -+ CASE_CSR_WRQ(FWPC) -+ CASE_CSR_WRQ(FWPS) -+ CASE_CSR_WRQ(IB0ADDR) -+ CASE_CSR_WRQ(IB0MASK) -+ CASE_CSR_WRQ(IB0CTL) -+ CASE_CSR_WRQ(IB0ASID) -+ CASE_CSR_WRQ(IB1ADDR) -+ CASE_CSR_WRQ(IB1MASK) -+ CASE_CSR_WRQ(IB1CTL) -+ CASE_CSR_WRQ(IB1ASID) -+ CASE_CSR_WRQ(IB2ADDR) -+ CASE_CSR_WRQ(IB2MASK) -+ CASE_CSR_WRQ(IB2CTL) -+ CASE_CSR_WRQ(IB2ASID) -+ CASE_CSR_WRQ(IB3ADDR) -+ CASE_CSR_WRQ(IB3MASK) -+ CASE_CSR_WRQ(IB3CTL) -+ CASE_CSR_WRQ(IB3ASID) -+ CASE_CSR_WRQ(IB4ADDR) -+ CASE_CSR_WRQ(IB4MASK) -+ CASE_CSR_WRQ(IB4CTL) -+ CASE_CSR_WRQ(IB4ASID) -+ CASE_CSR_WRQ(IB5ADDR) -+ CASE_CSR_WRQ(IB5MASK) -+ CASE_CSR_WRQ(IB5CTL) -+ CASE_CSR_WRQ(IB5ASID) -+ CASE_CSR_WRQ(IB6ADDR) -+ CASE_CSR_WRQ(IB6MASK) -+ CASE_CSR_WRQ(IB6CTL) -+ CASE_CSR_WRQ(IB6ASID) -+ CASE_CSR_WRQ(IB7ADDR) -+ CASE_CSR_WRQ(IB7MASK) -+ CASE_CSR_WRQ(IB7CTL) -+ CASE_CSR_WRQ(IB7ASID) -+ CASE_CSR_WRQ(DEBUG) -+ CASE_CSR_WRQ(DERA) -+ CASE_CSR_WRQ(DESAVE) -+ default : -+ assert(0); -+ } -+ -+ if (csr == LOONGARCH_CSR_ASID) { -+ if (old_v != v) { -+ tlb_flush(CPU(loongarch_env_get_cpu(env))); -+ } -+ } -+ -+#undef CASE_CSR_WRQ -+ compute_hflags(env); -+ return old_v; -+} -+ -+target_ulong helper_csr_xchgq(CPULOONGARCHState *env, target_ulong val, -+ target_ulong mask, uint64_t csr) -+{ -+ target_ulong v, tmp; -+ v = val & mask; -+ -+#define CASE_CSR_XCHGQ(csr) \ -+ case LOONGARCH_CSR_ ## csr: \ -+ { \ -+ val = env->CSR_ ## csr; \ -+ env->CSR_ ## csr = (env->CSR_ ## csr) & (~mask); \ -+ env->CSR_ ## csr = (env->CSR_ ## csr) | v; \ -+ break; \ -+ }; \ -+ -+ switch (csr) { -+ CASE_CSR_XCHGQ(CRMD) -+ CASE_CSR_XCHGQ(PRMD) -+ CASE_CSR_XCHGQ(EUEN) -+ CASE_CSR_XCHGQ(MISC) -+ CASE_CSR_XCHGQ(ECFG) -+ case LOONGARCH_CSR_ESTAT: -+ val = env->CSR_ESTAT; -+ qatomic_and(&env->CSR_ESTAT, ~mask); -+ qatomic_or(&env->CSR_ESTAT, v); -+ break; -+ CASE_CSR_XCHGQ(ERA) -+ CASE_CSR_XCHGQ(BADV) -+ CASE_CSR_XCHGQ(BADI) -+ CASE_CSR_XCHGQ(EEPN) -+ CASE_CSR_XCHGQ(TLBIDX) -+ CASE_CSR_XCHGQ(TLBEHI) -+ CASE_CSR_XCHGQ(TLBELO0) -+ CASE_CSR_XCHGQ(TLBELO1) -+ CASE_CSR_XCHGQ(TLBWIRED) -+ CASE_CSR_XCHGQ(GTLBC) -+ CASE_CSR_XCHGQ(TRGP) -+ CASE_CSR_XCHGQ(ASID) -+ CASE_CSR_XCHGQ(PGDL) -+ CASE_CSR_XCHGQ(PGDH) -+ CASE_CSR_XCHGQ(PGD) -+ CASE_CSR_XCHGQ(PWCTL0) -+ CASE_CSR_XCHGQ(PWCTL1) -+ CASE_CSR_XCHGQ(STLBPGSIZE) -+ CASE_CSR_XCHGQ(RVACFG) -+ CASE_CSR_XCHGQ(CPUID) -+ CASE_CSR_XCHGQ(PRCFG1) -+ CASE_CSR_XCHGQ(PRCFG2) -+ CASE_CSR_XCHGQ(PRCFG3) -+ CASE_CSR_XCHGQ(KS0) -+ CASE_CSR_XCHGQ(KS1) -+ CASE_CSR_XCHGQ(KS2) -+ CASE_CSR_XCHGQ(KS3) -+ CASE_CSR_XCHGQ(KS4) -+ CASE_CSR_XCHGQ(KS5) -+ CASE_CSR_XCHGQ(KS6) -+ CASE_CSR_XCHGQ(KS7) -+ CASE_CSR_XCHGQ(KS8) -+ CASE_CSR_XCHGQ(TMID) -+ case LOONGARCH_CSR_TCFG: -+ val = env->CSR_TCFG; -+ tmp = val & ~mask; -+ tmp |= v; -+ cpu_loongarch_store_stable_timer_config(env, tmp); -+ break; -+ CASE_CSR_XCHGQ(TVAL) -+ CASE_CSR_XCHGQ(CNTC) -+ CASE_CSR_XCHGQ(TINTCLR) -+ CASE_CSR_XCHGQ(GSTAT) -+ CASE_CSR_XCHGQ(GCFG) -+ CASE_CSR_XCHGQ(GINTC) -+ CASE_CSR_XCHGQ(GCNTC) -+ CASE_CSR_XCHGQ(LLBCTL) -+ CASE_CSR_XCHGQ(IMPCTL1) -+ CASE_CSR_XCHGQ(IMPCTL2) -+ CASE_CSR_XCHGQ(GNMI) -+ CASE_CSR_XCHGQ(TLBRENT) -+ CASE_CSR_XCHGQ(TLBRBADV) -+ CASE_CSR_XCHGQ(TLBRERA) -+ CASE_CSR_XCHGQ(TLBRSAVE) -+ CASE_CSR_XCHGQ(TLBRELO0) -+ CASE_CSR_XCHGQ(TLBRELO1) -+ CASE_CSR_XCHGQ(TLBREHI) -+ CASE_CSR_XCHGQ(TLBRPRMD) -+ CASE_CSR_XCHGQ(ERRCTL) -+ CASE_CSR_XCHGQ(ERRINFO) -+ CASE_CSR_XCHGQ(ERRINFO1) -+ CASE_CSR_XCHGQ(ERRENT) -+ CASE_CSR_XCHGQ(ERRERA) -+ CASE_CSR_XCHGQ(ERRSAVE) -+ CASE_CSR_XCHGQ(CTAG) -+ CASE_CSR_XCHGQ(DMWIN0) -+ CASE_CSR_XCHGQ(DMWIN1) -+ CASE_CSR_XCHGQ(DMWIN2) -+ CASE_CSR_XCHGQ(DMWIN3) -+ CASE_CSR_XCHGQ(PERFCTRL0) -+ CASE_CSR_XCHGQ(PERFCNTR0) -+ CASE_CSR_XCHGQ(PERFCTRL1) -+ CASE_CSR_XCHGQ(PERFCNTR1) -+ CASE_CSR_XCHGQ(PERFCTRL2) -+ CASE_CSR_XCHGQ(PERFCNTR2) -+ CASE_CSR_XCHGQ(PERFCTRL3) -+ CASE_CSR_XCHGQ(PERFCNTR3) -+ /* debug */ -+ CASE_CSR_XCHGQ(MWPC) -+ CASE_CSR_XCHGQ(MWPS) -+ CASE_CSR_XCHGQ(DB0ADDR) -+ CASE_CSR_XCHGQ(DB0MASK) -+ CASE_CSR_XCHGQ(DB0CTL) -+ CASE_CSR_XCHGQ(DB0ASID) -+ CASE_CSR_XCHGQ(DB1ADDR) -+ CASE_CSR_XCHGQ(DB1MASK) -+ CASE_CSR_XCHGQ(DB1CTL) -+ CASE_CSR_XCHGQ(DB1ASID) -+ CASE_CSR_XCHGQ(DB2ADDR) -+ CASE_CSR_XCHGQ(DB2MASK) -+ CASE_CSR_XCHGQ(DB2CTL) -+ CASE_CSR_XCHGQ(DB2ASID) -+ CASE_CSR_XCHGQ(DB3ADDR) -+ CASE_CSR_XCHGQ(DB3MASK) -+ CASE_CSR_XCHGQ(DB3CTL) -+ CASE_CSR_XCHGQ(DB3ASID) -+ CASE_CSR_XCHGQ(FWPC) -+ CASE_CSR_XCHGQ(FWPS) -+ CASE_CSR_XCHGQ(IB0ADDR) -+ CASE_CSR_XCHGQ(IB0MASK) -+ CASE_CSR_XCHGQ(IB0CTL) -+ CASE_CSR_XCHGQ(IB0ASID) -+ CASE_CSR_XCHGQ(IB1ADDR) -+ CASE_CSR_XCHGQ(IB1MASK) -+ CASE_CSR_XCHGQ(IB1CTL) -+ CASE_CSR_XCHGQ(IB1ASID) -+ CASE_CSR_XCHGQ(IB2ADDR) -+ CASE_CSR_XCHGQ(IB2MASK) -+ CASE_CSR_XCHGQ(IB2CTL) -+ CASE_CSR_XCHGQ(IB2ASID) -+ CASE_CSR_XCHGQ(IB3ADDR) -+ CASE_CSR_XCHGQ(IB3MASK) -+ CASE_CSR_XCHGQ(IB3CTL) -+ CASE_CSR_XCHGQ(IB3ASID) -+ CASE_CSR_XCHGQ(IB4ADDR) -+ CASE_CSR_XCHGQ(IB4MASK) -+ CASE_CSR_XCHGQ(IB4CTL) -+ CASE_CSR_XCHGQ(IB4ASID) -+ CASE_CSR_XCHGQ(IB5ADDR) -+ CASE_CSR_XCHGQ(IB5MASK) -+ CASE_CSR_XCHGQ(IB5CTL) -+ CASE_CSR_XCHGQ(IB5ASID) -+ CASE_CSR_XCHGQ(IB6ADDR) -+ CASE_CSR_XCHGQ(IB6MASK) -+ CASE_CSR_XCHGQ(IB6CTL) -+ CASE_CSR_XCHGQ(IB6ASID) -+ CASE_CSR_XCHGQ(IB7ADDR) -+ CASE_CSR_XCHGQ(IB7MASK) -+ CASE_CSR_XCHGQ(IB7CTL) -+ CASE_CSR_XCHGQ(IB7ASID) -+ CASE_CSR_XCHGQ(DEBUG) -+ CASE_CSR_XCHGQ(DERA) -+ CASE_CSR_XCHGQ(DESAVE) -+ default : -+ assert(0); -+ } -+ -+#undef CASE_CSR_XCHGQ -+ compute_hflags(env); -+ return val; -+} -+ -+static target_ulong confbus_addr(CPULOONGARCHState *env, int cpuid, -+ target_ulong csr_addr) -+{ -+ target_ulong addr; -+ target_ulong node_addr; -+ int cores_per_node = ((0x60018 >> 3) & 0xff) + 1; -+ -+ switch (cores_per_node) { -+ case 4: -+ assert(cpuid < 64); -+ node_addr = ((target_ulong)(cpuid & 0x3c) << 42); -+ break; -+ case 8: -+ assert(cpuid < 128); -+ node_addr = ((target_ulong)(cpuid & 0x78) << 41) + -+ ((target_ulong)(cpuid & 0x4) << 14); -+ break; -+ case 16: -+ assert(cpuid < 256); -+ node_addr = ((target_ulong)(cpuid & 0xf0) << 40) + -+ ((target_ulong)(cpuid & 0xc) << 14); -+ break; -+ default: -+ assert(0); -+ break; -+ } -+ -+ /* -+ * per core address -+ *0x10xx => ipi -+ * 0x18xx => extioi isr -+ */ -+ if (((csr_addr & 0xff00) == 0x1000)) { -+ addr = (csr_addr & 0xff) + (target_ulong)(cpuid << 8); -+ addr = 0x800000001f000000UL + addr; -+ return addr; -+ } else if ((csr_addr & 0xff00) == 0x1800) { -+ addr = (csr_addr & 0xff) + ((target_ulong)(cpuid << 8)); -+ addr = 0x800000001f020000UL + addr; -+ return addr; -+ } else if ((csr_addr & 0xff00) >= 0x1400 && (csr_addr & 0xff00) < 0x1d00) { -+ addr = 0x800000001f010000UL + ((csr_addr & 0xfff) - 0x400); -+ return addr; -+ } else if (csr_addr == 0x408) { -+ addr = csr_addr; -+ } else { -+ addr = csr_addr + node_addr; -+ } -+ -+ addr = 0x800000001fe00000UL + addr; -+ return addr; -+} -+ -+void helper_iocsr(CPULOONGARCHState *env, target_ulong r_addr, -+ target_ulong r_val, uint32_t op) -+{ -+ target_ulong addr; -+ target_ulong val = env->active_tc.gpr[r_val]; -+ int mask; -+ -+ addr = confbus_addr(env, CPU(loongarch_env_get_cpu(env))->cpu_index, -+ env->active_tc.gpr[r_addr]); -+ -+ switch (env->active_tc.gpr[r_addr]) { -+ /* IPI send */ -+ case 0x1040: -+ if (op != OPC_LARCH_ST_W) { -+ return; -+ } -+ op = OPC_LARCH_ST_W; -+ break; -+ -+ /* Mail send */ -+ case 0x1048: -+ if (op != OPC_LARCH_ST_D) { -+ return; -+ } -+ op = OPC_LARCH_ST_D; -+ break; -+ -+ /* ANY send */ -+ case 0x1158: -+ if (op != OPC_LARCH_ST_D) { -+ return; -+ } -+ addr = confbus_addr(env, (val >> 16) & 0x3ff, val & 0xffff); -+ mask = (val >> 27) & 0xf; -+ val = (val >> 32); -+ switch (mask) { -+ case 0: -+ op = OPC_LARCH_ST_W; -+ break; -+ case 0x7: -+ op = OPC_LARCH_ST_B; -+ addr += 3; -+ val >>= 24; -+ break; -+ case 0xb: -+ op = OPC_LARCH_ST_B; -+ addr += 2; -+ val >>= 16; -+ break; -+ case 0xd: -+ op = OPC_LARCH_ST_B; -+ addr += 1; -+ val >>= 8; -+ break; -+ case 0xe: -+ op = OPC_LARCH_ST_B; -+ break; -+ case 0xc: -+ op = OPC_LARCH_ST_H; -+ break; -+ case 0x3: -+ op = OPC_LARCH_ST_H; -+ addr += 2; -+ val >>= 16; -+ break; -+ default: -+ qemu_log("Unsupported any_send mask0x%x\n", mask); -+ break; -+ } -+ break; -+ -+ default: -+ break; -+ } -+ -+ switch (op) { -+ case OPC_LARCH_LD_D: -+ env->active_tc.gpr[r_val] = cpu_ldq_data_ra(env, addr, -+ GETPC()); -+ break; -+ case OPC_LARCH_LD_W: -+ env->active_tc.gpr[r_val] = cpu_ldl_data_ra(env, addr, -+ GETPC()); -+ break; -+ case OPC_LARCH_LD_H: -+ assert(0); -+ break; -+ case OPC_LARCH_LD_B: -+ assert(0); -+ break; -+ case OPC_LARCH_ST_D: -+ cpu_stq_data_ra(env, addr, val, GETPC()); -+ break; -+ case OPC_LARCH_ST_W: -+ cpu_stl_data_ra(env, addr, val, GETPC()); -+ break; -+ case OPC_LARCH_ST_H: -+ cpu_stb_data_ra(env, addr, val, GETPC()); -+ break; -+ case OPC_LARCH_ST_B: -+ cpu_stb_data_ra(env, addr, val, GETPC()); -+ break; -+ default: -+ qemu_log("Unknown op 0x%x", op); -+ assert(0); -+ } -+} -+#endif -+ -+target_ulong helper_cpucfg(CPULOONGARCHState *env, target_ulong rj) -+{ -+ return 0; -+} -+ -+ -diff --git a/target/loongarch64/fpu.c b/target/loongarch64/fpu.c -new file mode 100644 -index 000000000..795458205 ---- /dev/null -+++ b/target/loongarch64/fpu.c -@@ -0,0 +1,28 @@ -+/* -+ * loongarch float point emulation helpers for qemu. -+ * -+ * Copyright (c) 2020-2021 -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 "fpu/softfloat.h" -+ -+/* convert loongarch rounding mode in fcsr0 to IEEE library */ -+unsigned int ieee_rm[] = { -+ float_round_nearest_even, -+ float_round_to_zero, -+ float_round_up, -+ float_round_down -+}; -diff --git a/target/loongarch64/fpu_helper.c b/target/loongarch64/fpu_helper.c -new file mode 100644 -index 000000000..42d7f05ca ---- /dev/null -+++ b/target/loongarch64/fpu_helper.c -@@ -0,0 +1,952 @@ -+/* -+ * loongarch float point emulation helpers for qemu. -+ * -+ * Copyright (c) 2020-2021 -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 "cpu.h" -+#include "internal.h" -+#include "qemu/host-utils.h" -+#include "exec/helper-proto.h" -+#include "exec/exec-all.h" -+#include "fpu/softfloat.h" -+ -+#define FP_TO_INT32_OVERFLOW 0x7fffffff -+#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL -+ -+#define FLOAT_CLASS_SIGNALING_NAN 0x001 -+#define FLOAT_CLASS_QUIET_NAN 0x002 -+#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 -+#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008 -+#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 -+#define FLOAT_CLASS_NEGATIVE_ZERO 0x020 -+#define FLOAT_CLASS_POSITIVE_INFINITY 0x040 -+#define FLOAT_CLASS_POSITIVE_NORMAL 0x080 -+#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 -+#define FLOAT_CLASS_POSITIVE_ZERO 0x200 -+ -+target_ulong helper_movfcsr2gr(CPULOONGARCHState *env, uint32_t reg) -+{ -+ target_ulong r = 0; -+ -+ switch (reg) { -+ case 0: -+ r = (uint32_t)env->active_fpu.fcsr0; -+ break; -+ case 1: -+ r = (env->active_fpu.fcsr0 & FCSR0_M1); -+ break; -+ case 2: -+ r = (env->active_fpu.fcsr0 & FCSR0_M2); -+ break; -+ case 3: -+ r = (env->active_fpu.fcsr0 & FCSR0_M3); -+ break; -+ case 16: -+ r = (uint32_t)env->active_fpu.vcsr16; -+ break; -+ default: -+ printf("%s: warning, fcsr '%d' not supported\n", __func__, reg); -+ assert(0); -+ break; -+ } -+ -+ return r; -+} -+ -+void helper_movgr2fcsr(CPULOONGARCHState *env, target_ulong arg1, -+ uint32_t fcsr, uint32_t rj) -+{ -+ switch (fcsr) { -+ case 0: -+ env->active_fpu.fcsr0 = arg1; -+ break; -+ case 1: -+ env->active_fpu.fcsr0 = (arg1 & FCSR0_M1) | -+ (env->active_fpu.fcsr0 & ~FCSR0_M1); -+ break; -+ case 2: -+ env->active_fpu.fcsr0 = (arg1 & FCSR0_M2) | -+ (env->active_fpu.fcsr0 & ~FCSR0_M2); -+ break; -+ case 3: -+ env->active_fpu.fcsr0 = (arg1 & FCSR0_M3) | -+ (env->active_fpu.fcsr0 & ~FCSR0_M3); -+ break; -+ case 16: -+ env->active_fpu.vcsr16 = arg1; -+ break; -+ default: -+ printf("%s: warning, fcsr '%d' not supported\n", __func__, fcsr); -+ assert(0); -+ break; -+ } -+ restore_fp_status(env); -+ set_float_exception_flags(0, &env->active_fpu.fp_status); -+} -+ -+void helper_movreg2cf(CPULOONGARCHState *env, uint32_t cd, target_ulong src) -+{ -+ env->active_fpu.cf[cd & 0x7] = src & 0x1; -+} -+ -+void helper_movreg2cf_i32(CPULOONGARCHState *env, uint32_t cd, uint32_t src) -+{ -+ env->active_fpu.cf[cd & 0x7] = src & 0x1; -+} -+ -+void helper_movreg2cf_i64(CPULOONGARCHState *env, uint32_t cd, uint64_t src) -+{ -+ env->active_fpu.cf[cd & 0x7] = src & 0x1; -+} -+ -+target_ulong helper_movcf2reg(CPULOONGARCHState *env, uint32_t cj) -+{ -+ return (target_ulong)env->active_fpu.cf[cj & 0x7]; -+} -+ -+int ieee_ex_to_loongarch(int xcpt) -+{ -+ int ret = 0; -+ if (xcpt) { -+ if (xcpt & float_flag_invalid) { -+ ret |= FP_INVALID; -+ } -+ if (xcpt & float_flag_overflow) { -+ ret |= FP_OVERFLOW; -+ } -+ if (xcpt & float_flag_underflow) { -+ ret |= FP_UNDERFLOW; -+ } -+ if (xcpt & float_flag_divbyzero) { -+ ret |= FP_DIV0; -+ } -+ if (xcpt & float_flag_inexact) { -+ ret |= FP_INEXACT; -+ } -+ } -+ return ret; -+} -+ -+static inline void update_fcsr0(CPULOONGARCHState *env, uintptr_t pc) -+{ -+ int tmp = ieee_ex_to_loongarch(get_float_exception_flags( -+ &env->active_fpu.fp_status)); -+ -+ SET_FP_CAUSE(env->active_fpu.fcsr0, tmp); -+ if (tmp) { -+ set_float_exception_flags(0, &env->active_fpu.fp_status); -+ -+ if (GET_FP_ENABLE(env->active_fpu.fcsr0) & tmp) { -+ do_raise_exception(env, EXCP_FPE, pc); -+ } else { -+ UPDATE_FP_FLAGS(env->active_fpu.fcsr0, tmp); -+ } -+ } -+} -+ -+/* unary operations, modifying fp status */ -+uint64_t helper_float_sqrt_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt0; -+} -+ -+uint32_t helper_float_sqrt_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst0; -+} -+ -+uint64_t helper_float_cvtd_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint64_t helper_float_cvtd_w(CPULOONGARCHState *env, uint32_t wt0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint64_t helper_float_cvtd_l(CPULOONGARCHState *env, uint64_t dt0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint64_t helper_float_cvt_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_cvt_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_cvts_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t fst2; -+ -+ fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint32_t helper_float_cvts_w(CPULOONGARCHState *env, uint32_t wt0) -+{ -+ uint32_t fst2; -+ -+ fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint32_t helper_float_cvts_l(CPULOONGARCHState *env, uint64_t dt0) -+{ -+ uint32_t fst2; -+ -+ fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint32_t helper_float_cvt_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_cvt_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_round_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_nearest_even, -+ &env->active_fpu.fp_status); -+ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_round_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_nearest_even, -+ &env->active_fpu.fp_status); -+ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_round_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_nearest_even, -+ &env->active_fpu.fp_status); -+ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_round_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_nearest_even, -+ &env->active_fpu.fp_status); -+ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_trunc_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float64_to_int64_round_to_zero(fdt0, -+ &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_trunc_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_trunc_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_trunc_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_ceil_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); -+ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_ceil_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); -+ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_ceil_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); -+ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_ceil_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); -+ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_floor_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); -+ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_floor_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); -+ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_floor_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); -+ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_floor_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); -+ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+/* unary operations, not modifying fp status */ -+#define FLOAT_UNOP(name) \ -+uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \ -+{ \ -+ return float64_ ## name(fdt0); \ -+} \ -+uint32_t helper_float_ ## name ## _s(uint32_t fst0) \ -+{ \ -+ return float32_ ## name(fst0); \ -+} -+ -+FLOAT_UNOP(abs) -+FLOAT_UNOP(chs) -+#undef FLOAT_UNOP -+ -+uint64_t helper_float_recip_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint32_t helper_float_recip_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t fst2; -+ -+ fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint64_t helper_float_rsqrt_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status); -+ fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint32_t helper_float_rsqrt_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t fst2; -+ -+ fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status); -+ fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint32_t helper_float_rint_s(CPULOONGARCHState *env, uint32_t fs) -+{ -+ uint32_t fdret; -+ -+ fdret = float32_round_to_int(fs, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdret; -+} -+ -+uint64_t helper_float_rint_d(CPULOONGARCHState *env, uint64_t fs) -+{ -+ uint64_t fdret; -+ -+ fdret = float64_round_to_int(fs, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdret; -+} -+ -+#define FLOAT_CLASS(name, bits) \ -+uint ## bits ## _t float_ ## name(uint ## bits ## _t arg, \ -+ float_status *status) \ -+{ \ -+ if (float ## bits ## _is_signaling_nan(arg, status)) { \ -+ return FLOAT_CLASS_SIGNALING_NAN; \ -+ } else if (float ## bits ## _is_quiet_nan(arg, status)) { \ -+ return FLOAT_CLASS_QUIET_NAN; \ -+ } else if (float ## bits ## _is_neg(arg)) { \ -+ if (float ## bits ## _is_infinity(arg)) { \ -+ return FLOAT_CLASS_NEGATIVE_INFINITY; \ -+ } else if (float ## bits ## _is_zero(arg)) { \ -+ return FLOAT_CLASS_NEGATIVE_ZERO; \ -+ } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ -+ return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ -+ } else { \ -+ return FLOAT_CLASS_NEGATIVE_NORMAL; \ -+ } \ -+ } else { \ -+ if (float ## bits ## _is_infinity(arg)) { \ -+ return FLOAT_CLASS_POSITIVE_INFINITY; \ -+ } else if (float ## bits ## _is_zero(arg)) { \ -+ return FLOAT_CLASS_POSITIVE_ZERO; \ -+ } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ -+ return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ -+ } else { \ -+ return FLOAT_CLASS_POSITIVE_NORMAL; \ -+ } \ -+ } \ -+} \ -+ \ -+uint ## bits ## _t helper_float_ ## name(CPULOONGARCHState *env, \ -+ uint ## bits ## _t arg) \ -+{ \ -+ return float_ ## name(arg, &env->active_fpu.fp_status); \ -+} -+ -+FLOAT_CLASS(class_s, 32) -+FLOAT_CLASS(class_d, 64) -+#undef FLOAT_CLASS -+ -+/* binary operations */ -+#define FLOAT_BINOP(name) \ -+uint64_t helper_float_ ## name ## _d(CPULOONGARCHState *env, \ -+ uint64_t fdt0, uint64_t fdt1) \ -+{ \ -+ uint64_t dt2; \ -+ \ -+ dt2 = float64_ ## name(fdt0, fdt1, &env->active_fpu.fp_status);\ -+ update_fcsr0(env, GETPC()); \ -+ return dt2; \ -+} \ -+ \ -+uint32_t helper_float_ ## name ## _s(CPULOONGARCHState *env, \ -+ uint32_t fst0, uint32_t fst1) \ -+{ \ -+ uint32_t wt2; \ -+ \ -+ wt2 = float32_ ## name(fst0, fst1, &env->active_fpu.fp_status);\ -+ update_fcsr0(env, GETPC()); \ -+ return wt2; \ -+} -+ -+FLOAT_BINOP(add) -+FLOAT_BINOP(sub) -+FLOAT_BINOP(mul) -+FLOAT_BINOP(div) -+#undef FLOAT_BINOP -+ -+uint64_t helper_float_exp2_d(CPULOONGARCHState *env, -+ uint64_t fdt0, uint64_t fdt1) -+{ -+ uint64_t dt2; -+ int64_t n = (int64_t)fdt1; -+ -+ dt2 = float64_scalbn(fdt0, -+ n > 0x1000 ? 0x1000 : -+ n < -0x1000 ? -0x1000 : n, -+ &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_exp2_s(CPULOONGARCHState *env, -+ uint32_t fst0, uint32_t fst1) -+{ -+ uint32_t wt2; -+ int32_t n = (int32_t)fst1; -+ -+ wt2 = float32_scalbn(fst0, -+ n > 0x200 ? 0x200 : -+ n < -0x200 ? -0x200 : n, -+ &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+#define FLOAT_MINMAX(name, bits, minmaxfunc) \ -+uint ## bits ## _t helper_float_ ## name(CPULOONGARCHState *env, \ -+ uint ## bits ## _t fs, \ -+ uint ## bits ## _t ft) \ -+{ \ -+ uint ## bits ## _t fdret; \ -+ \ -+ fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ -+ &env->active_fpu.fp_status); \ -+ update_fcsr0(env, GETPC()); \ -+ return fdret; \ -+} -+ -+FLOAT_MINMAX(max_s, 32, maxnum) -+FLOAT_MINMAX(max_d, 64, maxnum) -+FLOAT_MINMAX(maxa_s, 32, maxnummag) -+FLOAT_MINMAX(maxa_d, 64, maxnummag) -+ -+FLOAT_MINMAX(min_s, 32, minnum) -+FLOAT_MINMAX(min_d, 64, minnum) -+FLOAT_MINMAX(mina_s, 32, minnummag) -+FLOAT_MINMAX(mina_d, 64, minnummag) -+#undef FLOAT_MINMAX -+ -+#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ -+uint ## bits ## _t helper_float_ ## name(CPULOONGARCHState *env, \ -+ uint ## bits ## _t fs, \ -+ uint ## bits ## _t ft, \ -+ uint ## bits ## _t fd) \ -+{ \ -+ uint ## bits ## _t fdret; \ -+ \ -+ fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ -+ &env->active_fpu.fp_status); \ -+ update_fcsr0(env, GETPC()); \ -+ return fdret; \ -+} -+ -+FLOAT_FMADDSUB(maddf_s, 32, 0) -+FLOAT_FMADDSUB(maddf_d, 64, 0) -+FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_c) -+FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_c) -+FLOAT_FMADDSUB(nmaddf_s, 32, float_muladd_negate_result) -+FLOAT_FMADDSUB(nmaddf_d, 64, float_muladd_negate_result) -+FLOAT_FMADDSUB(nmsubf_s, 32, float_muladd_negate_result | float_muladd_negate_c) -+FLOAT_FMADDSUB(nmsubf_d, 64, float_muladd_negate_result | float_muladd_negate_c) -+#undef FLOAT_FMADDSUB -+ -+/* compare operations */ -+#define FOP_CONDN_D(op, cond) \ -+uint64_t helper_cmp_d_ ## op(CPULOONGARCHState *env, uint64_t fdt0, \ -+ uint64_t fdt1) \ -+{ \ -+ uint64_t c; \ -+ c = cond; \ -+ update_fcsr0(env, GETPC()); \ -+ if (c) { \ -+ return -1; \ -+ } else { \ -+ return 0; \ -+ } \ -+} -+ -+/* -+ * NOTE: the comma operator will make "cond" to eval to false, -+ * but float64_unordered_quiet() is still called. -+ */ -+FOP_CONDN_D(af, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status), 0)) -+FOP_CONDN_D(un, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(eq, (float64_eq_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_eq_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(lt, (float64_lt_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(le, (float64_le_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_le_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+/* -+ * NOTE: the comma operator will make "cond" to eval to false, -+ * but float64_unordered() is still called. -+ */ -+FOP_CONDN_D(saf, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status), 0)) -+FOP_CONDN_D(sun, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(seq, (float64_eq(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_eq(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(slt, (float64_lt(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sle, (float64_le(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_le(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(or, (float64_le_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_le_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(une, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(ne, (float64_lt_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sor, (float64_le(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_le(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sne, (float64_lt(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+ -+#define FOP_CONDN_S(op, cond) \ -+uint32_t helper_cmp_s_ ## op(CPULOONGARCHState *env, uint32_t fst0, \ -+ uint32_t fst1) \ -+{ \ -+ uint64_t c; \ -+ c = cond; \ -+ update_fcsr0(env, GETPC()); \ -+ if (c) { \ -+ return -1; \ -+ } else { \ -+ return 0; \ -+ } \ -+} -+ -+/* -+ * NOTE: the comma operator will make "cond" to eval to false, -+ * but float32_unordered_quiet() is still called. -+ */ -+FOP_CONDN_S(af, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status), 0)) -+FOP_CONDN_S(un, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(eq, (float32_eq_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(ueq, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_eq_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(lt, (float32_lt_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(ult, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(le, (float32_le_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(ule, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_le_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+/* -+ * NOTE: the comma operator will make "cond" to eval to false, -+ * but float32_unordered() is still called. -+ */ -+FOP_CONDN_S(saf, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status), 0)) -+FOP_CONDN_S(sun, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(seq, (float32_eq(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_eq(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(slt, (float32_lt(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sle, (float32_le(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_le(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(or, (float32_le_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_le_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(une, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(ne, (float32_lt_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sor, (float32_le(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_le(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sne, (float32_lt(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt(fst0, fst1, -+ &env->active_fpu.fp_status))) -+ -+uint32_t helper_float_logb_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float32_log2(fst0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_logb_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float64_log2(fdt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+target_ulong helper_fsel(CPULOONGARCHState *env, target_ulong fj, -+ target_ulong fk, uint32_t ca) -+{ -+ if (env->active_fpu.cf[ca & 0x7]) { -+ return fk; -+ } else { -+ return fj; -+ } -+} -diff --git a/target/loongarch64/fpu_helper.h b/target/loongarch64/fpu_helper.h -new file mode 100644 -index 000000000..b6898c2e9 ---- /dev/null -+++ b/target/loongarch64/fpu_helper.h -@@ -0,0 +1,129 @@ -+/* loongarch internal definitions and helpers -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef LOONGARCH_FPU_H -+#define LOONGARCH_FPU_H -+ -+#include "cpu-csr.h" -+ -+ -+extern const struct loongarch_def_t loongarch_defs[]; -+extern const int loongarch_defs_number; -+ -+enum CPULSXDataFormat { -+ DF_BYTE = 0, -+ DF_HALF, -+ DF_WORD, -+ DF_DOUBLE, -+ DF_QUAD -+}; -+ -+void loongarch_cpu_do_interrupt(CPUState *cpu); -+bool loongarch_cpu_exec_interrupt(CPUState *cpu, int int_req); -+void loongarch_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, -+ MMUAccessType access_type, -+ int mmu_idx, uintptr_t retaddr) QEMU_NORETURN; -+ -+#if !defined(CONFIG_USER_ONLY) -+ -+typedef struct r4k_tlb_t r4k_tlb_t; -+struct r4k_tlb_t { -+ target_ulong VPN; -+ uint32_t PageMask; -+ uint16_t ASID; -+ unsigned int G:1; -+ unsigned int C0:3; -+ unsigned int C1:3; -+ unsigned int V0:1; -+ unsigned int V1:1; -+ unsigned int D0:1; -+ unsigned int D1:1; -+ unsigned int XI0:1; -+ unsigned int XI1:1; -+ unsigned int RI0:1; -+ unsigned int RI1:1; -+ unsigned int EHINV:1; -+ uint64_t PPN[2]; -+}; -+ -+int no_mmu_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type); -+int fixed_mmu_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type); -+int r4k_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type); -+ -+/* loongarch 3a5000 tlb helper function : lisa csr */ -+int ls3a5k_map_address(CPULOONGARCHState *env, hwaddr *physical, -+ int *prot, target_ulong address, -+ int rw, int access_type); -+void ls3a5k_helper_tlbwr(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbfill(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbsrch(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbrd(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbclr(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbflush(CPULOONGARCHState *env); -+void ls3a5k_invalidate_tlb(CPULOONGARCHState *env, int idx); -+void ls3a5k_helper_invtlb(CPULOONGARCHState *env, target_ulong addr, -+ target_ulong info, int op); -+void ls3a5k_flush_vtlb(CPULOONGARCHState *env); -+void ls3a5k_flush_ftlb(CPULOONGARCHState *env); -+/*void loongarch_cpu_unassigned_access(CPUState *cpu, hwaddr addr, -+ bool is_write, bool is_exec, int unused, -+ unsigned size); -+*/ -+hwaddr cpu_loongarch_translate_address(CPULOONGARCHState *env, target_ulong address, -+ int rw); -+#endif -+ -+#define cpu_signal_handler cpu_loongarch_signal_handler -+ -+ -+static inline bool cpu_loongarch_hw_interrupts_enabled(CPULOONGARCHState *env) -+{ -+ bool ret = 0; -+ -+ ret = env->CSR_CRMD & (1 << CSR_CRMD_IE_SHIFT); -+ -+ return ret; -+} -+ -+ -+void loongarch_tcg_init(void); -+ -+ -+/* helper.c */ -+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, -+ MMUAccessType access_type, int mmu_idx, -+ bool probe, uintptr_t retaddr); -+ -+/* op_helper.c */ -+uint32_t float_class_s(uint32_t arg, float_status *fst); -+uint64_t float_class_d(uint64_t arg, float_status *fst); -+ -+int ieee_ex_to_loongarch(int xcpt); -+void update_pagemask(CPULOONGARCHState *env, target_ulong arg1, int32_t *pagemask); -+ -+void cpu_loongarch_tlb_flush(CPULOONGARCHState *env); -+void sync_c0_status(CPULOONGARCHState *env, CPULOONGARCHState *cpu, int tc); -+ -+void QEMU_NORETURN do_raise_exception_err(CPULOONGARCHState *env, uint32_t exception, -+ int error_code, uintptr_t pc); -+int loongarch_read_qxfer(CPUState *cs, const char *annex, -+ uint8_t *read_buf, -+ unsigned long offset, unsigned long len); -+int loongarch_write_qxfer(CPUState *cs, const char *annex, -+ const uint8_t *write_buf, -+ unsigned long offset, unsigned long len); -+ -+static inline void QEMU_NORETURN do_raise_exception(CPULOONGARCHState *env, -+ uint32_t exception, -+ uintptr_t pc) -+{ -+ do_raise_exception_err(env, exception, 0, pc); -+} -+ -+#endif -diff --git a/target/loongarch64/gdbstub.c b/target/loongarch64/gdbstub.c -new file mode 100644 -index 000000000..4013178f4 ---- /dev/null -+++ b/target/loongarch64/gdbstub.c -@@ -0,0 +1,109 @@ -+/* -+ * LOONGARCH gdb server stub -+ * -+ * Copyright (c) 2003-2005 Fabrice Bellard -+ * Copyright (c) 2013 SUSE LINUX Products GmbH -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 "qemu-common.h" -+#include "cpu.h" -+#include "internal.h" -+#include "exec/gdbstub.h" -+#ifdef CONFIG_TCG -+#include "exec/helper-proto.h" -+#endif -+int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ if (0 <= n && n < 32) { -+ return gdb_get_regl(mem_buf, env->active_tc.gpr[n]); -+ } else if (n == 32) { -+ return gdb_get_regl(mem_buf, env->active_tc.PC); -+ } -+ return 0; -+} -+ -+int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ target_ulong tmp = ldtul_p(mem_buf); -+ -+ if (0 <= n && n < 32) { -+ return env->active_tc.gpr[n] = tmp, sizeof(target_ulong); -+ } else if (n == 32) { -+ return env->active_tc.PC = tmp, sizeof(target_ulong); -+ } -+ return 0; -+} -+ -+static int loongarch_gdb_get_fpu(CPULOONGARCHState *env, GByteArray *mem_buf, int n) -+{ -+ if (0 <= n && n < 32) { -+ return gdb_get_reg64(mem_buf, env->active_fpu.fpr[n].d); -+ } else if (32 <= n && n < 40) { -+ return gdb_get_reg8(mem_buf, env->active_fpu.cf[n - 32]); -+ } else if (n == 40) { -+ return gdb_get_reg32(mem_buf, env->active_fpu.fcsr0); -+ } -+ return 0; -+} -+ -+static int loongarch_gdb_set_fpu(CPULOONGARCHState *env, uint8_t *mem_buf, int n) -+{ -+ if (0 <= n && n < 32) { -+ return env->active_fpu.fpr[n].d = ldq_p(mem_buf), 8; -+ } else if (32 <= n && n < 40) { -+ return env->active_fpu.cf[n - 32] = ldub_p(mem_buf), 1; -+ } else if (n == 40) { -+ return env->active_fpu.fcsr0 = ldl_p(mem_buf), 4; -+ } -+ return 0; -+} -+ -+void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs) -+{ -+ gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu, -+ 41, "loongarch-fpu64.xml", 0); -+} -+ -+#ifdef CONFIG_TCG -+int loongarch_read_qxfer(CPUState *cs, const char *annex, uint8_t *read_buf, -+ unsigned long offset, unsigned long len) -+{ -+ if (strncmp(annex, "cpucfg", sizeof("cpucfg") - 1) == 0) { -+ if (offset % 4 != 0 || len % 4 != 0) { -+ return 0; -+ } -+ -+ size_t i; -+ for (i = offset; i < offset + len; i += 4) -+ ((uint32_t *)read_buf)[(i - offset) / 4] = -+ helper_cpucfg(&(LOONGARCH_CPU(cs)->env), i / 4); -+ return 32 * 4; -+ } -+ return 0; -+} -+ -+int loongarch_write_qxfer(CPUState *cs, const char *annex, -+ const uint8_t *write_buf, unsigned long offset, -+ unsigned long len) -+{ -+ return 0; -+} -+#endif -diff --git a/target/loongarch64/helper.c b/target/loongarch64/helper.c -new file mode 100644 -index 000000000..841240e57 ---- /dev/null -+++ b/target/loongarch64/helper.c -@@ -0,0 +1,727 @@ -+/* -+ * LOONGARCH emulation helpers for qemu. -+ * -+ * Copyright (c) 2004-2005 Jocelyn Mayer -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 "cpu.h" -+#include "internal.h" -+#include "exec/exec-all.h" -+#include "exec/cpu_ldst.h" -+#include "exec/log.h" -+#include "hw/loongarch/cpudevs.h" -+ -+ -+#if !defined(CONFIG_USER_ONLY) -+ -+static int ls3a5k_map_address_tlb_entry( -+ CPULOONGARCHState *env, -+ hwaddr *physical, -+ int *prot, -+ target_ulong address, -+ int rw, -+ int access_type, -+ ls3a5k_tlb_t *tlb) -+{ -+ uint64_t mask = tlb->PageMask; -+ int n = !!(address & mask & ~(mask >> 1)); -+ uint32_t plv = env->CSR_CRMD & CSR_CRMD_PLV; -+ -+ /* Check access rights */ -+ if (!(n ? tlb->V1 : tlb->V0)) { -+ return TLBRET_INVALID; -+ } -+ -+ if (rw == MMU_INST_FETCH && (n ? tlb->XI1 : tlb->XI0)) { -+ return TLBRET_XI; -+ } -+ -+ if (rw == MMU_DATA_LOAD && (n ? tlb->RI1 : tlb->RI0)) { -+ return TLBRET_RI; -+ } -+ -+ if (plv > (n ? tlb->PLV1 : tlb->PLV0)) { -+ return TLBRET_PE; -+ } -+ -+ if (rw != MMU_DATA_STORE || (n ? tlb->WE1 : tlb->WE0)) { -+ /* PPN address -+ * 4 KB: [47:13] [12;0] -+ * 16 KB: [47:15] [14:0] -+ */ -+ if (n) { -+ *physical = tlb->PPN1 | (address & (mask >> 1)); -+ } else { -+ *physical = tlb->PPN0 | (address & (mask >> 1)); -+ } -+ *prot = PAGE_READ; -+ if (n ? tlb->WE1 : tlb->WE0) { -+ *prot |= PAGE_WRITE; -+ } -+ if (!(n ? tlb->XI1 : tlb->XI0)) { -+ *prot |= PAGE_EXEC; -+ } -+ return TLBRET_MATCH; -+ } -+ -+ return TLBRET_DIRTY; -+} -+ -+/* Loongarch 3A5K -style MMU emulation */ -+int ls3a5k_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type) -+{ -+ uint16_t asid = env->CSR_ASID & 0x3ff; -+ int i; -+ ls3a5k_tlb_t *tlb; -+ -+ int ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ int vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; -+ -+ int ftlb_idx; -+ -+ uint64_t mask; -+ uint64_t vpn; /* address to map */ -+ uint64_t tag; /* address in TLB entry */ -+ -+ /* search VTLB */ -+ for (i = ftlb_size; i < ftlb_size + vtlb_size; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ mask = tlb->PageMask; -+ -+ vpn = address & 0xffffffffe000 & ~mask; -+ tag = tlb->VPN & ~mask; -+ -+ if ((tlb->G == 1 || tlb->ASID == asid) -+ && vpn == tag -+ && tlb->EHINV != 1) -+ { -+ return ls3a5k_map_address_tlb_entry(env, physical, prot, -+ address, rw, access_type, tlb); -+ } -+ } -+ -+ if (ftlb_size == 0) { -+ return TLBRET_NOMATCH; -+ } -+ -+ /* search FTLB */ -+ mask = env->tlb->mmu.ls3a5k.ftlb_mask; -+ vpn = address & 0xffffffffe000 & ~mask; -+ -+ ftlb_idx = (address & 0xffffffffc000) >> 15; /* 16 KB */ -+ ftlb_idx = ftlb_idx & 0xff; /* [0,255] */ -+ -+ for (i = 0; i < 8; ++i) { -+ /* ---------- set 0 1 2 ... 7 -+ * ftlb_idx ----------------------------------- -+ * 0 | 0 1 2 ... 7 -+ * 1 | 8 9 10 ... 15 -+ * 2 | 16 17 18 ... 23 -+ * ... | -+ * 255 | 2040 2041 2042 ... 2047 -+ */ -+ tlb = &env->tlb->mmu.ls3a5k.tlb[ftlb_idx * 8 + i]; -+ tag = tlb->VPN & ~mask; -+ -+ if ((tlb->G == 1 || tlb->ASID == asid) -+ && vpn == tag -+ && tlb->EHINV != 1) -+ { -+ return ls3a5k_map_address_tlb_entry(env, physical, prot, -+ address, rw, access_type, tlb); -+ } -+ } -+ -+ return TLBRET_NOMATCH; -+} -+ -+static int get_physical_address(CPULOONGARCHState *env, hwaddr *physical, -+ int *prot, target_ulong real_address, -+ int rw, int access_type, int mmu_idx) -+{ -+ int user_mode = mmu_idx == LARCH_HFLAG_UM; -+ int kernel_mode = !user_mode; -+ unsigned plv, base_c, base_v, tmp; -+ -+ /* effective address (modified for KVM T&E kernel segments) */ -+ target_ulong address = real_address; -+ -+ /* Check PG */ -+ if (!(env->CSR_CRMD & CSR_CRMD_PG)) { -+ /* DA mode */ -+ *physical = address & 0xffffffffffffUL; -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ -+ plv = kernel_mode | (user_mode << 3); -+ base_v = address >> CSR_DMW_BASE_SH; -+ /* Check direct map window 0 */ -+ base_c = env->CSR_DMWIN0 >> CSR_DMW_BASE_SH; -+ if ((plv & env->CSR_DMWIN0) && (base_c == base_v)) { -+ *physical = dmwin_va2pa(address); -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ /* Check direct map window 1 */ -+ base_c = env->CSR_DMWIN1 >> CSR_DMW_BASE_SH; -+ if ((plv & env->CSR_DMWIN1) && (base_c == base_v)) { -+ *physical = dmwin_va2pa(address); -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ /* Check valid extension */ -+ tmp = address >> 47; -+ if (!(tmp == 0 || tmp == 0x1ffff)) { -+ return TLBRET_BADADDR; -+ } -+ /* mapped address */ -+ return env->tlb->map_address(env, physical, prot, real_address, rw, -+ access_type); -+} -+ -+void cpu_loongarch_tlb_flush(CPULOONGARCHState *env) -+{ -+ LOONGARCHCPU *cpu = loongarch_env_get_cpu(env); -+ -+ /* Flush qemu's TLB and discard all shadowed entries. */ -+ tlb_flush(CPU(cpu)); -+ env->tlb->tlb_in_use = env->tlb->nb_tlb; -+} -+#endif -+ -+static void raise_mmu_exception(CPULOONGARCHState *env, target_ulong address, -+ int rw, int tlb_error) -+{ -+ CPUState *cs = CPU(loongarch_env_get_cpu(env)); -+ int exception = 0, error_code = 0; -+ -+ if (rw == MMU_INST_FETCH) { -+ error_code |= EXCP_INST_NOTAVAIL; -+ } -+ -+ switch (tlb_error) { -+ default: -+ case TLBRET_BADADDR: -+ /* Reference to kernel address from user mode or supervisor mode */ -+ /* Reference to supervisor address from user mode */ -+ if (rw == MMU_DATA_STORE) { -+ exception = EXCP_AdES; -+ } else { -+ exception = EXCP_AdEL; -+ } -+ break; -+ case TLBRET_NOMATCH: -+ /* No TLB match for a mapped address */ -+ if (rw == MMU_DATA_STORE) { -+ exception = EXCP_TLBS; -+ } else { -+ exception = EXCP_TLBL; -+ } -+ error_code |= EXCP_TLB_NOMATCH; -+ break; -+ case TLBRET_INVALID: -+ /* TLB match with no valid bit */ -+ if (rw == MMU_DATA_STORE) { -+ exception = EXCP_TLBS; -+ } else { -+ exception = EXCP_TLBL; -+ } -+ break; -+ case TLBRET_DIRTY: -+ /* TLB match but 'D' bit is cleared */ -+ exception = EXCP_LTLBL; -+ break; -+ case TLBRET_XI: -+ /* Execute-Inhibit Exception */ -+ exception = EXCP_TLBXI; -+ break; -+ case TLBRET_RI: -+ /* Read-Inhibit Exception */ -+ exception = EXCP_TLBRI; -+ break; -+ case TLBRET_PE: -+ /* Privileged Exception */ -+ exception = EXCP_TLBPE; -+ break; -+ } -+ -+ if (env->insn_flags & INSN_LOONGARCH) { -+ if (tlb_error == TLBRET_NOMATCH) { -+ env->CSR_TLBRBADV = address; -+ env->CSR_TLBREHI = address & (TARGET_PAGE_MASK << 1); -+ cs->exception_index = exception; -+ env->error_code = error_code; -+ return; -+ } -+ } -+ -+ /* Raise exception */ -+ env->CSR_BADV = address; -+ cs->exception_index = exception; -+ env->error_code = error_code; -+ -+ if (env->insn_flags & INSN_LOONGARCH) { -+ env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1); -+ } -+} -+ -+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, -+ MMUAccessType access_type, int mmu_idx, -+ bool probe, uintptr_t retaddr) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+#if !defined(CONFIG_USER_ONLY) -+ hwaddr physical; -+ int prot; -+ int loongarch_access_type; -+#endif -+ int ret = TLBRET_BADADDR; -+ -+ qemu_log_mask(CPU_LOG_MMU, -+ "%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " mmu_idx %d\n", -+ __func__, env->active_tc.PC, address, mmu_idx); -+ -+ /* data access */ -+#if !defined(CONFIG_USER_ONLY) -+ /* XXX: put correct access by using cpu_restore_state() correctly */ -+ loongarch_access_type = ACCESS_INT; -+ ret = get_physical_address(env, &physical, &prot, address, -+ access_type, loongarch_access_type, mmu_idx); -+ switch (ret) { -+ case TLBRET_MATCH: -+ qemu_log_mask(CPU_LOG_MMU, -+ "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx -+ " prot %d asid %ld pc 0x%lx\n", -+ __func__, address, physical, prot, -+ env->CSR_ASID, env->active_tc.PC); -+ break; -+ default: -+ qemu_log_mask(CPU_LOG_MMU, -+ "%s address=%" VADDR_PRIx " ret %d asid %ld pc 0x%lx\n", -+ __func__, address, ret, env->CSR_ASID, env->active_tc.PC); -+ break; -+ } -+ if (ret == TLBRET_MATCH) { -+ tlb_set_page(cs, address & TARGET_PAGE_MASK, -+ physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, -+ mmu_idx, TARGET_PAGE_SIZE); -+ ret = true; -+ } -+ if (probe) { -+ return false; -+ } -+#endif -+ -+ raise_mmu_exception(env, address, access_type, ret); -+ do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr); -+} -+ -+#if !defined(CONFIG_USER_ONLY) -+hwaddr cpu_loongarch_translate_address(CPULOONGARCHState *env, -+ target_ulong address, int rw) -+{ -+ hwaddr physical; -+ int prot; -+ int access_type; -+ int ret = 0; -+ -+ /* data access */ -+ access_type = ACCESS_INT; -+ ret = get_physical_address(env, &physical, &prot, address, rw, access_type, -+ cpu_mmu_index(env, false)); -+ if (ret != TLBRET_MATCH) { -+ raise_mmu_exception(env, address, rw, ret); -+ return -1LL; -+ } else { -+ return physical; -+ } -+} -+ -+static const char * const excp_names[EXCP_LAST + 1] = { -+ [EXCP_RESET] = "reset", -+ [EXCP_SRESET] = "soft reset", -+ [EXCP_NMI] = "non-maskable interrupt", -+ [EXCP_EXT_INTERRUPT] = "interrupt", -+ [EXCP_AdEL] = "address error load", -+ [EXCP_AdES] = "address error store", -+ [EXCP_TLBF] = "TLB refill", -+ [EXCP_IBE] = "instruction bus error", -+ [EXCP_SYSCALL] = "syscall", -+ [EXCP_BREAK] = "break", -+ [EXCP_FPDIS] = "float unit unusable", -+ [EXCP_LSXDIS] = "vector128 unusable", -+ [EXCP_LASXDIS] = "vector256 unusable", -+ [EXCP_RI] = "reserved instruction", -+ [EXCP_OVERFLOW] = "arithmetic overflow", -+ [EXCP_TRAP] = "trap", -+ [EXCP_FPE] = "floating point", -+ [EXCP_LTLBL] = "TLB modify", -+ [EXCP_TLBL] = "TLB load", -+ [EXCP_TLBS] = "TLB store", -+ [EXCP_DBE] = "data bus error", -+ [EXCP_TLBXI] = "TLB execute-inhibit", -+ [EXCP_TLBRI] = "TLB read-inhibit", -+ [EXCP_TLBPE] = "TLB priviledged error", -+}; -+#endif -+ -+target_ulong exception_resume_pc(CPULOONGARCHState *env) -+{ -+ target_ulong bad_pc; -+ -+ bad_pc = env->active_tc.PC; -+ if (env->hflags & LARCH_HFLAG_BMASK) { -+ /* If the exception was raised from a delay slot, come back to -+ the jump. */ -+ bad_pc -= 4; -+ } -+ -+ return bad_pc; -+} -+ -+#if !defined(CONFIG_USER_ONLY) -+static void set_hflags_for_handler (CPULOONGARCHState *env) -+{ -+ /* Exception handlers are entered in 32-bit mode. */ -+} -+ -+static inline void set_badinstr_registers(CPULOONGARCHState *env) -+{ -+ if ((env->insn_flags & INSN_LOONGARCH)) { -+ env->CSR_BADI = cpu_ldl_code(env, env->active_tc.PC); -+ return; -+ } -+} -+#endif -+ -+static inline unsigned int get_vint_size(CPULOONGARCHState *env) -+{ -+ unsigned int size = 0; -+ -+ switch ((env->CSR_ECFG >> 16) & 0x7) { -+ case 0: -+ break; -+ case 1: -+ size = 2 * 4; /* #Insts * inst_size */ -+ break; -+ case 2: -+ size = 4 * 4; -+ break; -+ case 3: -+ size = 8 * 4; -+ break; -+ case 4: -+ size = 16 * 4; -+ break; -+ case 5: -+ size = 32 * 4; -+ break; -+ case 6: -+ size = 64 * 4; -+ break; -+ case 7: -+ size = 128 * 4; -+ break; -+ default: -+ printf("%s: unexpected value", __func__); -+ assert(0); -+ } -+ -+ return size; -+} -+ -+#define is_refill(cs, env) (((cs->exception_index == EXCP_TLBL) \ -+ || (cs->exception_index == EXCP_TLBS)) \ -+ && (env->error_code & EXCP_TLB_NOMATCH)) -+ -+void loongarch_cpu_do_interrupt(CPUState *cs) -+{ -+#if !defined(CONFIG_USER_ONLY) -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ bool update_badinstr = 0; -+ int cause = -1; -+ const char *name; -+ -+ if (qemu_loglevel_mask(CPU_LOG_INT) -+ && cs->exception_index != EXCP_EXT_INTERRUPT) { -+ if (cs->exception_index < 0 || cs->exception_index > EXCP_LAST) { -+ name = "unknown"; -+ } else { -+ name = excp_names[cs->exception_index]; -+ } -+ -+ qemu_log("%s enter: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx -+ " TLBRERA 0x%016lx" " %s exception\n", __func__, -+ env->active_tc.PC, env->CSR_ERA, env->CSR_TLBRERA, name); -+ } -+ -+ switch (cs->exception_index) { -+ case EXCP_RESET: -+ cpu_reset(CPU(cpu)); -+ break; -+ case EXCP_NMI: -+ env->CSR_ERRERA = exception_resume_pc(env); -+ env->hflags &= ~LARCH_HFLAG_BMASK; -+ env->hflags |= LARCH_HFLAG_64; -+ env->hflags &= ~LARCH_HFLAG_AWRAP; -+ env->hflags &= ~(LARCH_HFLAG_KSU); -+ env->active_tc.PC = env->exception_base; -+ set_hflags_for_handler(env); -+ break; -+ case EXCP_EXT_INTERRUPT: -+ cause = 0; -+ goto set_ERA; -+ case EXCP_LTLBL: -+ cause = 1; -+ update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); -+ goto set_ERA; -+ case EXCP_TLBL: -+ cause = 2; -+ update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); -+ goto set_ERA; -+ case EXCP_TLBS: -+ cause = 3; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_AdEL: -+ cause = 4; -+ update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); -+ goto set_ERA; -+ case EXCP_AdES: -+ cause = 5; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_IBE: -+ cause = 6; -+ goto set_ERA; -+ case EXCP_DBE: -+ cause = 7; -+ goto set_ERA; -+ case EXCP_SYSCALL: -+ cause = 8; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_BREAK: -+ cause = 9; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_RI: -+ cause = 10; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_FPDIS: -+ case EXCP_LSXDIS: -+ case EXCP_LASXDIS: -+ cause = 11; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_OVERFLOW: -+ cause = 12; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_TRAP: -+ cause = 13; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_FPE: -+ cause = 15; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_TLBRI: -+ cause = 19; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_TLBXI: -+ case EXCP_TLBPE: -+ cause = 20; -+ goto set_ERA; -+ set_ERA: -+ if (is_refill(cs, env)) { -+ env->CSR_TLBRERA = exception_resume_pc(env); -+ env->CSR_TLBRERA |= 1; -+ } else { -+ env->CSR_ERA = exception_resume_pc(env); -+ } -+ -+ if (update_badinstr) { -+ set_badinstr_registers(env); -+ } -+ env->hflags &= ~(LARCH_HFLAG_KSU); -+ -+ env->hflags &= ~LARCH_HFLAG_BMASK; -+ if (env->insn_flags & INSN_LOONGARCH) { -+ /* save PLV and IE */ -+ if (is_refill(cs, env)) { -+ env->CSR_TLBRPRMD &= (~0x7); -+ env->CSR_TLBRPRMD |= (env->CSR_CRMD & 0x7); -+ } else { -+ env->CSR_PRMD &= (~0x7); -+ env->CSR_PRMD |= (env->CSR_CRMD & 0x7); -+ } -+ -+ env->CSR_CRMD &= ~(0x7); -+ -+ switch (cs->exception_index) { -+ case EXCP_EXT_INTERRUPT: -+ break; -+ case EXCP_TLBL: -+ if (env->error_code & EXCP_INST_NOTAVAIL) { -+ cause = EXCCODE_TLBI; -+ } else { -+ cause = EXCCODE_TLBL; -+ } -+ break; -+ case EXCP_TLBS: -+ cause = EXCCODE_TLBS; -+ break; -+ case EXCP_LTLBL: -+ cause = EXCCODE_MOD; -+ break; -+ case EXCP_TLBRI: -+ cause = EXCCODE_TLBRI; -+ break; -+ case EXCP_TLBXI: -+ cause = EXCCODE_TLBXI; -+ break; -+ case EXCP_TLBPE: -+ cause = EXCCODE_TLBPE; -+ break; -+ case EXCP_AdEL: -+ case EXCP_AdES: -+ case EXCP_IBE: -+ case EXCP_DBE: -+ cause = EXCCODE_ADE; -+ break; -+ case EXCP_SYSCALL: -+ cause = EXCCODE_SYS; -+ break; -+ case EXCP_BREAK: -+ cause = EXCCODE_BP; -+ break; -+ case EXCP_RI: -+ cause = EXCCODE_RI; -+ break; -+ case EXCP_FPDIS: -+ cause = EXCCODE_FPDIS; -+ break; -+ case EXCP_LSXDIS: -+ cause = EXCCODE_LSXDIS; -+ break; -+ case EXCP_LASXDIS: -+ cause = EXCCODE_LASXDIS; -+ break; -+ case EXCP_FPE: -+ cause = EXCCODE_FPE; -+ break; -+ default: -+ printf("Error: exception(%d) '%s' has not been supported\n", -+ cs->exception_index, excp_names[cs->exception_index]); -+ abort(); -+ } -+ -+ uint32_t vec_size = get_vint_size(env); -+ env->active_tc.PC = env->CSR_EEPN; -+ env->active_tc.PC += cause * vec_size; -+ if (is_refill(cs, env)) { -+ /* TLB Refill */ -+ env->active_tc.PC = env->CSR_TLBRENT; -+ break; /* Do not modify excode */ -+ } -+ if (cs->exception_index == EXCP_EXT_INTERRUPT) { -+ /* Interrupt */ -+ uint32_t vector = 0; -+ uint32_t pending = env->CSR_ESTAT & CSR_ESTAT_IPMASK; -+ pending &= env->CSR_ECFG & CSR_ECFG_IPMASK; -+ -+ /* Find the highest-priority interrupt. */ -+ while (pending >>= 1) { -+ vector++; -+ } -+ env->active_tc.PC = env->CSR_EEPN + -+ (EXCODE_IP + vector) * vec_size; -+ if (qemu_loglevel_mask(CPU_LOG_INT)) { -+ qemu_log("%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx -+ " cause %d\n" " A " TARGET_FMT_lx " D " -+ TARGET_FMT_lx " vector = %d ExC %08lx ExS %08lx\n", -+ __func__, env->active_tc.PC, env->CSR_ERA, -+ cause, env->CSR_BADV, env->CSR_DERA, vector, -+ env->CSR_ECFG, env->CSR_ESTAT); -+ } -+ } -+ /* Excode */ -+ env->CSR_ESTAT = (env->CSR_ESTAT & ~(0x1f << CSR_ESTAT_EXC_SH)) | -+ (cause << CSR_ESTAT_EXC_SH); -+ } -+ set_hflags_for_handler(env); -+ break; -+ default: -+ abort(); -+ } -+ if (qemu_loglevel_mask(CPU_LOG_INT) -+ && cs->exception_index != EXCP_EXT_INTERRUPT) { -+ qemu_log("%s: PC " TARGET_FMT_lx " ERA 0x%08lx" " cause %d%s\n" -+ " ESTAT %08lx EXCFG 0x%08lx BADVA 0x%08lx BADI 0x%08lx \ -+ SYS_NUM %lu cpu %d asid 0x%lx" "\n", -+ __func__, env->active_tc.PC, -+ is_refill(cs, env) ? env->CSR_TLBRERA : env->CSR_ERA, -+ cause, -+ is_refill(cs, env) ? "(refill)" : "", -+ env->CSR_ESTAT, env->CSR_ECFG, -+ is_refill(cs, env) ? env->CSR_TLBRBADV : env->CSR_BADV, -+ env->CSR_BADI, env->active_tc.gpr[11], cs->cpu_index, -+ env->CSR_ASID -+ ); -+ } -+#endif -+ cs->exception_index = EXCP_NONE; -+} -+ -+bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -+{ -+ if (interrupt_request & CPU_INTERRUPT_HARD) { -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ if (cpu_loongarch_hw_interrupts_enabled(env) && -+ cpu_loongarch_hw_interrupts_pending(env)) { -+ /* Raise it */ -+ cs->exception_index = EXCP_EXT_INTERRUPT; -+ env->error_code = 0; -+ loongarch_cpu_do_interrupt(cs); -+ return true; -+ } -+ } -+ return false; -+} -+ -+void QEMU_NORETURN do_raise_exception_err(CPULOONGARCHState *env, -+ uint32_t exception, -+ int error_code, -+ uintptr_t pc) -+{ -+ CPUState *cs = CPU(loongarch_env_get_cpu(env)); -+ -+ qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n", -+ __func__, exception, error_code); -+ cs->exception_index = exception; -+ env->error_code = error_code; -+ -+ cpu_loop_exit_restore(cs, pc); -+} -diff --git a/target/loongarch64/helper.h b/target/loongarch64/helper.h -new file mode 100644 -index 000000000..ff2026ed8 ---- /dev/null -+++ b/target/loongarch64/helper.h -@@ -0,0 +1,168 @@ -+DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) -+DEF_HELPER_2(raise_exception, noreturn, env, i32) -+DEF_HELPER_1(raise_exception_debug, noreturn, env) -+ -+#if 0 -+#ifndef CONFIG_USER_ONLY -+DEF_HELPER_3(ll, tl, env, tl, int) -+DEF_HELPER_3(lld, tl, env, tl, int) -+#endif -+#endif -+ -+DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) -+DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) -+ -+DEF_HELPER_3(crc32, tl, tl, tl, i32) -+DEF_HELPER_3(crc32c, tl, tl, tl, i32) -+ -+#ifndef CONFIG_USER_ONLY -+/* LoongISA CSR register */ -+DEF_HELPER_2(csr_rdq, tl, env, i64) -+DEF_HELPER_3(csr_wrq, tl, env, tl, i64) -+DEF_HELPER_4(csr_xchgq, tl, env, tl, tl, i64) -+ -+#endif /* !CONFIG_USER_ONLY */ -+ -+/* CP1 functions */ -+DEF_HELPER_2(movfcsr2gr, tl, env, i32) -+DEF_HELPER_4(movgr2fcsr, void, env, tl, i32, i32) -+ -+DEF_HELPER_2(float_cvtd_s, i64, env, i32) -+DEF_HELPER_2(float_cvtd_w, i64, env, i32) -+DEF_HELPER_2(float_cvtd_l, i64, env, i64) -+DEF_HELPER_2(float_cvts_d, i32, env, i64) -+DEF_HELPER_2(float_cvts_w, i32, env, i32) -+DEF_HELPER_2(float_cvts_l, i32, env, i64) -+ -+DEF_HELPER_FLAGS_2(float_class_s, TCG_CALL_NO_RWG_SE, i32, env, i32) -+DEF_HELPER_FLAGS_2(float_class_d, TCG_CALL_NO_RWG_SE, i64, env, i64) -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_4(float_ ## op ## _s, i32, env, i32, i32, i32) \ -+DEF_HELPER_4(float_ ## op ## _d, i64, env, i64, i64, i64) -+FOP_PROTO(maddf) -+FOP_PROTO(msubf) -+FOP_PROTO(nmaddf) -+FOP_PROTO(nmsubf) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \ -+DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64) -+FOP_PROTO(max) -+FOP_PROTO(maxa) -+FOP_PROTO(min) -+FOP_PROTO(mina) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_2(float_ ## op ## _l_s, i64, env, i32) \ -+DEF_HELPER_2(float_ ## op ## _l_d, i64, env, i64) \ -+DEF_HELPER_2(float_ ## op ## _w_s, i32, env, i32) \ -+DEF_HELPER_2(float_ ## op ## _w_d, i32, env, i64) -+FOP_PROTO(cvt) -+FOP_PROTO(round) -+FOP_PROTO(trunc) -+FOP_PROTO(ceil) -+FOP_PROTO(floor) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_2(float_ ## op ## _s, i32, env, i32) \ -+DEF_HELPER_2(float_ ## op ## _d, i64, env, i64) -+FOP_PROTO(sqrt) -+FOP_PROTO(rsqrt) -+FOP_PROTO(recip) -+FOP_PROTO(rint) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_1(float_ ## op ## _s, i32, i32) \ -+DEF_HELPER_1(float_ ## op ## _d, i64, i64) -+FOP_PROTO(abs) -+FOP_PROTO(chs) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \ -+DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64) -+FOP_PROTO(add) -+FOP_PROTO(sub) -+FOP_PROTO(mul) -+FOP_PROTO(div) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_3(cmp_d_ ## op, i64, env, i64, i64) \ -+DEF_HELPER_3(cmp_s_ ## op, i32, env, i32, i32) -+FOP_PROTO(af) -+FOP_PROTO(un) -+FOP_PROTO(eq) -+FOP_PROTO(ueq) -+FOP_PROTO(lt) -+FOP_PROTO(ult) -+FOP_PROTO(le) -+FOP_PROTO(ule) -+FOP_PROTO(saf) -+FOP_PROTO(sun) -+FOP_PROTO(seq) -+FOP_PROTO(sueq) -+FOP_PROTO(slt) -+FOP_PROTO(sult) -+FOP_PROTO(sle) -+FOP_PROTO(sule) -+FOP_PROTO(or) -+FOP_PROTO(une) -+FOP_PROTO(ne) -+FOP_PROTO(sor) -+FOP_PROTO(sune) -+FOP_PROTO(sne) -+#undef FOP_PROTO -+ -+/* Special functions */ -+#ifndef CONFIG_USER_ONLY -+DEF_HELPER_1(tlbwr, void, env) -+DEF_HELPER_1(tlbfill, void, env) -+DEF_HELPER_1(tlbsrch, void, env) -+DEF_HELPER_1(tlbrd, void, env) -+DEF_HELPER_1(tlbclr, void, env) -+DEF_HELPER_1(tlbflush, void, env) -+DEF_HELPER_4(invtlb, void, env, tl, tl, tl) -+DEF_HELPER_1(ertn, void, env) -+DEF_HELPER_5(lddir, void, env, tl, tl, tl, i32) -+DEF_HELPER_4(ldpte, void, env, tl, tl, i32) -+DEF_HELPER_3(drdtime, void, env, tl, tl) -+DEF_HELPER_1(read_pgd, tl, env) -+#endif /* !CONFIG_USER_ONLY */ -+DEF_HELPER_2(cpucfg, tl, env, tl) -+DEF_HELPER_1(idle, void, env) -+ -+DEF_HELPER_3(float_exp2_s, i32, env, i32, i32) -+DEF_HELPER_3(float_exp2_d, i64, env, i64, i64) -+DEF_HELPER_2(float_logb_s, i32, env, i32) -+DEF_HELPER_2(float_logb_d, i64, env, i64) -+DEF_HELPER_3(movreg2cf, void, env, i32, tl) -+DEF_HELPER_2(movcf2reg, tl, env, i32) -+DEF_HELPER_3(movreg2cf_i32, void, env, i32, i32) -+DEF_HELPER_3(movreg2cf_i64, void, env, i32, i64) -+ -+DEF_HELPER_2(cto_w, tl, env, tl) -+DEF_HELPER_2(ctz_w, tl, env, tl) -+DEF_HELPER_2(cto_d, tl, env, tl) -+DEF_HELPER_2(ctz_d, tl, env, tl) -+DEF_HELPER_2(bitrev_w, tl, env, tl) -+DEF_HELPER_2(bitrev_d, tl, env, tl) -+ -+DEF_HELPER_2(load_scr, i64, env, i32) -+DEF_HELPER_3(store_scr, void, env, i32, i64) -+ -+DEF_HELPER_3(asrtle_d, void, env, tl, tl) -+DEF_HELPER_3(asrtgt_d, void, env, tl, tl) -+ -+DEF_HELPER_4(fsel, i64, env, i64, i64, i32) -+ -+#ifndef CONFIG_USER_ONLY -+DEF_HELPER_4(iocsr, void, env, tl, tl, i32) -+#endif -+DEF_HELPER_3(memtrace_addr, void, env, tl, i32) -+DEF_HELPER_2(memtrace_val, void, env, tl) -diff --git a/target/loongarch64/insn.decode b/target/loongarch64/insn.decode -new file mode 100644 -index 000000000..f194f7011 ---- /dev/null -+++ b/target/loongarch64/insn.decode -@@ -0,0 +1,514 @@ -+# Fields -+%sd 0:2 -+%rj 5:5 -+%rd 0:5 -+%sj 5:2 -+%ptr 5:3 -+%rk 10:5 -+%sa2 15:2 -+%sa3 15:3 -+%si5 10:s5 -+%code 0:15 -+%cond 10:4 -+%cond2 0:4 -+%ui5 10:5 -+%ui6 10:6 -+%ui3 10:3 -+%ui4 10:4 -+%op 5:5 -+%ui8 10:8 -+%msbw 16:5 -+%lsbw 10:5 -+%msbd 16:6 -+%lsbd 10:6 -+%fd 0:5 -+%fj 5:5 -+%fk 10:5 -+%fcsrd 0:5 -+%fcsrs 5:5 -+%cd 0:3 -+%cj 5:3 -+%si12 10:s12 -+%ui12 10:12 -+%csr 10:14 -+%cop 0:5 -+%level 10:8 -+%seq 10:8 -+%whint 0:15 -+%addr 10:5 -+%info 5:5 -+%invop 0:5 -+%fa 15:5 -+%vd 0:5 -+%vj 5:5 -+%vk 10:5 -+%va 15:5 -+%xd 0:5 -+%xj 5:5 -+%xk 10:5 -+%xa 15:5 -+%fcond 15:5 -+%ca 15:3 -+%vui5 15:5 -+%si16 10:s16 -+%si20 5:s20 -+%si14 10:s14 -+%hint 0:5 -+%si9 10:s9 -+%si10 10:s10 -+%si11 10:s11 -+%si8 10:s8 -+%idx1 18:1 -+%idx2 18:2 -+%idx3 18:3 -+%idx4 18:4 -+%idx 18:5 -+%offs21 0:s5 10:16 -+%offs16 10:s16 -+%offs 0:s10 10:16 -+%mode 5:5 -+%ui2 10:2 -+%ui1 10:1 -+%ui7 10:7 -+%i13 5:13 -+ -+# Argument sets -+&fmt_sdrj sd rj -+&fmt_rdsj rd sj -+&fmt_rdrj rd rj -+&fmt_empty -+&fmt_rjrk rj rk -+&fmt_rdrjrksa2 rd rj rk sa2 -+&fmt_rdrjrksa3 rd rj rk sa3 -+&fmt_rdrjrk rd rj rk -+&fmt_code code -+&fmt_rdrjui5 rd rj ui5 -+&fmt_rdrjui6 rd rj ui6 -+&fmt_rdrjmsbwlsbw rd rj msbw lsbw -+&fmt_rdrjmsbdlsbd rd rj msbd lsbd -+&fmt_fdfjfk fd fj fk -+&fmt_fdfj fd fj -+&fmt_fdrj fd rj -+&fmt_rdfj rd fj -+&fmt_fcsrdrj fcsrd rj -+&fmt_rdfcsrs rd fcsrs -+&fmt_cdfj cd fj -+&fmt_fdcj fd cj -+&fmt_cdrj cd rj -+&fmt_rdcj rd cj -+&fmt_rdrjsi12 rd rj si12 -+&fmt_rdrjui12 rd rj ui12 -+&fmt_rdrjcsr rd rj csr -+&fmt_coprjsi12 cop rj si12 -+&fmt_rdrjlevel rd rj level -+&fmt_rjseq rj seq -+&fmt_whint whint -+&fmt_invtlb addr info invop -+&fmt_fdfjfkfa fd fj fk fa -+&fmt_cdfjfkfcond cd fj fk fcond -+&fmt_fdfjfkca fd fj fk ca -+&fmt_rdrjsi16 rd rj si16 -+&fmt_rdsi20 rd si20 -+&fmt_rdrjsi14 rd rj si14 -+&fmt_hintrjsi12 hint rj si12 -+&fmt_fdrjsi12 fd rj si12 -+&fmt_fdrjrk fd rj rk -+&fmt_rjoffs21 rj offs21 -+&fmt_cjoffs21 cj offs21 -+&fmt_rdrjoffs16 rd rj offs16 -+&fmt_offs offs -+&fmt_rjrdoffs16 rj rd offs16 -+ -+# Formats -+@fmt_sdrj .... ........ ..... ..... ..... ... .. &fmt_sdrj %sd %rj -+@fmt_rdsj .... ........ ..... ..... ... .. ..... &fmt_rdsj %rd %sj -+@fmt_rdrj .... ........ ..... ..... ..... ..... &fmt_rdrj %rd %rj -+@fmt_empty .... ........ ..... ..... ..... ..... &fmt_empty -+@fmt_rjrk .... ........ ..... ..... ..... ..... &fmt_rjrk %rj %rk -+@fmt_rdrjrksa2 .... ........ ... .. ..... ..... ..... &fmt_rdrjrksa2 %rd %rj %rk %sa2 -+@fmt_rdrjrksa3 .... ........ .. ... ..... ..... ..... &fmt_rdrjrksa3 %rd %rj %rk %sa3 -+@fmt_rdrjrk .... ........ ..... ..... ..... ..... &fmt_rdrjrk %rd %rj %rk -+@fmt_code .... ........ ..... ............... &fmt_code %code -+@fmt_rdrjui5 .... ........ ..... ..... ..... ..... &fmt_rdrjui5 %rd %rj %ui5 -+@fmt_rdrjui6 .... ........ .... ...... ..... ..... &fmt_rdrjui6 %rd %rj %ui6 -+@fmt_rdrjmsbwlsbw .... ....... ..... . ..... ..... ..... &fmt_rdrjmsbwlsbw %rd %rj %msbw %lsbw -+@fmt_rdrjmsbdlsbd .... ...... ...... ...... ..... ..... &fmt_rdrjmsbdlsbd %rd %rj %msbd %lsbd -+@fmt_fdfjfk .... ........ ..... ..... ..... ..... &fmt_fdfjfk %fd %fj %fk -+@fmt_fdfj .... ........ ..... ..... ..... ..... &fmt_fdfj %fd %fj -+@fmt_fdrj .... ........ ..... ..... ..... ..... &fmt_fdrj %fd %rj -+@fmt_rdfj .... ........ ..... ..... ..... ..... &fmt_rdfj %rd %fj -+@fmt_fcsrdrj .... ........ ..... ..... ..... ..... &fmt_fcsrdrj %fcsrd %rj -+@fmt_rdfcsrs .... ........ ..... ..... ..... ..... &fmt_rdfcsrs %rd %fcsrs -+@fmt_cdfj .... ........ ..... ..... ..... .. ... &fmt_cdfj %cd %fj -+@fmt_fdcj .... ........ ..... ..... .. ... ..... &fmt_fdcj %fd %cj -+@fmt_cdrj .... ........ ..... ..... ..... .. ... &fmt_cdrj %cd %rj -+@fmt_rdcj .... ........ ..... ..... .. ... ..... &fmt_rdcj %rd %cj -+@fmt_rdrjsi12 .... ...... ............ ..... ..... &fmt_rdrjsi12 %rd %rj %si12 -+@fmt_rdrjui12 .... ...... ............ ..... ..... &fmt_rdrjui12 %rd %rj %ui12 -+@fmt_rdrjcsr .... .... .............. ..... ..... &fmt_rdrjcsr %rd %rj %csr -+@fmt_coprjsi12 .... ...... ............ ..... ..... &fmt_coprjsi12 %cop %rj %si12 -+@fmt_rdrjlevel .... ........ .. ........ ..... ..... &fmt_rdrjlevel %rd %rj %level -+@fmt_rjseq .... ........ .. ........ ..... ..... &fmt_rjseq %rj %seq -+@fmt_whint .... ........ ..... ............... &fmt_whint %whint -+@fmt_invtlb ...... ...... ..... ..... ..... ..... &fmt_invtlb %addr %info %invop -+@fmt_fdfjfkfa .... ........ ..... ..... ..... ..... &fmt_fdfjfkfa %fd %fj %fk %fa -+@fmt_cdfjfkfcond .... ........ ..... ..... ..... .. ... &fmt_cdfjfkfcond %cd %fj %fk %fcond -+@fmt_fdfjfkca .... ........ .. ... ..... ..... ..... &fmt_fdfjfkca %fd %fj %fk %ca -+@fmt_rdrjsi16 .... .. ................ ..... ..... &fmt_rdrjsi16 %rd %rj %si16 -+@fmt_rdsi20 .... ... .................... ..... &fmt_rdsi20 %rd %si20 -+@fmt_rdrjsi14 .... .... .............. ..... ..... &fmt_rdrjsi14 %rd %rj %si14 -+@fmt_hintrjsi12 .... ...... ............ ..... ..... &fmt_hintrjsi12 %hint %rj %si12 -+@fmt_fdrjsi12 .... ...... ............ ..... ..... &fmt_fdrjsi12 %fd %rj %si12 -+@fmt_fdrjrk .... ........ ..... ..... ..... ..... &fmt_fdrjrk %fd %rj %rk -+@fmt_rjoffs21 .... .. ................ ..... ..... &fmt_rjoffs21 %rj %offs21 -+@fmt_cjoffs21 .... .. ................ .. ... ..... &fmt_cjoffs21 %cj %offs21 -+@fmt_rdrjoffs16 .... .. ................ ..... ..... &fmt_rdrjoffs16 %rd %rj %offs16 -+@fmt_offs .... .. .......................... &fmt_offs %offs -+@fmt_rjrdoffs16 .... .. ................ ..... ..... &fmt_rjrdoffs16 %rj %rd %offs16 -+ -+# Instructions -+ -+# Fiexd point arithmetic Instructions -+gr2scr 0000 00000000 00000 00010 ..... 000 .. @fmt_sdrj -+scr2gr 0000 00000000 00000 00011 000 .. ..... @fmt_rdsj -+clo_w 0000 00000000 00000 00100 ..... ..... @fmt_rdrj -+clz_w 0000 00000000 00000 00101 ..... ..... @fmt_rdrj -+cto_w 0000 00000000 00000 00110 ..... ..... @fmt_rdrj -+ctz_w 0000 00000000 00000 00111 ..... ..... @fmt_rdrj -+clo_d 0000 00000000 00000 01000 ..... ..... @fmt_rdrj -+clz_d 0000 00000000 00000 01001 ..... ..... @fmt_rdrj -+cto_d 0000 00000000 00000 01010 ..... ..... @fmt_rdrj -+ctz_d 0000 00000000 00000 01011 ..... ..... @fmt_rdrj -+revb_2h 0000 00000000 00000 01100 ..... ..... @fmt_rdrj -+revb_4h 0000 00000000 00000 01101 ..... ..... @fmt_rdrj -+revb_2w 0000 00000000 00000 01110 ..... ..... @fmt_rdrj -+revb_d 0000 00000000 00000 01111 ..... ..... @fmt_rdrj -+revh_2w 0000 00000000 00000 10000 ..... ..... @fmt_rdrj -+revh_d 0000 00000000 00000 10001 ..... ..... @fmt_rdrj -+bitrev_4b 0000 00000000 00000 10010 ..... ..... @fmt_rdrj -+bitrev_8b 0000 00000000 00000 10011 ..... ..... @fmt_rdrj -+bitrev_w 0000 00000000 00000 10100 ..... ..... @fmt_rdrj -+bitrev_d 0000 00000000 00000 10101 ..... ..... @fmt_rdrj -+ext_w_h 0000 00000000 00000 10110 ..... ..... @fmt_rdrj -+ext_w_b 0000 00000000 00000 10111 ..... ..... @fmt_rdrj -+rdtime_d 0000 00000000 00000 11010 ..... ..... @fmt_rdrj -+cpucfg 0000 00000000 00000 11011 ..... ..... @fmt_rdrj -+asrtle_d 0000 00000000 00010 ..... ..... 00000 @fmt_rjrk -+asrtgt_d 0000 00000000 00011 ..... ..... 00000 @fmt_rjrk -+alsl_w 0000 00000000 010 .. ..... ..... ..... @fmt_rdrjrksa2 -+alsl_wu 0000 00000000 011 .. ..... ..... ..... @fmt_rdrjrksa2 -+bytepick_w 0000 00000000 100 .. ..... ..... ..... @fmt_rdrjrksa2 -+bytepick_d 0000 00000000 11 ... ..... ..... ..... @fmt_rdrjrksa3 -+add_w 0000 00000001 00000 ..... ..... ..... @fmt_rdrjrk -+add_d 0000 00000001 00001 ..... ..... ..... @fmt_rdrjrk -+sub_w 0000 00000001 00010 ..... ..... ..... @fmt_rdrjrk -+sub_d 0000 00000001 00011 ..... ..... ..... @fmt_rdrjrk -+slt 0000 00000001 00100 ..... ..... ..... @fmt_rdrjrk -+sltu 0000 00000001 00101 ..... ..... ..... @fmt_rdrjrk -+maskeqz 0000 00000001 00110 ..... ..... ..... @fmt_rdrjrk -+masknez 0000 00000001 00111 ..... ..... ..... @fmt_rdrjrk -+nor 0000 00000001 01000 ..... ..... ..... @fmt_rdrjrk -+and 0000 00000001 01001 ..... ..... ..... @fmt_rdrjrk -+or 0000 00000001 01010 ..... ..... ..... @fmt_rdrjrk -+xor 0000 00000001 01011 ..... ..... ..... @fmt_rdrjrk -+orn 0000 00000001 01100 ..... ..... ..... @fmt_rdrjrk -+andn 0000 00000001 01101 ..... ..... ..... @fmt_rdrjrk -+sll_w 0000 00000001 01110 ..... ..... ..... @fmt_rdrjrk -+srl_w 0000 00000001 01111 ..... ..... ..... @fmt_rdrjrk -+sra_w 0000 00000001 10000 ..... ..... ..... @fmt_rdrjrk -+sll_d 0000 00000001 10001 ..... ..... ..... @fmt_rdrjrk -+srl_d 0000 00000001 10010 ..... ..... ..... @fmt_rdrjrk -+sra_d 0000 00000001 10011 ..... ..... ..... @fmt_rdrjrk -+rotr_w 0000 00000001 10110 ..... ..... ..... @fmt_rdrjrk -+rotr_d 0000 00000001 10111 ..... ..... ..... @fmt_rdrjrk -+mul_w 0000 00000001 11000 ..... ..... ..... @fmt_rdrjrk -+mulh_w 0000 00000001 11001 ..... ..... ..... @fmt_rdrjrk -+mulh_wu 0000 00000001 11010 ..... ..... ..... @fmt_rdrjrk -+mul_d 0000 00000001 11011 ..... ..... ..... @fmt_rdrjrk -+mulh_d 0000 00000001 11100 ..... ..... ..... @fmt_rdrjrk -+mulh_du 0000 00000001 11101 ..... ..... ..... @fmt_rdrjrk -+mulw_d_w 0000 00000001 11110 ..... ..... ..... @fmt_rdrjrk -+mulw_d_wu 0000 00000001 11111 ..... ..... ..... @fmt_rdrjrk -+div_w 0000 00000010 00000 ..... ..... ..... @fmt_rdrjrk -+mod_w 0000 00000010 00001 ..... ..... ..... @fmt_rdrjrk -+div_wu 0000 00000010 00010 ..... ..... ..... @fmt_rdrjrk -+mod_wu 0000 00000010 00011 ..... ..... ..... @fmt_rdrjrk -+div_d 0000 00000010 00100 ..... ..... ..... @fmt_rdrjrk -+mod_d 0000 00000010 00101 ..... ..... ..... @fmt_rdrjrk -+div_du 0000 00000010 00110 ..... ..... ..... @fmt_rdrjrk -+mod_du 0000 00000010 00111 ..... ..... ..... @fmt_rdrjrk -+crc_w_b_w 0000 00000010 01000 ..... ..... ..... @fmt_rdrjrk -+crc_w_h_w 0000 00000010 01001 ..... ..... ..... @fmt_rdrjrk -+crc_w_w_w 0000 00000010 01010 ..... ..... ..... @fmt_rdrjrk -+crc_w_d_w 0000 00000010 01011 ..... ..... ..... @fmt_rdrjrk -+crcc_w_b_w 0000 00000010 01100 ..... ..... ..... @fmt_rdrjrk -+crcc_w_h_w 0000 00000010 01101 ..... ..... ..... @fmt_rdrjrk -+crcc_w_w_w 0000 00000010 01110 ..... ..... ..... @fmt_rdrjrk -+crcc_w_d_w 0000 00000010 01111 ..... ..... ..... @fmt_rdrjrk -+break 0000 00000010 10100 ............... @fmt_code -+dbcl 0000 00000010 10101 ............... @fmt_code -+syscall 0000 00000010 10110 ............... @fmt_code -+alsl_d 0000 00000010 110 .. ..... ..... ..... @fmt_rdrjrksa2 -+slli_w 0000 00000100 00001 ..... ..... ..... @fmt_rdrjui5 -+slli_d 0000 00000100 0001 ...... ..... ..... @fmt_rdrjui6 -+srli_w 0000 00000100 01001 ..... ..... ..... @fmt_rdrjui5 -+srli_d 0000 00000100 0101 ...... ..... ..... @fmt_rdrjui6 -+srai_w 0000 00000100 10001 ..... ..... ..... @fmt_rdrjui5 -+srai_d 0000 00000100 1001 ...... ..... ..... @fmt_rdrjui6 -+rotri_w 0000 00000100 11001 ..... ..... ..... @fmt_rdrjui5 -+rotri_d 0000 00000100 1101 ...... ..... ..... @fmt_rdrjui6 -+bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @fmt_rdrjmsbwlsbw -+bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @fmt_rdrjmsbwlsbw -+bstrins_d 0000 000010 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd -+bstrpick_d 0000 000011 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd -+ -+# float Instructions -+fadd_s 0000 00010000 00001 ..... ..... ..... @fmt_fdfjfk -+fadd_d 0000 00010000 00010 ..... ..... ..... @fmt_fdfjfk -+fsub_s 0000 00010000 00101 ..... ..... ..... @fmt_fdfjfk -+fsub_d 0000 00010000 00110 ..... ..... ..... @fmt_fdfjfk -+fmul_s 0000 00010000 01001 ..... ..... ..... @fmt_fdfjfk -+fmul_d 0000 00010000 01010 ..... ..... ..... @fmt_fdfjfk -+fdiv_s 0000 00010000 01101 ..... ..... ..... @fmt_fdfjfk -+fdiv_d 0000 00010000 01110 ..... ..... ..... @fmt_fdfjfk -+fmax_s 0000 00010000 10001 ..... ..... ..... @fmt_fdfjfk -+fmax_d 0000 00010000 10010 ..... ..... ..... @fmt_fdfjfk -+fmin_s 0000 00010000 10101 ..... ..... ..... @fmt_fdfjfk -+fmin_d 0000 00010000 10110 ..... ..... ..... @fmt_fdfjfk -+fmaxa_s 0000 00010000 11001 ..... ..... ..... @fmt_fdfjfk -+fmaxa_d 0000 00010000 11010 ..... ..... ..... @fmt_fdfjfk -+fmina_s 0000 00010000 11101 ..... ..... ..... @fmt_fdfjfk -+fmina_d 0000 00010000 11110 ..... ..... ..... @fmt_fdfjfk -+fscaleb_s 0000 00010001 00001 ..... ..... ..... @fmt_fdfjfk -+fscaleb_d 0000 00010001 00010 ..... ..... ..... @fmt_fdfjfk -+fcopysign_s 0000 00010001 00101 ..... ..... ..... @fmt_fdfjfk -+fcopysign_d 0000 00010001 00110 ..... ..... ..... @fmt_fdfjfk -+fabs_s 0000 00010001 01000 00001 ..... ..... @fmt_fdfj -+fabs_d 0000 00010001 01000 00010 ..... ..... @fmt_fdfj -+fneg_s 0000 00010001 01000 00101 ..... ..... @fmt_fdfj -+fneg_d 0000 00010001 01000 00110 ..... ..... @fmt_fdfj -+flogb_s 0000 00010001 01000 01001 ..... ..... @fmt_fdfj -+flogb_d 0000 00010001 01000 01010 ..... ..... @fmt_fdfj -+fclass_s 0000 00010001 01000 01101 ..... ..... @fmt_fdfj -+fclass_d 0000 00010001 01000 01110 ..... ..... @fmt_fdfj -+fsqrt_s 0000 00010001 01000 10001 ..... ..... @fmt_fdfj -+fsqrt_d 0000 00010001 01000 10010 ..... ..... @fmt_fdfj -+frecip_s 0000 00010001 01000 10101 ..... ..... @fmt_fdfj -+frecip_d 0000 00010001 01000 10110 ..... ..... @fmt_fdfj -+frsqrt_s 0000 00010001 01000 11001 ..... ..... @fmt_fdfj -+frsqrt_d 0000 00010001 01000 11010 ..... ..... @fmt_fdfj -+fmov_s 0000 00010001 01001 00101 ..... ..... @fmt_fdfj -+fmov_d 0000 00010001 01001 00110 ..... ..... @fmt_fdfj -+movgr2fr_w 0000 00010001 01001 01001 ..... ..... @fmt_fdrj -+movgr2fr_d 0000 00010001 01001 01010 ..... ..... @fmt_fdrj -+movgr2frh_w 0000 00010001 01001 01011 ..... ..... @fmt_fdrj -+movfr2gr_s 0000 00010001 01001 01101 ..... ..... @fmt_rdfj -+movfr2gr_d 0000 00010001 01001 01110 ..... ..... @fmt_rdfj -+movfrh2gr_s 0000 00010001 01001 01111 ..... ..... @fmt_rdfj -+movgr2fcsr 0000 00010001 01001 10000 ..... ..... @fmt_fcsrdrj -+movfcsr2gr 0000 00010001 01001 10010 ..... ..... @fmt_rdfcsrs -+movfr2cf 0000 00010001 01001 10100 ..... 00 ... @fmt_cdfj -+movcf2fr 0000 00010001 01001 10101 00 ... ..... @fmt_fdcj -+movgr2cf 0000 00010001 01001 10110 ..... 00 ... @fmt_cdrj -+movcf2gr 0000 00010001 01001 10111 00 ... ..... @fmt_rdcj -+fcvt_s_d 0000 00010001 10010 00110 ..... ..... @fmt_fdfj -+fcvt_d_s 0000 00010001 10010 01001 ..... ..... @fmt_fdfj -+ftintrm_w_s 0000 00010001 10100 00001 ..... ..... @fmt_fdfj -+ftintrm_w_d 0000 00010001 10100 00010 ..... ..... @fmt_fdfj -+ftintrm_l_s 0000 00010001 10100 01001 ..... ..... @fmt_fdfj -+ftintrm_l_d 0000 00010001 10100 01010 ..... ..... @fmt_fdfj -+ftintrp_w_s 0000 00010001 10100 10001 ..... ..... @fmt_fdfj -+ftintrp_w_d 0000 00010001 10100 10010 ..... ..... @fmt_fdfj -+ftintrp_l_s 0000 00010001 10100 11001 ..... ..... @fmt_fdfj -+ftintrp_l_d 0000 00010001 10100 11010 ..... ..... @fmt_fdfj -+ftintrz_w_s 0000 00010001 10101 00001 ..... ..... @fmt_fdfj -+ftintrz_w_d 0000 00010001 10101 00010 ..... ..... @fmt_fdfj -+ftintrz_l_s 0000 00010001 10101 01001 ..... ..... @fmt_fdfj -+ftintrz_l_d 0000 00010001 10101 01010 ..... ..... @fmt_fdfj -+ftintrne_w_s 0000 00010001 10101 10001 ..... ..... @fmt_fdfj -+ftintrne_w_d 0000 00010001 10101 10010 ..... ..... @fmt_fdfj -+ftintrne_l_s 0000 00010001 10101 11001 ..... ..... @fmt_fdfj -+ftintrne_l_d 0000 00010001 10101 11010 ..... ..... @fmt_fdfj -+ftint_w_s 0000 00010001 10110 00001 ..... ..... @fmt_fdfj -+ftint_w_d 0000 00010001 10110 00010 ..... ..... @fmt_fdfj -+ftint_l_s 0000 00010001 10110 01001 ..... ..... @fmt_fdfj -+ftint_l_d 0000 00010001 10110 01010 ..... ..... @fmt_fdfj -+ffint_s_w 0000 00010001 11010 00100 ..... ..... @fmt_fdfj -+ffint_s_l 0000 00010001 11010 00110 ..... ..... @fmt_fdfj -+ffint_d_w 0000 00010001 11010 01000 ..... ..... @fmt_fdfj -+ffint_d_l 0000 00010001 11010 01010 ..... ..... @fmt_fdfj -+frint_s 0000 00010001 11100 10001 ..... ..... @fmt_fdfj -+frint_d 0000 00010001 11100 10010 ..... ..... @fmt_fdfj -+ -+# 12 bit immediate Instructions -+slti 0000 001000 ............ ..... ..... @fmt_rdrjsi12 -+sltui 0000 001001 ............ ..... ..... @fmt_rdrjsi12 -+addi_w 0000 001010 ............ ..... ..... @fmt_rdrjsi12 -+addi_d 0000 001011 ............ ..... ..... @fmt_rdrjsi12 -+lu52i_d 0000 001100 ............ ..... ..... @fmt_rdrjsi12 -+andi 0000 001101 ............ ..... ..... @fmt_rdrjui12 -+ori 0000 001110 ............ ..... ..... @fmt_rdrjui12 -+xori 0000 001111 ............ ..... ..... @fmt_rdrjui12 -+ -+# core Instructions -+csrxchg 0000 0100 .............. ..... ..... @fmt_rdrjcsr -+cacop 0000 011000 ............ ..... ..... @fmt_coprjsi12 -+lddir 0000 01100100 00 ........ ..... ..... @fmt_rdrjlevel -+ldpte 0000 01100100 01 ........ ..... 00000 @fmt_rjseq -+iocsrrd_b 0000 01100100 10000 00000 ..... ..... @fmt_rdrj -+iocsrrd_h 0000 01100100 10000 00001 ..... ..... @fmt_rdrj -+iocsrrd_w 0000 01100100 10000 00010 ..... ..... @fmt_rdrj -+iocsrrd_d 0000 01100100 10000 00011 ..... ..... @fmt_rdrj -+iocsrwr_b 0000 01100100 10000 00100 ..... ..... @fmt_rdrj -+iocsrwr_h 0000 01100100 10000 00101 ..... ..... @fmt_rdrj -+iocsrwr_w 0000 01100100 10000 00110 ..... ..... @fmt_rdrj -+iocsrwr_d 0000 01100100 10000 00111 ..... ..... @fmt_rdrj -+tlbclr 0000 01100100 10000 01000 00000 00000 @fmt_empty -+tlbflush 0000 01100100 10000 01001 00000 00000 @fmt_empty -+tlbsrch 0000 01100100 10000 01010 00000 00000 @fmt_empty -+tlbrd 0000 01100100 10000 01011 00000 00000 @fmt_empty -+tlbwr 0000 01100100 10000 01100 00000 00000 @fmt_empty -+tlbfill 0000 01100100 10000 01101 00000 00000 @fmt_empty -+ertn 0000 01100100 10000 01110 00000 00000 @fmt_empty -+idle 0000 01100100 10001 ............... @fmt_whint -+invtlb 0000 01100100 10011 ..... ..... ..... @fmt_invtlb -+ -+# foure Op Instructions -+fmadd_s 0000 10000001 ..... ..... ..... ..... @fmt_fdfjfkfa -+fmadd_d 0000 10000010 ..... ..... ..... ..... @fmt_fdfjfkfa -+fmsub_s 0000 10000101 ..... ..... ..... ..... @fmt_fdfjfkfa -+fmsub_d 0000 10000110 ..... ..... ..... ..... @fmt_fdfjfkfa -+fnmadd_s 0000 10001001 ..... ..... ..... ..... @fmt_fdfjfkfa -+fnmadd_d 0000 10001010 ..... ..... ..... ..... @fmt_fdfjfkfa -+fnmsub_s 0000 10001101 ..... ..... ..... ..... @fmt_fdfjfkfa -+fnmsub_d 0000 10001110 ..... ..... ..... ..... @fmt_fdfjfkfa -+fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @fmt_cdfjfkfcond -+fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @fmt_cdfjfkfcond -+fsel 0000 11010000 00 ... ..... ..... ..... @fmt_fdfjfkca -+ -+# loog immediate Instructions -+addu16i_d 0001 00 ................ ..... ..... @fmt_rdrjsi16 -+lu12i_w 0001 010 .................... ..... @fmt_rdsi20 -+lu32i_d 0001 011 .................... ..... @fmt_rdsi20 -+pcaddi 0001 100 .................... ..... @fmt_rdsi20 -+pcalau12i 0001 101 .................... ..... @fmt_rdsi20 -+pcaddu12i 0001 110 .................... ..... @fmt_rdsi20 -+pcaddu18i 0001 111 .................... ..... @fmt_rdsi20 -+ -+# load/store Instructions -+ll_w 0010 0000 .............. ..... ..... @fmt_rdrjsi14 -+sc_w 0010 0001 .............. ..... ..... @fmt_rdrjsi14 -+ll_d 0010 0010 .............. ..... ..... @fmt_rdrjsi14 -+sc_d 0010 0011 .............. ..... ..... @fmt_rdrjsi14 -+ldptr_w 0010 0100 .............. ..... ..... @fmt_rdrjsi14 -+stptr_w 0010 0101 .............. ..... ..... @fmt_rdrjsi14 -+ldptr_d 0010 0110 .............. ..... ..... @fmt_rdrjsi14 -+stptr_d 0010 0111 .............. ..... ..... @fmt_rdrjsi14 -+ld_b 0010 100000 ............ ..... ..... @fmt_rdrjsi12 -+ld_h 0010 100001 ............ ..... ..... @fmt_rdrjsi12 -+ld_w 0010 100010 ............ ..... ..... @fmt_rdrjsi12 -+ld_d 0010 100011 ............ ..... ..... @fmt_rdrjsi12 -+st_b 0010 100100 ............ ..... ..... @fmt_rdrjsi12 -+st_h 0010 100101 ............ ..... ..... @fmt_rdrjsi12 -+st_w 0010 100110 ............ ..... ..... @fmt_rdrjsi12 -+st_d 0010 100111 ............ ..... ..... @fmt_rdrjsi12 -+ld_bu 0010 101000 ............ ..... ..... @fmt_rdrjsi12 -+ld_hu 0010 101001 ............ ..... ..... @fmt_rdrjsi12 -+ld_wu 0010 101010 ............ ..... ..... @fmt_rdrjsi12 -+preld 0010 101011 ............ ..... ..... @fmt_hintrjsi12 -+fld_s 0010 101100 ............ ..... ..... @fmt_fdrjsi12 -+fst_s 0010 101101 ............ ..... ..... @fmt_fdrjsi12 -+fld_d 0010 101110 ............ ..... ..... @fmt_fdrjsi12 -+fst_d 0010 101111 ............ ..... ..... @fmt_fdrjsi12 -+ldx_b 0011 10000000 00000 ..... ..... ..... @fmt_rdrjrk -+ldx_h 0011 10000000 01000 ..... ..... ..... @fmt_rdrjrk -+ldx_w 0011 10000000 10000 ..... ..... ..... @fmt_rdrjrk -+ldx_d 0011 10000000 11000 ..... ..... ..... @fmt_rdrjrk -+stx_b 0011 10000001 00000 ..... ..... ..... @fmt_rdrjrk -+stx_h 0011 10000001 01000 ..... ..... ..... @fmt_rdrjrk -+stx_w 0011 10000001 10000 ..... ..... ..... @fmt_rdrjrk -+stx_d 0011 10000001 11000 ..... ..... ..... @fmt_rdrjrk -+ldx_bu 0011 10000010 00000 ..... ..... ..... @fmt_rdrjrk -+ldx_hu 0011 10000010 01000 ..... ..... ..... @fmt_rdrjrk -+ldx_wu 0011 10000010 10000 ..... ..... ..... @fmt_rdrjrk -+fldx_s 0011 10000011 00000 ..... ..... ..... @fmt_fdrjrk -+fldx_d 0011 10000011 01000 ..... ..... ..... @fmt_fdrjrk -+fstx_s 0011 10000011 10000 ..... ..... ..... @fmt_fdrjrk -+fstx_d 0011 10000011 11000 ..... ..... ..... @fmt_fdrjrk -+amswap_w 0011 10000110 00000 ..... ..... ..... @fmt_rdrjrk -+amswap_d 0011 10000110 00001 ..... ..... ..... @fmt_rdrjrk -+amadd_w 0011 10000110 00010 ..... ..... ..... @fmt_rdrjrk -+amadd_d 0011 10000110 00011 ..... ..... ..... @fmt_rdrjrk -+amand_w 0011 10000110 00100 ..... ..... ..... @fmt_rdrjrk -+amand_d 0011 10000110 00101 ..... ..... ..... @fmt_rdrjrk -+amor_w 0011 10000110 00110 ..... ..... ..... @fmt_rdrjrk -+amor_d 0011 10000110 00111 ..... ..... ..... @fmt_rdrjrk -+amxor_w 0011 10000110 01000 ..... ..... ..... @fmt_rdrjrk -+amxor_d 0011 10000110 01001 ..... ..... ..... @fmt_rdrjrk -+ammax_w 0011 10000110 01010 ..... ..... ..... @fmt_rdrjrk -+ammax_d 0011 10000110 01011 ..... ..... ..... @fmt_rdrjrk -+ammin_w 0011 10000110 01100 ..... ..... ..... @fmt_rdrjrk -+ammin_d 0011 10000110 01101 ..... ..... ..... @fmt_rdrjrk -+ammax_wu 0011 10000110 01110 ..... ..... ..... @fmt_rdrjrk -+ammax_du 0011 10000110 01111 ..... ..... ..... @fmt_rdrjrk -+ammin_wu 0011 10000110 10000 ..... ..... ..... @fmt_rdrjrk -+ammin_du 0011 10000110 10001 ..... ..... ..... @fmt_rdrjrk -+amswap_db_w 0011 10000110 10010 ..... ..... ..... @fmt_rdrjrk -+amswap_db_d 0011 10000110 10011 ..... ..... ..... @fmt_rdrjrk -+amadd_db_w 0011 10000110 10100 ..... ..... ..... @fmt_rdrjrk -+amadd_db_d 0011 10000110 10101 ..... ..... ..... @fmt_rdrjrk -+amand_db_w 0011 10000110 10110 ..... ..... ..... @fmt_rdrjrk -+amand_db_d 0011 10000110 10111 ..... ..... ..... @fmt_rdrjrk -+amor_db_w 0011 10000110 11000 ..... ..... ..... @fmt_rdrjrk -+amor_db_d 0011 10000110 11001 ..... ..... ..... @fmt_rdrjrk -+amxor_db_w 0011 10000110 11010 ..... ..... ..... @fmt_rdrjrk -+amxor_db_d 0011 10000110 11011 ..... ..... ..... @fmt_rdrjrk -+ammax_db_w 0011 10000110 11100 ..... ..... ..... @fmt_rdrjrk -+ammax_db_d 0011 10000110 11101 ..... ..... ..... @fmt_rdrjrk -+ammin_db_w 0011 10000110 11110 ..... ..... ..... @fmt_rdrjrk -+ammin_db_d 0011 10000110 11111 ..... ..... ..... @fmt_rdrjrk -+ammax_db_wu 0011 10000111 00000 ..... ..... ..... @fmt_rdrjrk -+ammax_db_du 0011 10000111 00001 ..... ..... ..... @fmt_rdrjrk -+ammin_db_wu 0011 10000111 00010 ..... ..... ..... @fmt_rdrjrk -+ammin_db_du 0011 10000111 00011 ..... ..... ..... @fmt_rdrjrk -+dbar 0011 10000111 00100 ............... @fmt_whint -+ibar 0011 10000111 00101 ............... @fmt_whint -+fldgt_s 0011 10000111 01000 ..... ..... ..... @fmt_fdrjrk -+fldgt_d 0011 10000111 01001 ..... ..... ..... @fmt_fdrjrk -+fldle_s 0011 10000111 01010 ..... ..... ..... @fmt_fdrjrk -+fldle_d 0011 10000111 01011 ..... ..... ..... @fmt_fdrjrk -+fstgt_s 0011 10000111 01100 ..... ..... ..... @fmt_fdrjrk -+fstgt_d 0011 10000111 01101 ..... ..... ..... @fmt_fdrjrk -+fstle_s 0011 10000111 01110 ..... ..... ..... @fmt_fdrjrk -+fstle_d 0011 10000111 01111 ..... ..... ..... @fmt_fdrjrk -+ldgt_b 0011 10000111 10000 ..... ..... ..... @fmt_rdrjrk -+ldgt_h 0011 10000111 10001 ..... ..... ..... @fmt_rdrjrk -+ldgt_w 0011 10000111 10010 ..... ..... ..... @fmt_rdrjrk -+ldgt_d 0011 10000111 10011 ..... ..... ..... @fmt_rdrjrk -+ldle_b 0011 10000111 10100 ..... ..... ..... @fmt_rdrjrk -+ldle_h 0011 10000111 10101 ..... ..... ..... @fmt_rdrjrk -+ldle_w 0011 10000111 10110 ..... ..... ..... @fmt_rdrjrk -+ldle_d 0011 10000111 10111 ..... ..... ..... @fmt_rdrjrk -+stgt_b 0011 10000111 11000 ..... ..... ..... @fmt_rdrjrk -+stgt_h 0011 10000111 11001 ..... ..... ..... @fmt_rdrjrk -+stgt_w 0011 10000111 11010 ..... ..... ..... @fmt_rdrjrk -+stgt_d 0011 10000111 11011 ..... ..... ..... @fmt_rdrjrk -+stle_b 0011 10000111 11100 ..... ..... ..... @fmt_rdrjrk -+stle_h 0011 10000111 11101 ..... ..... ..... @fmt_rdrjrk -+stle_w 0011 10000111 11110 ..... ..... ..... @fmt_rdrjrk -+stle_d 0011 10000111 11111 ..... ..... ..... @fmt_rdrjrk -+ -+# jump Instructions -+beqz 0100 00 ................ ..... ..... @fmt_rjoffs21 -+bnez 0100 01 ................ ..... ..... @fmt_rjoffs21 -+bceqz 0100 10 ................ 00 ... ..... @fmt_cjoffs21 -+bcnez 0100 10 ................ 01 ... ..... @fmt_cjoffs21 -+jirl 0100 11 ................ ..... ..... @fmt_rdrjoffs16 -+b 0101 00 .......................... @fmt_offs -+bl 0101 01 .......................... @fmt_offs -+beq 0101 10 ................ ..... ..... @fmt_rjrdoffs16 -+bne 0101 11 ................ ..... ..... @fmt_rjrdoffs16 -+blt 0110 00 ................ ..... ..... @fmt_rjrdoffs16 -+bge 0110 01 ................ ..... ..... @fmt_rjrdoffs16 -+bltu 0110 10 ................ ..... ..... @fmt_rjrdoffs16 -+bgeu 0110 11 ................ ..... ..... @fmt_rjrdoffs16 -diff --git a/target/loongarch64/instmap.h b/target/loongarch64/instmap.h -new file mode 100644 -index 000000000..6e85847f8 ---- /dev/null -+++ b/target/loongarch64/instmap.h -@@ -0,0 +1,216 @@ -+/* -+ * Loongarch emulation for qemu: instruction opcode -+ * -+ * Copyright (c) 2020-2021 -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program. If not, see . -+ */ -+ -+#ifndef TARGET_LARCH_INSTMAP_H -+#define TARGET_LARCH_INSTMAP_H -+ -+enum { -+ /* fix opcodes */ -+ OPC_LARCH_CLO_W = (0x000004 << 10), -+ OPC_LARCH_CLZ_W = (0x000005 << 10), -+ OPC_LARCH_CLO_D = (0x000008 << 10), -+ OPC_LARCH_CLZ_D = (0x000009 << 10), -+ OPC_LARCH_REVB_2H = (0x00000C << 10), -+ OPC_LARCH_REVB_4H = (0x00000D << 10), -+ OPC_LARCH_REVH_D = (0x000011 << 10), -+ OPC_LARCH_BREV_4B = (0x000012 << 10), -+ OPC_LARCH_BREV_8B = (0x000013 << 10), -+ OPC_LARCH_EXT_WH = (0x000016 << 10), -+ OPC_LARCH_EXT_WB = (0x000017 << 10), -+ -+ OPC_LARCH_ADD_W = (0x00020 << 15), -+ OPC_LARCH_ADD_D = (0x00021 << 15), -+ OPC_LARCH_SUB_W = (0x00022 << 15), -+ OPC_LARCH_SUB_D = (0x00023 << 15), -+ OPC_LARCH_SLT = (0x00024 << 15), -+ OPC_LARCH_SLTU = (0x00025 << 15), -+ OPC_LARCH_MASKEQZ = (0x00026 << 15), -+ OPC_LARCH_MASKNEZ = (0x00027 << 15), -+ OPC_LARCH_NOR = (0x00028 << 15), -+ OPC_LARCH_AND = (0x00029 << 15), -+ OPC_LARCH_OR = (0x0002A << 15), -+ OPC_LARCH_XOR = (0x0002B << 15), -+ OPC_LARCH_SLL_W = (0x0002E << 15), -+ OPC_LARCH_SRL_W = (0x0002F << 15), -+ OPC_LARCH_SRA_W = (0x00030 << 15), -+ OPC_LARCH_SLL_D = (0x00031 << 15), -+ OPC_LARCH_SRL_D = (0x00032 << 15), -+ OPC_LARCH_SRA_D = (0x00033 << 15), -+ OPC_LARCH_ROTR_W = (0x00036 << 15), -+ OPC_LARCH_ROTR_D = (0x00037 << 15), -+ OPC_LARCH_MUL_W = (0x00038 << 15), -+ OPC_LARCH_MULH_W = (0x00039 << 15), -+ OPC_LARCH_MULH_WU = (0x0003A << 15), -+ OPC_LARCH_MUL_D = (0x0003B << 15), -+ OPC_LARCH_MULH_D = (0x0003C << 15), -+ OPC_LARCH_MULH_DU = (0x0003D << 15), -+ OPC_LARCH_DIV_W = (0x00040 << 15), -+ OPC_LARCH_MOD_W = (0x00041 << 15), -+ OPC_LARCH_DIV_WU = (0x00042 << 15), -+ OPC_LARCH_MOD_WU = (0x00043 << 15), -+ OPC_LARCH_DIV_D = (0x00044 << 15), -+ OPC_LARCH_MOD_D = (0x00045 << 15), -+ OPC_LARCH_DIV_DU = (0x00046 << 15), -+ OPC_LARCH_MOD_DU = (0x00047 << 15), -+ OPC_LARCH_SRLI_W = (0x00089 << 15), -+ OPC_LARCH_SRAI_W = (0x00091 << 15), -+ OPC_LARCH_ROTRI_W = (0x00099 << 15), -+ -+ OPC_LARCH_ALSL_W = (0x0002 << 17), -+ OPC_LARCH_ALSL_D = (0x0016 << 17), -+ -+ OPC_LARCH_TRINS_W = (0x003 << 21) | (0x0 << 15), -+ OPC_LARCH_TRPICK_W = (0x003 << 21) | (0x1 << 15), -+}; -+ -+enum { -+ /* float opcodes */ -+ OPC_LARCH_FABS_S = (0x004501 << 10), -+ OPC_LARCH_FABS_D = (0x004502 << 10), -+ OPC_LARCH_FNEG_S = (0x004505 << 10), -+ OPC_LARCH_FNEG_D = (0x004506 << 10), -+ OPC_LARCH_FCLASS_S = (0x00450D << 10), -+ OPC_LARCH_FCLASS_D = (0x00450E << 10), -+ OPC_LARCH_FSQRT_S = (0x004511 << 10), -+ OPC_LARCH_FSQRT_D = (0x004512 << 10), -+ OPC_LARCH_FRECIP_S = (0x004515 << 10), -+ OPC_LARCH_FRECIP_D = (0x004516 << 10), -+ OPC_LARCH_FRSQRT_S = (0x004519 << 10), -+ OPC_LARCH_FRSQRT_D = (0x00451A << 10), -+ OPC_LARCH_FMOV_S = (0x004525 << 10), -+ OPC_LARCH_FMOV_D = (0x004526 << 10), -+ OPC_LARCH_GR2FR_W = (0x004529 << 10), -+ OPC_LARCH_GR2FR_D = (0x00452A << 10), -+ OPC_LARCH_GR2FRH_W = (0x00452B << 10), -+ OPC_LARCH_FR2GR_S = (0x00452D << 10), -+ OPC_LARCH_FR2GR_D = (0x00452E << 10), -+ OPC_LARCH_FRH2GR_S = (0x00452F << 10), -+ -+ OPC_LARCH_FCVT_S_D = (0x004646 << 10), -+ OPC_LARCH_FCVT_D_S = (0x004649 << 10), -+ OPC_LARCH_FTINTRM_W_S = (0x004681 << 10), -+ OPC_LARCH_FTINTRM_W_D = (0x004682 << 10), -+ OPC_LARCH_FTINTRM_L_S = (0x004689 << 10), -+ OPC_LARCH_FTINTRM_L_D = (0x00468A << 10), -+ OPC_LARCH_FTINTRP_W_S = (0x004691 << 10), -+ OPC_LARCH_FTINTRP_W_D = (0x004692 << 10), -+ OPC_LARCH_FTINTRP_L_S = (0x004699 << 10), -+ OPC_LARCH_FTINTRP_L_D = (0x00469A << 10), -+ OPC_LARCH_FTINTRZ_W_S = (0x0046A1 << 10), -+ OPC_LARCH_FTINTRZ_W_D = (0x0046A2 << 10), -+ OPC_LARCH_FTINTRZ_L_S = (0x0046A9 << 10), -+ OPC_LARCH_FTINTRZ_L_D = (0x0046AA << 10), -+ OPC_LARCH_FTINTRNE_W_S = (0x0046B1 << 10), -+ OPC_LARCH_FTINTRNE_W_D = (0x0046B2 << 10), -+ OPC_LARCH_FTINTRNE_L_S = (0x0046B9 << 10), -+ OPC_LARCH_FTINTRNE_L_D = (0x0046BA << 10), -+ OPC_LARCH_FTINT_W_S = (0x0046C1 << 10), -+ OPC_LARCH_FTINT_W_D = (0x0046C2 << 10), -+ OPC_LARCH_FTINT_L_S = (0x0046C9 << 10), -+ OPC_LARCH_FTINT_L_D = (0x0046CA << 10), -+ OPC_LARCH_FFINT_S_W = (0x004744 << 10), -+ OPC_LARCH_FFINT_S_L = (0x004746 << 10), -+ OPC_LARCH_FFINT_D_W = (0x004748 << 10), -+ OPC_LARCH_FFINT_D_L = (0x00474A << 10), -+ OPC_LARCH_FRINT_S = (0x004791 << 10), -+ OPC_LARCH_FRINT_D = (0x004792 << 10), -+ -+ OPC_LARCH_FADD_S = (0x00201 << 15), -+ OPC_LARCH_FADD_D = (0x00202 << 15), -+ OPC_LARCH_FSUB_S = (0x00205 << 15), -+ OPC_LARCH_FSUB_D = (0x00206 << 15), -+ OPC_LARCH_FMUL_S = (0x00209 << 15), -+ OPC_LARCH_FMUL_D = (0x0020A << 15), -+ OPC_LARCH_FDIV_S = (0x0020D << 15), -+ OPC_LARCH_FDIV_D = (0x0020E << 15), -+ OPC_LARCH_FMAX_S = (0x00211 << 15), -+ OPC_LARCH_FMAX_D = (0x00212 << 15), -+ OPC_LARCH_FMIN_S = (0x00215 << 15), -+ OPC_LARCH_FMIN_D = (0x00216 << 15), -+ OPC_LARCH_FMAXA_S = (0x00219 << 15), -+ OPC_LARCH_FMAXA_D = (0x0021A << 15), -+ OPC_LARCH_FMINA_S = (0x0021D << 15), -+ OPC_LARCH_FMINA_D = (0x0021E << 15), -+}; -+ -+enum { -+ /* 12 bit immediate opcodes */ -+ OPC_LARCH_SLTI = (0x008 << 22), -+ OPC_LARCH_SLTIU = (0x009 << 22), -+ OPC_LARCH_ADDI_W = (0x00A << 22), -+ OPC_LARCH_ADDI_D = (0x00B << 22), -+ OPC_LARCH_ANDI = (0x00D << 22), -+ OPC_LARCH_ORI = (0x00E << 22), -+ OPC_LARCH_XORI = (0x00F << 22), -+}; -+ -+enum { -+ /* load/store opcodes */ -+ OPC_LARCH_FLDX_S = (0x07060 << 15), -+ OPC_LARCH_FLDX_D = (0x07068 << 15), -+ OPC_LARCH_FSTX_S = (0x07070 << 15), -+ OPC_LARCH_FSTX_D = (0x07078 << 15), -+ OPC_LARCH_FLDGT_S = (0x070E8 << 15), -+ OPC_LARCH_FLDGT_D = (0x070E9 << 15), -+ OPC_LARCH_FLDLE_S = (0x070EA << 15), -+ OPC_LARCH_FLDLE_D = (0x070EB << 15), -+ OPC_LARCH_FSTGT_S = (0x070EC << 15), -+ OPC_LARCH_FSTGT_D = (0x070ED << 15), -+ OPC_LARCH_FSTLE_S = (0x070EE << 15), -+ OPC_LARCH_FSTLE_D = (0x070EF << 15), -+ -+ OPC_LARCH_LD_B = (0x0A0 << 22), -+ OPC_LARCH_LD_H = (0x0A1 << 22), -+ OPC_LARCH_LD_W = (0x0A2 << 22), -+ OPC_LARCH_LD_D = (0x0A3 << 22), -+ OPC_LARCH_ST_B = (0x0A4 << 22), -+ OPC_LARCH_ST_H = (0x0A5 << 22), -+ OPC_LARCH_ST_W = (0x0A6 << 22), -+ OPC_LARCH_ST_D = (0x0A7 << 22), -+ OPC_LARCH_LD_BU = (0x0A8 << 22), -+ OPC_LARCH_LD_HU = (0x0A9 << 22), -+ OPC_LARCH_LD_WU = (0x0AA << 22), -+ OPC_LARCH_FLD_S = (0x0AC << 22), -+ OPC_LARCH_FST_S = (0x0AD << 22), -+ OPC_LARCH_FLD_D = (0x0AE << 22), -+ OPC_LARCH_FST_D = (0x0AF << 22), -+ -+ OPC_LARCH_LL_W = (0x20 << 24), -+ OPC_LARCH_SC_W = (0x21 << 24), -+ OPC_LARCH_LL_D = (0x22 << 24), -+ OPC_LARCH_SC_D = (0x23 << 24), -+ OPC_LARCH_LDPTR_W = (0x24 << 24), -+ OPC_LARCH_STPTR_W = (0x25 << 24), -+ OPC_LARCH_LDPTR_D = (0x26 << 24), -+ OPC_LARCH_STPTR_D = (0x27 << 24), -+}; -+ -+enum { -+ /* jump opcodes */ -+ OPC_LARCH_BEQZ = (0x10 << 26), -+ OPC_LARCH_BNEZ = (0x11 << 26), -+ OPC_LARCH_B = (0x14 << 26), -+ OPC_LARCH_BEQ = (0x16 << 26), -+ OPC_LARCH_BNE = (0x17 << 26), -+ OPC_LARCH_BLT = (0x18 << 26), -+ OPC_LARCH_BGE = (0x19 << 26), -+ OPC_LARCH_BLTU = (0x1A << 26), -+ OPC_LARCH_BGEU = (0x1B << 26), -+}; -+ -+#endif -diff --git a/target/loongarch64/internal.h b/target/loongarch64/internal.h -new file mode 100644 -index 000000000..43594c5ac ---- /dev/null -+++ b/target/loongarch64/internal.h -@@ -0,0 +1,184 @@ -+#ifndef LOONGARCH_INTERNAL_H -+#define LOONGARCH_INTERNAL_H -+ -+#include "cpu-csr.h" -+ -+/* MMU types, the first four entries have the same layout as the -+ CP0C0_MT field. */ -+enum loongarch_mmu_types { -+ MMU_TYPE_NONE, -+ MMU_TYPE_LS3A5K, /* LISA CSR */ -+}; -+ -+ -+ -+struct loongarch_def_t { -+ const char *name; -+ int32_t CSR_PRid; -+ int32_t FCSR0; -+ int32_t FCSR0_rw_bitmask; -+ int32_t PABITS; -+ CPU_LOONGARCH_CSR -+ uint64_t insn_flags; -+ enum loongarch_mmu_types mmu_type; -+ int cpu_cfg[64]; -+}; -+ -+/* loongarch 3a5000 TLB entry */ -+struct ls3a5k_tlb_t { -+ target_ulong VPN; -+ uint64_t PageMask; /* CSR_TLBIDX[29:24] */ -+ uint32_t PageSize; -+ uint16_t ASID; -+ unsigned int G:1; /* CSR_TLBLO[6] */ -+ -+ unsigned int C0:3; /* CSR_TLBLO[5:4] */ -+ unsigned int C1:3; -+ -+ unsigned int V0:1; /* CSR_TLBLO[0] */ -+ unsigned int V1:1; -+ -+ unsigned int WE0:1; /* CSR_TLBLO[1] */ -+ unsigned int WE1:1; -+ -+ unsigned int XI0:1; /* CSR_TLBLO[62] */ -+ unsigned int XI1:1; -+ -+ unsigned int RI0:1; /* CSR_TLBLO[61] */ -+ unsigned int RI1:1; -+ -+ unsigned int EHINV:1;/* CSR_TLBIDX[31] */ -+ -+ unsigned int PLV0:2; /* CSR_TLBLO[3:2] */ -+ unsigned int PLV1:2; -+ -+ unsigned int RPLV0:1; -+ unsigned int RPLV1:1; /* CSR_TLBLO[63] */ -+ -+ uint64_t PPN0; /* CSR_TLBLO[47:12] */ -+ uint64_t PPN1; /* CSR_TLBLO[47:12] */ -+}; -+typedef struct ls3a5k_tlb_t ls3a5k_tlb_t; -+ -+ -+struct CPULOONGARCHTLBContext { -+ uint32_t nb_tlb; -+ uint32_t tlb_in_use; -+ int (*map_address)(struct CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type); -+ void (*helper_tlbwr)(struct CPULOONGARCHState *env); -+ void (*helper_tlbfill)(struct CPULOONGARCHState *env); -+ void (*helper_tlbsrch)(struct CPULOONGARCHState *env); -+ void (*helper_tlbrd)(struct CPULOONGARCHState *env); -+ void (*helper_tlbclr)(struct CPULOONGARCHState *env); -+ void (*helper_tlbflush)(struct CPULOONGARCHState *env); -+ void (*helper_invtlb)(struct CPULOONGARCHState *env, target_ulong addr, -+ target_ulong info, int op); -+ union { -+ struct { -+ uint64_t ftlb_mask; -+ uint32_t ftlb_size; /* at most : 8 * 256 = 2048 */ -+ uint32_t vtlb_size; /* at most : 64 */ -+ ls3a5k_tlb_t tlb[2048 + 64]; /* at most : 2048 FTLB + 64 VTLB */ -+ } ls3a5k; -+ } mmu; -+}; -+ -+enum { -+ TLBRET_PE = -7, -+ TLBRET_XI = -6, -+ TLBRET_RI = -5, -+ TLBRET_DIRTY = -4, -+ TLBRET_INVALID = -3, -+ TLBRET_NOMATCH = -2, -+ TLBRET_BADADDR = -1, -+ TLBRET_MATCH = 0 -+}; -+ -+ -+extern unsigned int ieee_rm[]; -+ -+static inline void restore_rounding_mode(CPULOONGARCHState *env) -+{ -+ set_float_rounding_mode(ieee_rm[(env->active_fpu.fcsr0 >> FCSR0_RM) & 0x3], -+ &env->active_fpu.fp_status); -+} -+ -+static inline void restore_flush_mode(CPULOONGARCHState *env) -+{ -+ set_flush_to_zero(0, &env->active_fpu.fp_status); -+} -+ -+static inline void restore_fp_status(CPULOONGARCHState *env) -+{ -+ restore_rounding_mode(env); -+ restore_flush_mode(env); -+} -+static inline void compute_hflags(CPULOONGARCHState *env) -+{ -+ env->hflags &= ~(LARCH_HFLAG_64 | LARCH_HFLAG_FPU | LARCH_HFLAG_KSU | -+ LARCH_HFLAG_AWRAP | LARCH_HFLAG_LSX | LARCH_HFLAG_LASX); -+ -+ env->hflags |= (env->CSR_CRMD & CSR_CRMD_PLV); -+ env->hflags |= LARCH_HFLAG_64; -+ -+ if (env->CSR_EUEN & CSR_EUEN_FPEN) { -+ env->hflags |= LARCH_HFLAG_FPU; -+ } -+ if (env->CSR_EUEN & CSR_EUEN_LSXEN) { -+ env->hflags |= LARCH_HFLAG_LSX; -+ } -+ if (env->CSR_EUEN & CSR_EUEN_LASXEN) { -+ env->hflags |= LARCH_HFLAG_LASX; -+ } -+ if (env->CSR_EUEN & CSR_EUEN_LBTEN) { -+ env->hflags |= LARCH_HFLAG_LBT; -+ } -+} -+ -+/* Check if there is pending and not masked out interrupt */ -+static inline bool cpu_loongarch_hw_interrupts_pending(CPULOONGARCHState *env) -+{ -+ int32_t pending; -+ int32_t status; -+ bool r; -+ -+ pending = env->CSR_ESTAT & CSR_ESTAT_IPMASK; -+ status = env->CSR_ECFG & CSR_ECFG_IPMASK; -+ -+ /* Configured with compatibility or VInt (Vectored Interrupts) -+ treats the pending lines as individual interrupt lines, the status -+ lines are individual masks. */ -+ r = (pending & status) != 0; -+ -+ return r; -+} -+ -+ -+/* stabletimer.c */ -+uint32_t cpu_loongarch_get_random_ls3a5k_tlb(uint32_t low, uint32_t high); -+uint64_t cpu_loongarch_get_stable_counter(CPULOONGARCHState *env); -+uint64_t cpu_loongarch_get_stable_timer_ticks(CPULOONGARCHState *env); -+void cpu_loongarch_store_stable_timer_config(CPULOONGARCHState *env, uint64_t value); -+int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, -+ int cpuid, DumpState *s); -+ -+void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -+ -+/* TODO QOM'ify CPU reset and remove */ -+void cpu_state_reset(CPULOONGARCHState *s); -+void cpu_loongarch_realize_env(CPULOONGARCHState *env); -+ -+int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); -+int loongarch_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -+ -+#ifdef CONFIG_TCG -+#include "fpu_helper.h" -+#endif -+ -+#ifndef CONFIG_USER_ONLY -+extern const struct VMStateDescription vmstate_loongarch_cpu; -+hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -+#endif -+ -+#endif -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -new file mode 100644 -index 000000000..404a605eb ---- /dev/null -+++ b/target/loongarch64/kvm.c -@@ -0,0 +1,1622 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * KVM/LOONGARCH: LOONGARCH specific KVM APIs -+ * -+ * Copyright (C) 2012-2014 Imagination Technologies Ltd. -+ * Authors: Sanjay Lal -+*/ -+ -+#include "qemu/osdep.h" -+#include -+ -+#include -+ -+#include "qemu-common.h" -+#include "cpu.h" -+#include "internal.h" -+#include "qemu/error-report.h" -+#include "qemu/timer.h" -+#include "qemu/main-loop.h" -+#include "sysemu/sysemu.h" -+#include "sysemu/kvm.h" -+#include "sysemu/runstate.h" -+#include "sysemu/cpus.h" -+#include "kvm_larch.h" -+#include "exec/memattrs.h" -+#include "exec/gdbstub.h" -+ -+#define DEBUG_KVM 0 -+/* A 16384-byte buffer can hold the 8-byte kvm_msrs header, plus -+ * 2047 kvm_msr_entry structs */ -+#define MSR_BUF_SIZE 16384 -+ -+#define DPRINTF(fmt, ...) \ -+ do { if (DEBUG_KVM) { fprintf(stderr, fmt, ## __VA_ARGS__); } } while (0) -+ -+/* -+ * Define loongarch kvm version. -+ * Add version number when -+ * qemu/kvm interface changed -+ */ -+#define KVM_LOONGARCH_VERSION 1 -+ -+static struct { -+ target_ulong addr; -+ int len; -+ int type; -+} inst_breakpoint[8], data_breakpoint[8]; -+ -+int nb_data_breakpoint = 0, nb_inst_breakpoint = 0; -+static int kvm_loongarch_version_cap; -+ -+/* Hardware breakpoint control register -+ * 4:1 plv0-plv3 enable -+ * 6:5 config virtualization mode -+ * 9:8 load store */ -+static const int type_code[] = { -+ [GDB_BREAKPOINT_HW] = 0x5e, -+ [GDB_WATCHPOINT_READ] = (0x5e | 1 << 8), -+ [GDB_WATCHPOINT_WRITE] = (0x5e | 1 << 9), -+ [GDB_WATCHPOINT_ACCESS] = (0x5e | 1 << 8 | 1 << 9) -+}; -+ -+const KVMCapabilityInfo kvm_arch_required_capabilities[] = { -+ KVM_CAP_LAST_INFO -+}; -+ -+static void kvm_loongarch_update_state(void *opaque, bool running, RunState state); -+static inline int kvm_larch_putq(CPUState *cs, uint64_t reg_id, uint64_t *addr); -+ -+unsigned long kvm_arch_vcpu_id(CPUState *cs) -+{ -+ return cs->cpu_index; -+} -+ -+int kvm_arch_init(MachineState *ms, KVMState *s) -+{ -+ /* LOONGARCH has 128 signals */ -+ kvm_set_sigmask_len(s, 16); -+ -+ kvm_loongarch_version_cap = kvm_check_extension(s, KVM_CAP_LOONGARCH_VZ); -+ -+ if (kvm_loongarch_version_cap != KVM_LOONGARCH_VERSION) { -+ warn_report("QEMU/KVM version not match, qemu_la_version: lvz-%d,\ -+ kvm_la_version: lvz-%d \n", -+ KVM_LOONGARCH_VERSION, kvm_loongarch_version_cap); -+ } -+ return 0; -+} -+ -+int kvm_arch_irqchip_create(KVMState *s) -+{ -+ return 0; -+} -+ -+int kvm_arch_init_vcpu(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ int ret = 0; -+ -+ cpu->cpuStateEntry = qemu_add_vm_change_state_handler(kvm_loongarch_update_state, cs); -+ cpu->kvm_msr_buf = g_malloc0(MSR_BUF_SIZE); -+ DPRINTF("%s\n", __func__); -+ return ret; -+} -+ -+int kvm_arch_destroy_vcpu(CPUState *cs) -+{ -+ return 0; -+} -+ -+static void kvm_msr_buf_reset(LOONGARCHCPU *cpu) -+{ -+ memset(cpu->kvm_msr_buf, 0, MSR_BUF_SIZE); -+} -+ -+static void kvm_msr_entry_add(LOONGARCHCPU *cpu, uint32_t index, uint64_t value) -+{ -+ struct kvm_msrs *msrs = cpu->kvm_msr_buf; -+ void *limit = ((void *)msrs) + MSR_BUF_SIZE; -+ struct kvm_csr_entry *entry = &msrs->entries[msrs->ncsrs]; -+ -+ assert((void *)(entry + 1) <= limit); -+ -+ entry->index = index; -+ entry->reserved = 0; -+ entry->data = value; -+ msrs->ncsrs++; -+} -+ -+void kvm_loongarch_reset_vcpu(LOONGARCHCPU *cpu) -+{ -+ int ret = 0; -+ uint64_t reset = 1; -+ -+ if (CPU(cpu)->kvm_fd > 0) { -+ ret = kvm_larch_putq(CPU(cpu), KVM_REG_LOONGARCH_VCPU_RESET, &reset); -+ if (ret < 0) { -+ error_report("%s reset vcpu failed:%d", __func__, ret); -+ } -+ } -+ -+ DPRINTF("%s\n", __func__); -+} -+ -+void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) -+{ -+ int n; -+ if (kvm_sw_breakpoints_active(cpu)) { -+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; -+ } -+ if (nb_data_breakpoint > 0) { -+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; -+ for (n = 0; n < nb_data_breakpoint; n++) { -+ dbg->arch.data_breakpoint[n].addr = data_breakpoint[n].addr; -+ dbg->arch.data_breakpoint[n].mask = 0; -+ dbg->arch.data_breakpoint[n].asid = 0; -+ dbg->arch.data_breakpoint[n].ctrl = type_code[data_breakpoint[n].type]; -+ } -+ dbg->arch.data_bp_nums = nb_data_breakpoint; -+ } else { -+ dbg->arch.data_bp_nums = 0; -+ } -+ if (nb_inst_breakpoint > 0) { -+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; -+ for (n = 0; n < nb_inst_breakpoint; n++) { -+ dbg->arch.inst_breakpoint[n].addr = inst_breakpoint[n].addr; -+ dbg->arch.inst_breakpoint[n].mask = 0; -+ dbg->arch.inst_breakpoint[n].asid = 0; -+ dbg->arch.inst_breakpoint[n].ctrl = type_code[inst_breakpoint[n].type]; -+ } -+ dbg->arch.inst_bp_nums = nb_inst_breakpoint; -+ } else { -+ dbg->arch.inst_bp_nums = 0; -+ } -+} -+ -+static const unsigned int brk_insn = 0x002b8005; -+ -+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) -+{ -+ DPRINTF("%s\n", __func__); -+ 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; -+ -+ DPRINTF("%s\n", __func__); -+ 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; -+} -+ -+static int find_hw_breakpoint(uint64_t addr, int len, int type) -+{ -+ int n; -+ switch (type) { -+ case GDB_BREAKPOINT_HW: -+ if (nb_inst_breakpoint == 0) { -+ return -1; -+ } -+ for (n = 0; n < nb_inst_breakpoint; n++) { -+ if (inst_breakpoint[n].addr == addr && inst_breakpoint[n].type == type) { -+ return n; -+ } -+ } -+ break; -+ case GDB_WATCHPOINT_WRITE: -+ case GDB_WATCHPOINT_READ: -+ case GDB_WATCHPOINT_ACCESS: -+ if (nb_data_breakpoint == 0) { -+ return -1; -+ } -+ for (n = 0; n < nb_data_breakpoint; n++) { -+ if (data_breakpoint[n].addr == addr && data_breakpoint[n].type == type && -+ data_breakpoint[n].len == len) { -+ return n; -+ } -+ } -+ break; -+ default: -+ return -1; -+ } -+ return -1; -+} -+ -+int kvm_arch_insert_hw_breakpoint(target_ulong addr, -+ target_ulong len, int type) -+{ -+ switch (type) { -+ case GDB_BREAKPOINT_HW: -+ len = 1; -+ if (nb_inst_breakpoint == 8) { -+ return -ENOBUFS; -+ } -+ if (find_hw_breakpoint(addr, len, type) >= 0) { -+ return -EEXIST; -+ } -+ inst_breakpoint[nb_inst_breakpoint].addr = addr; -+ inst_breakpoint[nb_inst_breakpoint].len = len; -+ inst_breakpoint[nb_inst_breakpoint].type = type; -+ nb_inst_breakpoint++; -+ break; -+ case GDB_WATCHPOINT_WRITE: -+ case GDB_WATCHPOINT_READ: -+ case GDB_WATCHPOINT_ACCESS: -+ switch (len) { -+ case 1: -+ case 2: -+ case 4: -+ case 8: -+ if (addr & (len - 1)) { -+ return -EINVAL; -+ } -+ if (nb_data_breakpoint == 8) { -+ return -ENOBUFS; -+ } -+ if (find_hw_breakpoint(addr, len, type) >= 0) { -+ return -EEXIST; -+ } -+ data_breakpoint[nb_data_breakpoint].addr = addr; -+ data_breakpoint[nb_data_breakpoint].len = len; -+ data_breakpoint[nb_data_breakpoint].type = type; -+ nb_data_breakpoint++; -+ break; -+ default: -+ return -EINVAL; -+ } -+ break; -+ default: -+ return -ENOSYS; -+ } -+ return 0; -+} -+ -+int kvm_arch_remove_hw_breakpoint(target_ulong addr, -+ target_ulong len, int type) -+{ -+ int n; -+ n = find_hw_breakpoint(addr, (type == GDB_BREAKPOINT_HW) ? 1 : len, type); -+ if (n < 0) { -+ printf("err not find remove target\n"); -+ return -ENOENT; -+ } -+ switch (type) { -+ case GDB_BREAKPOINT_HW: -+ nb_inst_breakpoint--; -+ inst_breakpoint[n] = inst_breakpoint[nb_inst_breakpoint]; -+ break; -+ case GDB_WATCHPOINT_WRITE: -+ case GDB_WATCHPOINT_READ: -+ case GDB_WATCHPOINT_ACCESS: -+ nb_data_breakpoint--; -+ data_breakpoint[n] = data_breakpoint[nb_data_breakpoint]; -+ break; -+ default: -+ return -1; -+ } -+ return 0; -+} -+ -+void kvm_arch_remove_all_hw_breakpoints(void) -+{ -+ DPRINTF("%s\n", __func__); -+ nb_data_breakpoint = 0; -+ nb_inst_breakpoint = 0; -+} -+ -+static inline int cpu_loongarch_io_interrupts_pending(LOONGARCHCPU *cpu) -+{ -+ CPULOONGARCHState *env = &cpu->env; -+ -+ return env->CSR_ESTAT & (0x1 << 2); -+} -+ -+void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ int r; -+ struct kvm_loongarch_interrupt intr; -+ -+ qemu_mutex_lock_iothread(); -+ -+ if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && -+ cpu_loongarch_io_interrupts_pending(cpu)) { -+ intr.cpu = -1; -+ intr.irq = 2; -+ r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); -+ if (r < 0) { -+ error_report("%s: cpu %d: failed to inject IRQ %x", -+ __func__, cs->cpu_index, intr.irq); -+ } -+ } -+ -+ qemu_mutex_unlock_iothread(); -+} -+ -+MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) -+{ -+ return MEMTXATTRS_UNSPECIFIED; -+} -+ -+int kvm_arch_process_async_events(CPUState *cs) -+{ -+ return cs->halted; -+} -+ -+static CPUWatchpoint hw_watchpoint; -+ -+static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int i; -+ bool ret = false; -+ kvm_cpu_synchronize_state(cs); -+ if (cs->singlestep_enabled) { -+ return true; -+ } -+ if (kvm_find_sw_breakpoint(cs, env->active_tc.PC)) { -+ return true; -+ } -+ /* hw breakpoint */ -+ if (run->debug.arch.exception == EXCCODE_WATCH) { -+ for (i = 0; i < 8; i++) { -+ if (run->debug.arch.fwps & (1 << i)) { -+ ret = true; -+ break; -+ } -+ } -+ for (i = 0; i < 8; i++) { -+ if (run->debug.arch.mwps & (1 << i)) { -+ cs->watchpoint_hit = &hw_watchpoint; -+ hw_watchpoint.vaddr = data_breakpoint[i].addr; -+ switch (data_breakpoint[i].type) { -+ case GDB_WATCHPOINT_READ: -+ ret = true; -+ hw_watchpoint.flags = BP_MEM_READ; -+ break; -+ case GDB_WATCHPOINT_WRITE: -+ ret = true; -+ hw_watchpoint.flags = BP_MEM_WRITE; -+ break; -+ case GDB_WATCHPOINT_ACCESS: -+ ret = true; -+ hw_watchpoint.flags = BP_MEM_ACCESS; -+ break; -+ } -+ } -+ } -+ run->debug.arch.exception = 0; -+ run->debug.arch.fwps = 0; -+ run->debug.arch.mwps = 0; -+ } -+ return ret; -+} -+ -+int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) -+{ -+ int ret; -+ -+ DPRINTF("%s\n", __func__); -+ switch (run->exit_reason) { -+ case KVM_EXIT_HYPERCALL: -+ DPRINTF("handle LOONGARCH hypercall\n"); -+ ret = 0; -+ run->hypercall.ret = ret; -+ break; -+ -+ case KVM_EXIT_DEBUG: -+ ret = 0; -+ if (kvm_loongarch_handle_debug(cs, run)) { -+ ret = EXCP_DEBUG; -+ } -+ break; -+ default: -+ error_report("%s: unknown exit reason %d", -+ __func__, run->exit_reason); -+ ret = -1; -+ break; -+ } -+ -+ return ret; -+} -+ -+bool kvm_arch_stop_on_emulation_error(CPUState *cs) -+{ -+ DPRINTF("%s\n", __func__); -+ return true; -+} -+/* -+#if 0 -+int kvmloongarch_load_kernel(CPUState *env, void *ram_base) -+{ -+ int ret; -+ -+ ret = kvm_vcpu_ioctl(env, KVM_LOAD_KERNEL, ram_base); -+ -+ return ret; -+} -+#endif -+*/ -+void kvm_arch_init_irq_routing(KVMState *s) -+{ -+} -+ -+int kvm_loongarch_set_interrupt(LOONGARCHCPU *cpu, int irq, int level) -+{ -+ CPUState *cs = CPU(cpu); -+ struct kvm_loongarch_interrupt intr; -+ -+ if (!kvm_enabled()) { -+ return 0; -+ } -+ -+ intr.cpu = -1; -+ -+ if (level) { -+ intr.irq = irq; -+ } else { -+ intr.irq = -irq; -+ } -+ -+ kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); -+ -+ return 0; -+} -+ -+int kvm_loongarch_set_ipi_interrupt(LOONGARCHCPU *cpu, int irq, int level) -+{ -+ CPUState *cs = current_cpu; -+ CPUState *dest_cs = CPU(cpu); -+ struct kvm_loongarch_interrupt intr; -+ -+ if (!kvm_enabled()) { -+ return 0; -+ } -+ -+ intr.cpu = dest_cs->cpu_index; -+ -+ if (level) { -+ intr.irq = irq; -+ } else { -+ intr.irq = -irq; -+ } -+ -+ DPRINTF("%s: IRQ: %d\n", __func__, intr.irq); -+ if (!current_cpu) { -+ cs = dest_cs; -+ } -+ kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); -+ -+ return 0; -+} -+ -+static inline int kvm_loongarch_put_one_reg(CPUState *cs, uint64_t reg_id, -+ int32_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_put_one_ureg(CPUState *cs, uint64_t reg_id, -+ uint32_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_put_one_ulreg(CPUState *cs, uint64_t reg_id, -+ target_ulong *addr) -+{ -+ uint64_t val64 = *addr; -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)&val64 -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_put_one_reg64(CPUState *cs, int64_t reg_id, -+ int64_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_larch_putq(CPUState *cs, uint64_t reg_id, -+ uint64_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_get_one_reg(CPUState *cs, uint64_t reg_id, -+ int32_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_get_one_ureg(CPUState *cs, uint64_t reg_id, -+ uint32_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_get_one_ulreg(CPUState *cs, uint64_t reg_id, -+ target_ulong *addr) -+{ -+ int ret; -+ uint64_t val64 = 0; -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)&val64 -+ }; -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+ if (ret >= 0) { -+ *addr = val64; -+ } -+ return ret; -+} -+ -+static inline int kvm_loongarch_get_one_reg64(CPUState *cs, int64_t reg_id, -+ int64_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_larch_getq(CPUState *cs, uint64_t reg_id, -+ uint64_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_change_one_reg(CPUState *cs, uint64_t reg_id, -+ int32_t *addr, int32_t mask) -+{ -+ int err; -+ int32_t tmp, change; -+ -+ err = kvm_loongarch_get_one_reg(cs, reg_id, &tmp); -+ if (err < 0) { -+ return err; -+ } -+ -+ /* only change bits in mask */ -+ change = (*addr ^ tmp) & mask; -+ if (!change) { -+ return 0; -+ } -+ -+ tmp = tmp ^ change; -+ return kvm_loongarch_put_one_reg(cs, reg_id, &tmp); -+} -+ -+static inline int kvm_loongarch_change_one_reg64(CPUState *cs, uint64_t reg_id, -+ int64_t *addr, int64_t mask) -+{ -+ int err; -+ int64_t tmp, change; -+ -+ err = kvm_loongarch_get_one_reg64(cs, reg_id, &tmp); -+ if (err < 0) { -+ DPRINTF("%s: Failed to get CSR_CONFIG7 (%d)\n", __func__, err); -+ return err; -+ } -+ -+ /* only change bits in mask */ -+ change = (*addr ^ tmp) & mask; -+ if (!change) { -+ return 0; -+ } -+ -+ tmp = tmp ^ change; -+ return kvm_loongarch_put_one_reg64(cs, reg_id, &tmp); -+} -+/* -+ * Handle the VM clock being started or stopped -+ */ -+static void kvm_loongarch_update_state(void *opaque, bool running, RunState state) -+{ -+ CPUState *cs = opaque; -+ int ret; -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ -+ /* -+ * If state is already dirty (synced to QEMU) then the KVM timer state is -+ * already saved and can be restored when it is synced back to KVM. -+ */ -+ if (!running) { -+ ret = kvm_larch_getq(cs, -+ KVM_REG_LOONGARCH_COUNTER, &cpu->counter_value); -+ if (ret < 0) { -+ printf("%s: Failed to get counter_value (%d)\n", __func__, ret); -+ } -+ -+ } else { -+ ret = kvm_larch_putq(cs, KVM_REG_LOONGARCH_COUNTER, -+ &(LOONGARCH_CPU(cs))->counter_value); -+ if (ret < 0) { -+ printf("%s: Failed to put counter_value (%d)\n", __func__, ret); -+ } -+ } -+} -+ -+static int kvm_loongarch_put_fpu_registers(CPUState *cs, int level) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int err, ret = 0; -+ unsigned int i; -+ struct kvm_fpu fpu; -+ -+ fpu.fcsr = env->active_fpu.fcsr0; -+ for (i = 0; i < 32; i++) { -+ memcpy(&fpu.fpr[i], &env->active_fpu.fpr[i], sizeof(struct kvm_fpureg)); -+ } -+ for (i = 0; i < 8; i++) { -+ ((char *)&fpu.fcc)[i] = env->active_fpu.cf[i]; -+ } -+ fpu.vcsr = env->active_fpu.vcsr16; -+ -+ err = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu); -+ if (err < 0) { -+ DPRINTF("%s: Failed to get FPU (%d)\n", __func__, err); -+ ret = err; -+ } -+ -+ return ret; -+} -+ -+static int kvm_loongarch_get_fpu_registers(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int err, ret = 0; -+ unsigned int i; -+ struct kvm_fpu fpu; -+ -+ err = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu); -+ if (err < 0) { -+ DPRINTF("%s: Failed to get FPU (%d)\n", __func__, err); -+ ret = err; -+ } else { -+ env->active_fpu.fcsr0 = fpu.fcsr; -+ for (i = 0; i < 32; i++) { -+ memcpy(&env->active_fpu.fpr[i], &fpu.fpr[i], sizeof(struct kvm_fpureg)); -+ } -+ for (i = 0; i < 8; i++) { -+ env->active_fpu.cf[i] = ((char *)&fpu.fcc)[i]; -+ } -+ env->active_fpu.vcsr16 = fpu.vcsr; -+ } -+ -+ return ret; -+} -+ -+#define KVM_PUT_ONE_UREG64(cs, regidx, addr) \ -+ ({ \ -+ int err; \ -+ uint64_t csrid = 0; \ -+ csrid = (KVM_IOC_CSRID(regidx)); \ -+ err = kvm_larch_putq(cs, csrid, addr); \ -+ if (err < 0) { \ -+ DPRINTF("%s: Failed to put regidx 0x%x err:%d\n", __func__, regidx, err); \ -+ } \ -+ err; \ -+ }) -+ -+ -+static int kvm_loongarch_put_csr_registers(CPUState *cs, int level) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int ret = 0; -+ -+ (void)level; -+ -+ kvm_msr_buf_reset(cpu); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CRMD, env->CSR_CRMD); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRMD, env->CSR_PRMD); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_EUEN, env->CSR_EUEN); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MISC, env->CSR_MISC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ECFG, env->CSR_ECFG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ESTAT, env->CSR_ESTAT); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERA, env->CSR_ERA); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADV, env->CSR_BADV); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADI, env->CSR_BADI); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_EEPN, env->CSR_EEPN); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, env->CSR_TLBIDX); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, env->CSR_TLBEHI); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, env->CSR_TLBELO0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, env->CSR_TLBELO1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GTLBC, env->CSR_GTLBC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TRGP, env->CSR_TRGP); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ASID, env->CSR_ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDL, env->CSR_PGDL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDH, env->CSR_PGDH); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGD, env->CSR_PGD); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, env->CSR_PWCTL0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, env->CSR_PWCTL1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, env->CSR_STLBPGSIZE); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_RVACFG, env->CSR_RVACFG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CPUID, env->CSR_CPUID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, env->CSR_PRCFG1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, env->CSR_PRCFG2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, env->CSR_PRCFG3); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS0, env->CSR_KS0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS1, env->CSR_KS1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS2, env->CSR_KS2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS3, env->CSR_KS3); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS4, env->CSR_KS4); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS5, env->CSR_KS5); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS6, env->CSR_KS6); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS7, env->CSR_KS7); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TMID, env->CSR_TMID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CNTC, env->CSR_CNTC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, env->CSR_TINTCLR); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GSTAT, env->CSR_GSTAT); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCFG, env->CSR_GCFG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GINTC, env->CSR_GINTC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCNTC, env->CSR_GCNTC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, env->CSR_LLBCTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, env->CSR_IMPCTL1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, env->CSR_IMPCTL2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GNMI, env->CSR_GNMI); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, env->CSR_TLBRENT); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, env->CSR_TLBRBADV); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, env->CSR_TLBRERA); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, env->CSR_TLBRSAVE); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, env->CSR_TLBRELO0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, env->CSR_TLBRELO1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, env->CSR_TLBREHI); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, env->CSR_TLBRPRMD); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, env->CSR_ERRCTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, env->CSR_ERRINFO); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, env->CSR_ERRINFO1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRENT, env->CSR_ERRENT); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRERA, env->CSR_ERRERA); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, env->CSR_ERRSAVE); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CTAG, env->CSR_CTAG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, env->CSR_DMWIN0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, env->CSR_DMWIN1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, env->CSR_DMWIN2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, env->CSR_DMWIN3); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, env->CSR_PERFCTRL0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, env->CSR_PERFCNTR0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, env->CSR_PERFCTRL1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, env->CSR_PERFCNTR1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, env->CSR_PERFCTRL2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, env->CSR_PERFCNTR2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, env->CSR_PERFCTRL3); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, env->CSR_PERFCNTR3); -+ -+ /* debug */ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPC, env->CSR_MWPC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPS, env->CSR_MWPS); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, env->CSR_DB0ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, env->CSR_DB0MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, env->CSR_DB0CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, env->CSR_DB0ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, env->CSR_DB1ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, env->CSR_DB1MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, env->CSR_DB1CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, env->CSR_DB1ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, env->CSR_DB2ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, env->CSR_DB2MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, env->CSR_DB2CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, env->CSR_DB2ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, env->CSR_DB3ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, env->CSR_DB3MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, env->CSR_DB3CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, env->CSR_DB3ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPC, env->CSR_FWPC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPS, env->CSR_FWPS); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, env->CSR_IB0ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, env->CSR_IB0MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, env->CSR_IB0CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, env->CSR_IB0ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, env->CSR_IB1ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, env->CSR_IB1MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, env->CSR_IB1CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, env->CSR_IB1ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, env->CSR_IB2ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, env->CSR_IB2MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, env->CSR_IB2CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, env->CSR_IB2ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, env->CSR_IB3ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, env->CSR_IB3MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, env->CSR_IB3CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, env->CSR_IB3ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, env->CSR_IB4ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, env->CSR_IB4MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, env->CSR_IB4CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, env->CSR_IB4ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, env->CSR_IB5ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, env->CSR_IB5MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, env->CSR_IB5CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, env->CSR_IB5ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, env->CSR_IB6ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, env->CSR_IB6MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, env->CSR_IB6CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, env->CSR_IB6ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, env->CSR_IB7ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, env->CSR_IB7MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, env->CSR_IB7CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, env->CSR_IB7ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DEBUG, env->CSR_DEBUG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DERA, env->CSR_DERA); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DESAVE, env->CSR_DESAVE); -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_SET_MSRS, cpu->kvm_msr_buf); -+ if (ret < cpu->kvm_msr_buf->ncsrs) { -+ struct kvm_csr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -+ printf("error: failed to set CSR 0x%" PRIx32 " to 0x%" PRIx64"\n", -+ (uint32_t)e->index, (uint64_t)e->data); -+ } -+ -+ /* -+ * timer cfg must be put at last since it is used to enable -+ * guest timer -+ */ -+ ret |= KVM_PUT_ONE_UREG64(cs, LOONGARCH_CSR_TVAL, &env->CSR_TVAL); -+ ret |= KVM_PUT_ONE_UREG64(cs, LOONGARCH_CSR_TCFG, &env->CSR_TCFG); -+ return ret; -+} -+ -+#define KVM_GET_ONE_UREG64(cs, regidx, addr) \ -+ ({ \ -+ int err; \ -+ uint64_t csrid = 0; \ -+ csrid = (KVM_IOC_CSRID(regidx)); \ -+ err = kvm_larch_getq(cs, csrid, addr); \ -+ if (err < 0) { \ -+ DPRINTF("%s: Failed to put regidx 0x%x err:%d\n", __func__, regidx, err); \ -+ } \ -+ err; \ -+ }) -+ -+static int kvm_loongarch_get_csr_registers(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int ret = 0, i; -+ struct kvm_csr_entry *csrs = cpu->kvm_msr_buf->entries; -+ -+ kvm_msr_buf_reset(cpu); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CRMD, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRMD, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_EUEN, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MISC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ECFG, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ESTAT, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERA, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADV, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADI, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_EEPN, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GTLBC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TRGP, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDH, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGD, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_RVACFG, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CPUID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS3, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS4, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS5, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS6, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS7, 0); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TMID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CNTC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GSTAT, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCFG, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GINTC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCNTC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GNMI, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRENT, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRERA, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CTAG, 0); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, 0); -+ -+ /* debug */ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPS, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPS, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DEBUG, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DERA, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DESAVE, 0); -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, cpu->kvm_msr_buf); -+ if (ret < cpu->kvm_msr_buf->ncsrs) { -+ struct kvm_csr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -+ printf("error: failed to get CSR 0x%" PRIx32"\n", -+ (uint32_t)e->index); -+ } -+ -+ for (i = 0; i < ret; i++) { -+ uint32_t index = csrs[i].index; -+ -+ switch (index) { -+ case LOONGARCH_CSR_CRMD: -+ env->CSR_CRMD = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PRMD: -+ env->CSR_PRMD = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_EUEN: -+ env->CSR_EUEN = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_MISC: -+ env->CSR_MISC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ECFG: -+ env->CSR_ECFG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ESTAT: -+ env->CSR_ESTAT = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERA: -+ env->CSR_ERA = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_BADV: -+ env->CSR_BADV = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_BADI: -+ env->CSR_BADI = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_EEPN: -+ env->CSR_EEPN = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBIDX: -+ env->CSR_TLBIDX = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBEHI: -+ env->CSR_TLBEHI = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBELO0: -+ env->CSR_TLBELO0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBELO1: -+ env->CSR_TLBELO1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GTLBC: -+ env->CSR_GTLBC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TRGP: -+ env->CSR_TRGP = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ASID: -+ env->CSR_ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PGDL: -+ env->CSR_PGDL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PGDH: -+ env->CSR_PGDH = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PGD: -+ env->CSR_PGD = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PWCTL0: -+ env->CSR_PWCTL0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PWCTL1: -+ env->CSR_PWCTL1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_STLBPGSIZE: -+ env->CSR_STLBPGSIZE = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_RVACFG: -+ env->CSR_RVACFG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_CPUID: -+ env->CSR_CPUID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PRCFG1: -+ env->CSR_PRCFG1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PRCFG2: -+ env->CSR_PRCFG2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PRCFG3: -+ env->CSR_PRCFG3 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS0: -+ env->CSR_KS0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS1: -+ env->CSR_KS1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS2: -+ env->CSR_KS2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS3: -+ env->CSR_KS3 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS4: -+ env->CSR_KS4 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS5: -+ env->CSR_KS5 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS6: -+ env->CSR_KS6 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS7: -+ env->CSR_KS7 = csrs[i].data; -+ break; -+ -+ case LOONGARCH_CSR_TMID: -+ env->CSR_TMID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_CNTC: -+ env->CSR_CNTC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TINTCLR: -+ env->CSR_TINTCLR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GSTAT: -+ env->CSR_GSTAT = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GCFG: -+ env->CSR_GCFG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GINTC: -+ env->CSR_GINTC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GCNTC: -+ env->CSR_GCNTC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_LLBCTL: -+ env->CSR_LLBCTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IMPCTL1: -+ env->CSR_IMPCTL1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IMPCTL2: -+ env->CSR_IMPCTL2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GNMI: -+ env->CSR_GNMI = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRENT: -+ env->CSR_TLBRENT = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRBADV: -+ env->CSR_TLBRBADV = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRERA: -+ env->CSR_TLBRERA = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRSAVE: -+ env->CSR_TLBRSAVE = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRELO0: -+ env->CSR_TLBRELO0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRELO1: -+ env->CSR_TLBRELO1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBREHI: -+ env->CSR_TLBREHI = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRPRMD: -+ env->CSR_TLBRPRMD = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRCTL: -+ env->CSR_ERRCTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRINFO: -+ env->CSR_ERRINFO = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRINFO1: -+ env->CSR_ERRINFO1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRENT: -+ env->CSR_ERRENT = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRERA: -+ env->CSR_ERRERA = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRSAVE: -+ env->CSR_ERRSAVE = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_CTAG: -+ env->CSR_CTAG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DMWIN0: -+ env->CSR_DMWIN0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DMWIN1: -+ env->CSR_DMWIN1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DMWIN2: -+ env->CSR_DMWIN2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DMWIN3: -+ env->CSR_DMWIN3 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCTRL0: -+ env->CSR_PERFCTRL0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCNTR0: -+ env->CSR_PERFCNTR0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCTRL1: -+ env->CSR_PERFCTRL1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCNTR1: -+ env->CSR_PERFCNTR1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCTRL2: -+ env->CSR_PERFCTRL2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCNTR2: -+ env->CSR_PERFCNTR2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCTRL3: -+ env->CSR_PERFCTRL3 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCNTR3: -+ env->CSR_PERFCNTR3 = csrs[i].data; -+ break; -+ -+ case LOONGARCH_CSR_MWPC: -+ env->CSR_MWPC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_MWPS: -+ env->CSR_MWPS = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB0ADDR: -+ env->CSR_DB0ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB0MASK: -+ env->CSR_DB0MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB0CTL: -+ env->CSR_DB0CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB0ASID: -+ env->CSR_DB0ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB1ADDR: -+ env->CSR_DB1ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB1MASK: -+ env->CSR_DB1MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB1CTL: -+ env->CSR_DB1CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB1ASID: -+ env->CSR_DB1ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB2ADDR: -+ env->CSR_DB2ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB2MASK: -+ env->CSR_DB2MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB2CTL: -+ env->CSR_DB2CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB2ASID: -+ env->CSR_DB2ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB3ADDR: -+ env->CSR_DB3ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB3MASK: -+ env->CSR_DB3MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB3CTL: -+ env->CSR_DB3CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB3ASID: -+ env->CSR_DB3ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_FWPC: -+ env->CSR_FWPC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_FWPS: -+ env->CSR_FWPS = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB0ADDR: -+ env->CSR_IB0ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB0MASK: -+ env->CSR_IB0MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB0CTL: -+ env->CSR_IB0CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB0ASID: -+ env->CSR_IB0ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB1ADDR: -+ env->CSR_IB1ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB1MASK: -+ env->CSR_IB1MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB1CTL: -+ env->CSR_IB1CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB1ASID: -+ env->CSR_IB1ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB2ADDR: -+ env->CSR_IB2ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB2MASK: -+ env->CSR_IB2MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB2CTL: -+ env->CSR_IB2CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB2ASID: -+ env->CSR_IB2ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB3ADDR: -+ env->CSR_IB3ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB3MASK: -+ env->CSR_IB3MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB3CTL: -+ env->CSR_IB3CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB3ASID: -+ env->CSR_IB3ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB4ADDR: -+ env->CSR_IB4ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB4MASK: -+ env->CSR_IB4MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB4CTL: -+ env->CSR_IB4CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB4ASID: -+ env->CSR_IB4ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB5ADDR: -+ env->CSR_IB5ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB5MASK: -+ env->CSR_IB5MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB5CTL: -+ env->CSR_IB5CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB5ASID: -+ env->CSR_IB5ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB6ADDR: -+ env->CSR_IB6ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB6MASK: -+ env->CSR_IB6MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB6CTL: -+ env->CSR_IB6CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB6ASID: -+ env->CSR_IB6ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB7ADDR: -+ env->CSR_IB7ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB7MASK: -+ env->CSR_IB7MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB7CTL: -+ env->CSR_IB7CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB7ASID: -+ env->CSR_IB7ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DEBUG: -+ env->CSR_DEBUG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DERA: -+ env->CSR_DERA = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DESAVE: -+ env->CSR_DESAVE = csrs[i].data; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ ret |= KVM_GET_ONE_UREG64(cs, LOONGARCH_CSR_TVAL, &env->CSR_TVAL); -+ ret |= KVM_GET_ONE_UREG64(cs, LOONGARCH_CSR_TCFG, &env->CSR_TCFG); -+ return ret; -+} -+ -+int kvm_loongarch_put_pvtime(LOONGARCHCPU *cpu) -+{ -+ CPULOONGARCHState *env = &cpu->env; -+ int err; -+ struct kvm_device_attr attr = { -+ .group = KVM_LARCH_VCPU_PVTIME_CTRL, -+ .attr = KVM_LARCH_VCPU_PVTIME_IPA, -+ .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_LARCH_VCPU_PVTIME_CTRL, -+ .attr = KVM_LARCH_VCPU_PVTIME_IPA, -+ .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_put_registers(CPUState *cs, int level) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ struct kvm_regs regs; -+ int ret; -+ int i; -+ -+ /* Set the registers based on QEMU's view of things */ -+ for (i = 0; i < 32; i++) { -+ regs.gpr[i] = (int64_t)(target_long)env->active_tc.gpr[i]; -+ } -+ -+ regs.pc = (int64_t)(target_long)env->active_tc.PC; -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); -+ -+ if (ret < 0) { -+ return ret; -+ } -+ -+ ret = kvm_loongarch_put_csr_registers(cs, level); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ ret = kvm_loongarch_put_fpu_registers(cs, level); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ return ret; -+} -+ -+int kvm_arch_get_registers(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int ret = 0; -+ struct kvm_regs regs; -+ int i; -+ -+ /* Get the current register set as KVM seems it */ -+ ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); -+ -+ if (ret < 0) { -+ return ret; -+ } -+ -+ for (i = 0; i < 32; i++) { -+ env->active_tc.gpr[i] = regs.gpr[i]; -+ } -+ -+ env->active_tc.PC = regs.pc; -+ -+ kvm_loongarch_get_csr_registers(cs); -+ kvm_loongarch_get_fpu_registers(cs); -+ -+ return ret; -+} -+ -+int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, -+ uint64_t address, uint32_t data, PCIDevice *dev) -+{ -+ return 0; -+} -+ -+int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, -+ int vector, PCIDevice *dev) -+{ -+ return 0; -+} -+ -+bool kvm_arch_cpu_check_are_resettable(void) -+{ -+ return true; -+} -+ -+int kvm_arch_release_virq_post(int virq) -+{ -+ return 0; -+} -+ -+int kvm_arch_msi_data_to_gsi(uint32_t data) -+{ -+ abort(); -+} -diff --git a/target/loongarch64/kvm_larch.h b/target/loongarch64/kvm_larch.h -new file mode 100644 -index 000000000..a56026d10 ---- /dev/null -+++ b/target/loongarch64/kvm_larch.h -@@ -0,0 +1,41 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * KVM/LOONGARCH: LOONGARCH specific KVM APIs -+ * -+ * Copyright (C) 2012-2014 Imagination Technologies Ltd. -+ * Authors: Sanjay Lal -+*/ -+ -+#ifndef KVM_LOONGARCH_H -+#define KVM_LOONGARCH_H -+ -+/** -+ * kvm_loongarch_reset_vcpu: -+ * @cpu: LOONGARCHCPU -+ * -+ * Called at reset time to set kernel registers to their initial values. -+ */ -+void kvm_loongarch_reset_vcpu(LOONGARCHCPU *cpu); -+ -+int kvm_loongarch_set_interrupt(LOONGARCHCPU *cpu, int irq, int level); -+int kvm_loongarch_set_ipi_interrupt(LOONGARCHCPU *cpu, int irq, int level); -+ -+int kvm_loongarch_put_pvtime(LOONGARCHCPU *cpu); -+int kvm_loongarch_get_pvtime(LOONGARCHCPU *cpu); -+ -+#ifndef KVM_INTERRUPT_SET -+#define KVM_INTERRUPT_SET -1 -+#endif -+ -+#ifndef KVM_INTERRUPT_UNSET -+#define KVM_INTERRUPT_UNSET -2 -+#endif -+ -+#ifndef KVM_INTERRUPT_SET_LEVEL -+#define KVM_INTERRUPT_SET_LEVEL -3 -+#endif -+ -+#endif /* KVM_LOONGARCH_H */ -diff --git a/target/loongarch64/larch-defs.h b/target/loongarch64/larch-defs.h -new file mode 100644 -index 000000000..d3a61cf25 ---- /dev/null -+++ b/target/loongarch64/larch-defs.h -@@ -0,0 +1,27 @@ -+#ifndef QEMU_LOONGARCH_DEFS_H -+#define QEMU_LOONGARCH_DEFS_H -+ -+/* If we want to use host float regs... */ -+/* #define USE_HOST_FLOAT_REGS */ -+ -+/* Real pages are variable size... */ -+#define TARGET_PAGE_BITS 14 -+ -+#define LOONGARCH_TLB_MAX 2112 -+ -+#define TARGET_LONG_BITS 64 -+#define TARGET_PHYS_ADDR_SPACE_BITS 48 -+#define TARGET_VIRT_ADDR_SPACE_BITS 48 -+ -+/* -+ * bit definitions for insn_flags (ISAs/ASEs flags) -+ * ------------------------------------------------ -+ */ -+#define ISA_LARCH32 0x00000001ULL -+#define ISA_LARCH64 0x00000002ULL -+#define INSN_LOONGARCH 0x00010000ULL -+ -+#define CPU_LARCH32 (ISA_LARCH32) -+#define CPU_LARCH64 (ISA_LARCH32 | ISA_LARCH64) -+ -+#endif /* QEMU_LOONGARCH_DEFS_H */ -diff --git a/target/loongarch64/machine.c b/target/loongarch64/machine.c -new file mode 100644 -index 000000000..b69bca6a9 ---- /dev/null -+++ b/target/loongarch64/machine.c -@@ -0,0 +1,416 @@ -+#include "qemu/osdep.h" -+#include "qemu-common.h" -+#include "cpu.h" -+#include "internal.h" -+#include "hw/hw.h" -+#include "kvm_larch.h" -+#include "migration/cpu.h" -+#include "linux/kvm.h" -+#include "sysemu/kvm.h" -+#include "qemu/error-report.h" -+ -+static int cpu_post_load(void *opaque, int version_id) -+{ -+ LOONGARCHCPU *cpu = opaque; -+ CPULOONGARCHState *env = &cpu->env; -+ int r = 0; -+ -+#ifdef CONFIG_KVM -+ struct kvm_loongarch_vcpu_state vcpu_state; -+ int i; -+ -+ vcpu_state.online_vcpus = cpu->online_vcpus; -+ vcpu_state.is_migrate = cpu->is_migrate; -+ vcpu_state.cpu_freq = cpu->cpu_freq; -+ vcpu_state.count_ctl = cpu->count_ctl; -+ vcpu_state.pending_exceptions = cpu->pending_exceptions; -+ vcpu_state.pending_exceptions_clr = cpu->pending_exceptions_clr; -+ for (i = 0; i < 4; i++) { -+ vcpu_state.core_ext_ioisr[i] = cpu->core_ext_ioisr[i]; -+ } -+ r = kvm_vcpu_ioctl(CPU(cpu), KVM_LARCH_SET_VCPU_STATE, &vcpu_state); -+ if (r) { -+ error_report("set vcpu state failed %d", r); -+ } -+ -+ kvm_loongarch_put_pvtime(cpu); -+#endif -+ -+ restore_fp_status(env); -+ compute_hflags(env); -+ -+ return r; -+} -+ -+static int cpu_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ LOONGARCHCPU *cpu = opaque; -+ struct kvm_loongarch_vcpu_state vcpu_state; -+ int i, r = 0; -+ -+ r = kvm_vcpu_ioctl(CPU(cpu), KVM_LARCH_GET_VCPU_STATE, &vcpu_state); -+ if (r < 0) { -+ error_report("get vcpu state failed %d", r); -+ return r; -+ } -+ -+ cpu->online_vcpus = vcpu_state.online_vcpus; -+ cpu->is_migrate = vcpu_state.is_migrate; -+ cpu->cpu_freq = vcpu_state.cpu_freq; -+ cpu->count_ctl = vcpu_state.count_ctl; -+ cpu->pending_exceptions = vcpu_state.pending_exceptions; -+ cpu->pending_exceptions_clr = vcpu_state.pending_exceptions_clr; -+ for (i = 0; i < 4; i++) { -+ cpu->core_ext_ioisr[i] = vcpu_state.core_ext_ioisr[i]; -+ } -+ -+ kvm_loongarch_get_pvtime(cpu); -+#endif -+ return 0; -+} -+ -+/* FPU state */ -+ -+static int get_fpr(QEMUFile *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ fpr_t *v = pv; -+ qemu_get_be64s(f, &v->d); -+ return 0; -+} -+ -+static int put_fpr(QEMUFile *f, void *pv, size_t size, -+ const VMStateField *field, JSONWriter *vmdesc) -+{ -+ fpr_t *v = pv; -+ qemu_put_be64s(f, &v->d); -+ return 0; -+} -+ -+const VMStateInfo vmstate_info_fpr = { -+ .name = "fpr", -+ .get = get_fpr, -+ .put = put_fpr, -+}; -+ -+#define VMSTATE_FPR_ARRAY_V(_f, _s, _n, _v) \ -+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_fpr, fpr_t) -+ -+#define VMSTATE_FPR_ARRAY(_f, _s, _n) \ -+ VMSTATE_FPR_ARRAY_V(_f, _s, _n, 0) -+ -+static VMStateField vmstate_fpu_fields[] = { -+ VMSTATE_FPR_ARRAY(fpr, CPULOONGARCHFPUContext, 32), -+ VMSTATE_UINT32(fcsr0, CPULOONGARCHFPUContext), -+ VMSTATE_END_OF_LIST() -+}; -+ -+const VMStateDescription vmstate_fpu = { -+ .name = "cpu/fpu", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = vmstate_fpu_fields -+}; -+ -+const VMStateDescription vmstate_inactive_fpu = { -+ .name = "cpu/inactive_fpu", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = vmstate_fpu_fields -+}; -+ -+/* TC state */ -+ -+static VMStateField vmstate_tc_fields[] = { -+ VMSTATE_UINTTL_ARRAY(gpr, TCState, 32), -+ VMSTATE_UINTTL(PC, TCState), -+ VMSTATE_END_OF_LIST() -+}; -+ -+const VMStateDescription vmstate_tc = { -+ .name = "cpu/tc", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = vmstate_tc_fields -+}; -+ -+const VMStateDescription vmstate_inactive_tc = { -+ .name = "cpu/inactive_tc", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = vmstate_tc_fields -+}; -+ -+/* TLB state */ -+ -+static int get_tlb(QEMUFile *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ ls3a5k_tlb_t *v = pv; -+ uint32_t flags; -+ -+ qemu_get_betls(f, &v->VPN); -+ qemu_get_be64s(f, &v->PageMask); -+ qemu_get_be32s(f, &v->PageSize); -+ qemu_get_be16s(f, &v->ASID); -+ qemu_get_be32s(f, &flags); -+ v->RPLV1 = (flags >> 21) & 1; -+ v->RPLV0 = (flags >> 20) & 1; -+ v->PLV1 = (flags >> 18) & 3; -+ v->PLV0 = (flags >> 16) & 3; -+ v->EHINV = (flags >> 15) & 1; -+ v->RI1 = (flags >> 14) & 1; -+ v->RI0 = (flags >> 13) & 1; -+ v->XI1 = (flags >> 12) & 1; -+ v->XI0 = (flags >> 11) & 1; -+ v->WE1 = (flags >> 10) & 1; -+ v->WE0 = (flags >> 9) & 1; -+ v->V1 = (flags >> 8) & 1; -+ v->V0 = (flags >> 7) & 1; -+ v->C1 = (flags >> 4) & 7; -+ v->C0 = (flags >> 1) & 7; -+ v->G = (flags >> 0) & 1; -+ qemu_get_be64s(f, &v->PPN0); -+ qemu_get_be64s(f, &v->PPN1); -+ -+ return 0; -+} -+ -+static int put_tlb(QEMUFile *f, void *pv, size_t size, -+ const VMStateField *field, JSONWriter *vmdesc) -+{ -+ ls3a5k_tlb_t *v = pv; -+ -+ uint16_t asid = v->ASID; -+ uint32_t flags = ((v->RPLV1 << 21) | -+ (v->RPLV0 << 20) | -+ (v->PLV1 << 18) | -+ (v->PLV0 << 16) | -+ (v->EHINV << 15) | -+ (v->RI1 << 14) | -+ (v->RI0 << 13) | -+ (v->XI1 << 12) | -+ (v->XI0 << 11) | -+ (v->WE1 << 10) | -+ (v->WE0 << 9) | -+ (v->V1 << 8) | -+ (v->V0 << 7) | -+ (v->C1 << 4) | -+ (v->C0 << 1) | -+ (v->G << 0)); -+ -+ qemu_put_betls(f, &v->VPN); -+ qemu_put_be64s(f, &v->PageMask); -+ qemu_put_be32s(f, &v->PageSize); -+ qemu_put_be16s(f, &asid); -+ qemu_put_be32s(f, &flags); -+ qemu_put_be64s(f, &v->PPN0); -+ qemu_put_be64s(f, &v->PPN1); -+ -+ return 0; -+} -+ -+const VMStateInfo vmstate_info_tlb = { -+ .name = "tlb_entry", -+ .get = get_tlb, -+ .put = put_tlb, -+}; -+ -+#define VMSTATE_TLB_ARRAY_V(_f, _s, _n, _v) \ -+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_tlb, ls3a5k_tlb_t) -+ -+#define VMSTATE_TLB_ARRAY(_f, _s, _n) \ -+ VMSTATE_TLB_ARRAY_V(_f, _s, _n, 0) -+ -+const VMStateDescription vmstate_tlb = { -+ .name = "cpu/tlb", -+ .version_id = 2, -+ .minimum_version_id = 2, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT32(nb_tlb, CPULOONGARCHTLBContext), -+ VMSTATE_UINT32(tlb_in_use, CPULOONGARCHTLBContext), -+ VMSTATE_TLB_ARRAY(mmu.ls3a5k.tlb, CPULOONGARCHTLBContext, LOONGARCH_TLB_MAX), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+/* LOONGARCH CPU state */ -+ -+const VMStateDescription vmstate_loongarch_cpu = { -+ .name = "cpu", -+ .version_id = 15, -+ .minimum_version_id = 15, -+ .post_load = cpu_post_load, -+ .pre_save = cpu_pre_save, -+ .fields = (VMStateField[]) { -+ /* Active TC */ -+ VMSTATE_STRUCT(env.active_tc, LOONGARCHCPU, 1, vmstate_tc, TCState), -+ -+ /* Active FPU */ -+ VMSTATE_STRUCT(env.active_fpu, LOONGARCHCPU, 1, vmstate_fpu, -+ CPULOONGARCHFPUContext), -+ -+ /* TLB */ -+ VMSTATE_STRUCT_POINTER(env.tlb, LOONGARCHCPU, vmstate_tlb, -+ CPULOONGARCHTLBContext), -+ /* CPU metastate */ -+ VMSTATE_UINT32(env.current_tc, LOONGARCHCPU), -+ VMSTATE_INT32(env.error_code, LOONGARCHCPU), -+ VMSTATE_UINTTL(env.btarget, LOONGARCHCPU), -+ VMSTATE_UINTTL(env.bcond, LOONGARCHCPU), -+ -+ VMSTATE_UINT64(env.lladdr, LOONGARCHCPU), -+ -+ /* PV time */ -+ VMSTATE_UINT64(env.st.guest_addr, LOONGARCHCPU), -+ -+ /* Remaining CSR registers */ -+ VMSTATE_UINT64(env.CSR_CRMD, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PRMD, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_EUEN, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_MISC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ECFG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ESTAT, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERA, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_BADV, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_BADI, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_EEPN, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBIDX, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBEHI, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBELO0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBELO1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBWIRED, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GTLBC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TRGP, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PGDL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PGDH, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PGD, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PWCTL0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PWCTL1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_STLBPGSIZE, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_RVACFG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_CPUID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PRCFG1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PRCFG2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PRCFG3, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS3, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS4, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS5, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS6, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS7, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TMID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TCFG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TVAL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_CNTC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TINTCLR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GSTAT, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GCFG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GINTC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GCNTC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_LLBCTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IMPCTL1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IMPCTL2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GNMI, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRENT, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRBADV, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRERA, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRSAVE, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRELO0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRELO1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBREHI, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRPRMD, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRCTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRINFO, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRINFO1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRENT, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRERA, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRSAVE, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_CTAG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DMWIN0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DMWIN1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DMWIN2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DMWIN3, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCTRL0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCNTR0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCTRL1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCNTR1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCTRL2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCNTR2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCTRL3, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCNTR3, LOONGARCHCPU), -+ /* debug */ -+ VMSTATE_UINT64(env.CSR_MWPC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_MWPS, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB0ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB0MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB0CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB0ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB1ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB1MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB1CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB1ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB2ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB2MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB2CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB2ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB3ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB3MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB3CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB3ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_FWPC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_FWPS, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB0ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB0MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB0CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB0ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB1ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB1MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB1CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB1ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB2ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB2MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB2CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB2ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB3ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB3MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB3CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB3ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB4ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB4MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB4CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB4ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB5ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB5MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB5CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB5ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB6ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB6MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB6CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB6ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB7ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB7MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB7CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB7ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DEBUG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DERA, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DESAVE, LOONGARCHCPU), -+ -+ VMSTATE_STRUCT_ARRAY(env.fpus, LOONGARCHCPU, LOONGARCH_FPU_MAX, 1, -+ vmstate_inactive_fpu, CPULOONGARCHFPUContext), -+ VMSTATE_UINT8(online_vcpus, LOONGARCHCPU), -+ VMSTATE_UINT8(is_migrate, LOONGARCHCPU), -+ VMSTATE_UINT64(counter_value, LOONGARCHCPU), -+ VMSTATE_UINT32(cpu_freq, LOONGARCHCPU), -+ VMSTATE_UINT32(count_ctl, LOONGARCHCPU), -+ VMSTATE_UINT64(pending_exceptions, LOONGARCHCPU), -+ VMSTATE_UINT64(pending_exceptions_clr, LOONGARCHCPU), -+ VMSTATE_UINT64_ARRAY(core_ext_ioisr, LOONGARCHCPU, 4), -+ -+ VMSTATE_END_OF_LIST() -+ }, -+}; -diff --git a/target/loongarch64/meson.build b/target/loongarch64/meson.build -new file mode 100644 -index 000000000..6badf4484 ---- /dev/null -+++ b/target/loongarch64/meson.build -@@ -0,0 +1,35 @@ -+loongarch_user_ss = ss.source_set() -+loongarch_softmmu_ss = ss.source_set() -+loongarch_ss = ss.source_set() -+loongarch_ss.add(files( -+ 'cpu.c', -+ 'fpu.c', -+ 'gdbstub.c', -+)) -+ -+gen = [ -+ decodetree.process('insn.decode', extra_args: [ '--decode', 'decode_insn', -+ '--insnwidth', '32' ]) -+] -+ -+loongarch_ss.add(gen) -+loongarch_ss.add(when: 'CONFIG_TCG', if_true: files( -+ 'helper.c', -+ 'translate.c', -+ 'op_helper.c', -+ 'fpu_helper.c', -+ 'tlb_helper.c', -+ 'csr_helper.c', -+)) -+ -+loongarch_softmmu_ss.add(when: 'CONFIG_SOFTMMU', if_true: files( -+ 'machine.c', -+ 'stabletimer.c', -+ 'arch_dump.c', -+)) -+ -+loongarch_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) -+ -+target_arch += {'loongarch64': loongarch_ss} -+target_softmmu_arch += {'loongarch64': loongarch_softmmu_ss} -+target_user_arch += {'loongarch64': loongarch_user_ss} -diff --git a/target/loongarch64/op_helper.c b/target/loongarch64/op_helper.c -new file mode 100644 -index 000000000..9a34c0d25 ---- /dev/null -+++ b/target/loongarch64/op_helper.c -@@ -0,0 +1,533 @@ -+/* -+ * LOONGARCH emulation helpers for qemu. -+ * -+ * Copyright (c) 2004-2005 Jocelyn Mayer -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 "qemu/main-loop.h" -+#include "cpu.h" -+#include "internal.h" -+#include "qemu/host-utils.h" -+#include "exec/helper-proto.h" -+#include "exec/exec-all.h" -+#include "exec/cpu_ldst.h" -+#include "sysemu/kvm.h" -+#include "qemu/crc32c.h" -+#include -+#include "hw/irq.h" -+#include "hw/core/cpu.h" -+#include "instmap.h" -+ -+/*****************************************************************************/ -+/* Exceptions processing helpers */ -+ -+void helper_raise_exception_err(CPULOONGARCHState *env, uint32_t exception, -+ int error_code) -+{ -+ do_raise_exception_err(env, exception, error_code, 0); -+} -+ -+void helper_raise_exception(CPULOONGARCHState *env, uint32_t exception) -+{ -+ do_raise_exception(env, exception, GETPC()); -+} -+ -+void helper_raise_exception_debug(CPULOONGARCHState *env) -+{ -+ do_raise_exception(env, EXCP_DEBUG, 0); -+} -+ -+static void raise_exception(CPULOONGARCHState *env, uint32_t exception) -+{ -+ do_raise_exception(env, exception, 0); -+} -+ -+#if defined(CONFIG_USER_ONLY) -+#define HELPER_LD(name, insn, type) \ -+static inline type do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ int mem_idx, uintptr_t retaddr) \ -+{ \ -+ return (type) cpu_##insn##_data_ra(env, addr, retaddr); \ -+} -+#else -+ -+#define HF_SMAP_SHIFT 23 /* CR4.SMAP */ -+#define HF_SMAP_MASK (1 << HF_SMAP_SHIFT) -+#define MMU_KNOSMAP_IDX 2 -+#define HF_CPL_SHIFT 0 -+#define HF_CPL_MASK (3 << HF_CPL_SHIFT) -+#define AC_MASK 0x00040000 -+#define MMU_KSMAP_IDX 0 -+static inline int cpu_mmu_index_kernel(CPULOONGARCHState *env) -+{ -+ return !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP_IDX : -+ ((env->hflags & HF_CPL_MASK) < 3 && (env->hflags & AC_MASK)) -+ ? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX; -+} -+ -+#define cpu_ldl_kernel_ra(e, p, r) \ -+ cpu_ldl_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) -+ -+#define HELPER_LD(name, insn, type) \ -+static inline type do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ int mem_idx, uintptr_t retaddr) \ -+{ \ -+/* \ -+ switch (mem_idx) { \ -+ case 0: return (type) cpu_##insn##_kernel_ra(env, addr, retaddr); \ -+ case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr); \ -+ default: \ -+ case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr); \ -+ case 3: return (type) cpu_##insn##_error_ra(env, addr, retaddr); \ -+ } \ -+*/ \ -+} -+#endif -+#if 0 -+HELPER_LD(lw, ldl, int32_t) -+HELPER_LD(ld, ldq, int64_t) -+#endif -+#undef HELPER_LD -+ -+#if defined(CONFIG_USER_ONLY) -+#define HELPER_ST(name, insn, type) \ -+static inline void do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ type val, int mem_idx, uintptr_t retaddr) \ -+{ \ -+/* \ -+ cpu_##insn##_data_ra(env, addr, val, retaddr); \ -+*/ \ -+} -+#else -+#define HELPER_ST(name, insn, type) \ -+static inline void do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ type val, int mem_idx, uintptr_t retaddr) \ -+{ \ -+/* \ -+ switch (mem_idx) { \ -+ case 0: \ -+ cpu_##insn##_kernel_ra(env, addr, val, retaddr); \ -+ break; \ -+ case 1: \ -+ cpu_##insn##_super_ra(env, addr, val, retaddr); \ -+ break; \ -+ default: \ -+ case 2: \ -+ cpu_##insn##_user_ra(env, addr, val, retaddr); \ -+ break; \ -+ case 3: \ -+ cpu_##insn##_error_ra(env, addr, val, retaddr); \ -+ break; \ -+ } \ -+*/ \ -+} -+#endif -+#if 0 -+HELPER_ST(sb, stb, uint8_t) -+HELPER_ST(sw, stl, uint32_t) -+HELPER_ST(sd, stq, uint64_t) -+#endif -+#undef HELPER_ST -+ -+static inline target_ulong bitswap(target_ulong v) -+{ -+ v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | -+ ((v & (target_ulong)0x5555555555555555ULL) << 1); -+ v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | -+ ((v & (target_ulong)0x3333333333333333ULL) << 2); -+ v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | -+ ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); -+ return v; -+} -+ -+target_ulong helper_dbitswap(target_ulong rt) -+{ -+ return bitswap(rt); -+} -+ -+target_ulong helper_bitswap(target_ulong rt) -+{ -+ return (int32_t)bitswap(rt); -+} -+ -+/* these crc32 functions are based on target/arm/helper-a64.c */ -+target_ulong helper_crc32(target_ulong val, target_ulong m, uint32_t sz) -+{ -+ uint8_t buf[8]; -+ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); -+ -+ m &= mask; -+ stq_le_p(buf, m); -+ return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); -+} -+ -+target_ulong helper_crc32c(target_ulong val, target_ulong m, uint32_t sz) -+{ -+ uint8_t buf[8]; -+ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); -+ m &= mask; -+ stq_le_p(buf, m); -+ return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); -+} -+ -+#ifndef CONFIG_USER_ONLY -+ -+#define HELPER_LD_ATOMIC(name, insn, almask) \ -+target_ulong helper_##name(CPULOONGARCHState *env, target_ulong arg, int mem_idx) \ -+{ \ -+/* \ -+ if (arg & almask) { \ -+ env->CSR_BADV = arg; \ -+ do_raise_exception(env, EXCP_AdEL, GETPC()); \ -+ } \ -+ env->lladdr = arg; \ -+ env->llval = do_##insn(env, arg, mem_idx, GETPC()); \ -+ return env->llval; \ -+*/ \ -+} -+#if 0 -+HELPER_LD_ATOMIC(ll, lw, 0x3) -+HELPER_LD_ATOMIC(lld, ld, 0x7) -+#endif -+#undef HELPER_LD_ATOMIC -+#endif -+ -+#ifndef CONFIG_USER_ONLY -+void helper_drdtime(CPULOONGARCHState *env, target_ulong rd, target_ulong rs) -+{ -+ env->active_tc.gpr[rd] = cpu_loongarch_get_stable_counter(env); -+ env->active_tc.gpr[rs] = env->CSR_TMID; -+} -+#endif -+ -+#ifndef CONFIG_USER_ONLY -+static void debug_pre_ertn(CPULOONGARCHState *env) -+{ -+ if (qemu_loglevel_mask(CPU_LOG_EXEC)) { -+ qemu_log("ERTN: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx, -+ env->active_tc.PC, env->CSR_ERA); -+ qemu_log("\n"); -+ } -+} -+ -+static void debug_post_ertn(CPULOONGARCHState *env) -+{ -+ if (qemu_loglevel_mask(CPU_LOG_EXEC)) { -+ qemu_log("ERTN: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx, -+ env->active_tc.PC, env->CSR_ERA); -+ } -+} -+ -+static void set_pc(CPULOONGARCHState *env, target_ulong error_pc) -+{ -+ env->active_tc.PC = error_pc & ~(target_ulong)1; -+} -+ -+static inline void exception_return(CPULOONGARCHState *env) -+{ -+ debug_pre_ertn(env); -+ -+ if (cpu_refill_state(env)) { -+ env->CSR_CRMD &= (~0x7); -+ env->CSR_CRMD |= (env->CSR_TLBRPRMD & 0x7); -+ /* Clear Refill flag and set pc */ -+ env->CSR_TLBRERA &= (~0x1); -+ set_pc(env, env->CSR_TLBRERA); -+ if (qemu_loglevel_mask(CPU_LOG_INT)) { -+ qemu_log("%s: TLBRERA 0x%lx\n", __func__, env->CSR_TLBRERA); -+ } -+ } else { -+ env->CSR_CRMD &= (~0x7); -+ env->CSR_CRMD |= (env->CSR_PRMD & 0x7); -+ /* Clear Refill flag and set pc*/ -+ set_pc(env, env->CSR_ERA); -+ if (qemu_loglevel_mask(CPU_LOG_INT)) { -+ qemu_log("%s: ERA 0x%lx\n", __func__, env->CSR_ERA); -+ } -+ } -+ -+ compute_hflags(env); -+ debug_post_ertn(env); -+} -+ -+void helper_ertn(CPULOONGARCHState *env) -+{ -+ exception_return(env); -+ env->lladdr = 1; -+} -+ -+#endif /* !CONFIG_USER_ONLY */ -+ -+void helper_idle(CPULOONGARCHState *env) -+{ -+ CPUState *cs = CPU(loongarch_env_get_cpu(env)); -+ -+ cs->halted = 1; -+ cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); -+ /* Last instruction in the block, PC was updated before -+ - no need to recover PC and icount */ -+ raise_exception(env, EXCP_HLT); -+} -+ -+#if !defined(CONFIG_USER_ONLY) -+ -+void loongarch_cpu_do_unaligned_access(CPUState *cs, vaddr addr, -+ MMUAccessType access_type, -+ int mmu_idx, uintptr_t retaddr) -+{ -+ while(1); -+} -+ -+#endif /* !CONFIG_USER_ONLY */ -+ -+void helper_store_scr(CPULOONGARCHState *env, uint32_t n, target_ulong val) -+{ -+ env->scr[n & 0x3] = val; -+} -+ -+target_ulong helper_load_scr(CPULOONGARCHState *env, uint32_t n) -+{ -+ return env->scr[n & 0x3]; -+} -+ -+/* loongarch assert op */ -+void helper_asrtle_d(CPULOONGARCHState *env, target_ulong rs, target_ulong rt) -+{ -+ if (rs > rt) { -+ do_raise_exception(env, EXCP_AdEL, GETPC()); -+ } -+} -+ -+void helper_asrtgt_d(CPULOONGARCHState *env, target_ulong rs, target_ulong rt) -+{ -+ if (rs <= rt) { -+ do_raise_exception(env, EXCP_AdEL, GETPC()); -+ } -+} -+ -+target_ulong helper_cto_w(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint32_t v = (uint32_t)a0; -+ int temp = 0; -+ -+ while ((v & 0x1) == 1) { -+ temp++; -+ v = v >> 1; -+ } -+ -+ return (target_ulong)temp; -+} -+ -+target_ulong helper_ctz_w(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint32_t v = (uint32_t)a0; -+ -+ if (v == 0) { -+ return 32; -+ } -+ -+ int temp = 0; -+ while ((v & 0x1) == 0) { -+ temp++; -+ v = v >> 1; -+ } -+ -+ return (target_ulong)temp; -+} -+ -+target_ulong helper_cto_d(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint64_t v = a0; -+ int temp = 0; -+ -+ while ((v & 0x1) == 1) { -+ temp++; -+ v = v >> 1; -+ } -+ -+ return (target_ulong)temp; -+} -+ -+target_ulong helper_ctz_d(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint64_t v = a0; -+ -+ if (v == 0) { -+ return 64; -+ } -+ -+ int temp = 0; -+ while ((v & 0x1) == 0) { -+ temp++; -+ v = v >> 1; -+ } -+ -+ return (target_ulong)temp; -+} -+ -+target_ulong helper_bitrev_w(CPULOONGARCHState *env, target_ulong a0) -+{ -+ int32_t v = (int32_t)a0; -+ const int SIZE = 32; -+ uint8_t bytes[SIZE]; -+ -+ int i; -+ for (i = 0; i < SIZE; i++) { -+ bytes[i] = v & 0x1; -+ v = v >> 1; -+ } -+ /* v == 0 */ -+ for (i = 0; i < SIZE; i++) { -+ v = v | ((uint32_t)bytes[i] << (SIZE - 1 - i)); -+ } -+ -+ return (target_ulong)(int32_t)v; -+} -+ -+target_ulong helper_bitrev_d(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint64_t v = a0; -+ const int SIZE = 64; -+ uint8_t bytes[SIZE]; -+ -+ int i; -+ for (i = 0; i < SIZE; i++) { -+ bytes[i] = v & 0x1; -+ v = v >> 1; -+ } -+ /* v == 0 */ -+ for (i = 0; i < SIZE; i++) { -+ v = v | ((uint64_t)bytes[i] << (SIZE - 1 - i)); -+ } -+ -+ return (target_ulong)v; -+} -+ -+void helper_memtrace_addr(CPULOONGARCHState *env, -+ target_ulong address, uint32_t op) -+{ -+ qemu_log("[cpu %d asid 0x%lx pc 0x%lx] addr 0x%lx op", -+ CPU(loongarch_env_get_cpu(env))->cpu_index, -+ env->CSR_ASID, env->active_tc.PC, address); -+ switch (op) { -+ case OPC_LARCH_LDPTR_D: -+ qemu_log("OPC_LARCH_LDPTR_D"); -+ break; -+ case OPC_LARCH_LD_D: -+ qemu_log("OPC_LARCH_LD_D"); -+ break; -+ case OPC_LARCH_LDPTR_W: -+ qemu_log("OPC_LARCH_LDPTR_W"); -+ break; -+ case OPC_LARCH_LD_W: -+ qemu_log("OPC_LARCH_LD_W"); -+ break; -+ case OPC_LARCH_LD_H: -+ qemu_log("OPC_LARCH_LD_H"); -+ break; -+ case OPC_LARCH_LD_B: -+ qemu_log("OPC_LARCH_LD_B"); -+ break; -+ case OPC_LARCH_LD_WU: -+ qemu_log("OPC_LARCH_LD_WU"); -+ break; -+ case OPC_LARCH_LD_HU: -+ qemu_log("OPC_LARCH_LD_HU"); -+ break; -+ case OPC_LARCH_LD_BU: -+ qemu_log("OPC_LARCH_LD_BU"); -+ break; -+ case OPC_LARCH_STPTR_D: -+ qemu_log("OPC_LARCH_STPTR_D"); -+ break; -+ case OPC_LARCH_ST_D: -+ qemu_log("OPC_LARCH_ST_D"); -+ break; -+ case OPC_LARCH_STPTR_W: -+ qemu_log("OPC_LARCH_STPTR_W"); -+ break; -+ case OPC_LARCH_ST_W: -+ qemu_log("OPC_LARCH_ST_W"); -+ break; -+ case OPC_LARCH_ST_H: -+ qemu_log("OPC_LARCH_ST_H"); -+ break; -+ case OPC_LARCH_ST_B: -+ qemu_log("OPC_LARCH_ST_B"); -+ break; -+ case OPC_LARCH_FLD_S: -+ qemu_log("OPC_LARCH_FLD_S"); -+ break; -+ case OPC_LARCH_FLD_D: -+ qemu_log("OPC_LARCH_FLD_D"); -+ break; -+ case OPC_LARCH_FST_S: -+ qemu_log("OPC_LARCH_FST_S"); -+ break; -+ case OPC_LARCH_FST_D: -+ qemu_log("OPC_LARCH_FST_D"); -+ break; -+ case OPC_LARCH_FLDX_S: -+ qemu_log("OPC_LARCH_FLDX_S"); -+ break; -+ case OPC_LARCH_FLDGT_S: -+ qemu_log("OPC_LARCH_FLDGT_S"); -+ break; -+ case OPC_LARCH_FLDLE_S: -+ qemu_log("OPC_LARCH_FLDLE_S"); -+ break;; -+ case OPC_LARCH_FSTX_S: -+ qemu_log("OPC_LARCH_FSTX_S"); -+ break; -+ case OPC_LARCH_FSTGT_S: -+ qemu_log("OPC_LARCH_FSTGT_S"); -+ break; -+ case OPC_LARCH_FSTLE_S: -+ qemu_log("OPC_LARCH_FSTLE_S"); -+ break; -+ case OPC_LARCH_FLDX_D: -+ qemu_log("OPC_LARCH_FLDX_D"); -+ break; -+ case OPC_LARCH_FLDGT_D: -+ qemu_log("OPC_LARCH_FLDGT_D"); -+ break; -+ case OPC_LARCH_FLDLE_D: -+ qemu_log("OPC_LARCH_FLDLE_D"); -+ break;; -+ case OPC_LARCH_FSTX_D: -+ qemu_log("OPC_LARCH_FSTX_D"); -+ break; -+ case OPC_LARCH_FSTGT_D: -+ qemu_log("OPC_LARCH_FSTGT_D"); -+ break; -+ case OPC_LARCH_FSTLE_D: -+ qemu_log("OPC_LARCH_FSTLE_D"); -+ break; -+ case OPC_LARCH_LL_W: -+ qemu_log("OPC_LARCH_LL_W"); -+ break; -+ case OPC_LARCH_LL_D: -+ qemu_log("OPC_LARCH_LL_D"); -+ break; -+ default: -+ qemu_log("0x%x", op); -+ } -+} -+ -+void helper_memtrace_val(CPULOONGARCHState *env, target_ulong val) -+{ -+ qemu_log("val 0x%lx\n", val); -+} -diff --git a/target/loongarch64/stabletimer.c b/target/loongarch64/stabletimer.c -new file mode 100644 -index 000000000..b86fecf89 ---- /dev/null -+++ b/target/loongarch64/stabletimer.c -@@ -0,0 +1,122 @@ -+/* -+ * QEMU LOONGARCH timer support -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/loongarch/cpudevs.h" -+#include "qemu/timer.h" -+#include "sysemu/kvm.h" -+#include "internal.h" -+#include "hw/irq.h" -+ -+ -+#ifdef DEBUG_TIMER -+#define debug_timer(fmt, args...) printf("%s(%d)-%s -> " #fmt "\n", \ -+ __FILE__, __LINE__, __func__, ##args); -+#else -+#define debug_timer(fmt, args...) -+#endif -+ -+#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */ -+#define STABLETIMER_TICK_MASK 0xfffffffffffcUL -+#define STABLETIMER_ENABLE 0x1UL -+#define STABLETIMER_PERIOD 0x2UL -+ -+/* return random value in [low, high] */ -+uint32_t cpu_loongarch_get_random_ls3a5k_tlb(uint32_t low, uint32_t high) -+{ -+ static uint32_t seed = 5; -+ static uint32_t prev_idx; -+ uint32_t idx; -+ uint32_t nb_rand_tlb = high - low + 1; -+ -+ do { -+ seed = 1103515245 * seed + 12345; -+ idx = (seed >> 16) % nb_rand_tlb + low; -+ } while (idx == prev_idx); -+ prev_idx = idx; -+ -+ return idx; -+} -+ -+/* LOONGARCH timer */ -+uint64_t cpu_loongarch_get_stable_counter(CPULOONGARCHState *env) -+{ -+ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD; -+} -+ -+uint64_t cpu_loongarch_get_stable_timer_ticks(CPULOONGARCHState *env) -+{ -+ uint64_t now, expire; -+ -+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -+ expire = timer_expire_time_ns(env->timer); -+ -+ return (expire - now) / TIMER_PERIOD; -+} -+ -+void cpu_loongarch_store_stable_timer_config(CPULOONGARCHState *env, -+ uint64_t value) -+{ -+ uint64_t now, next; -+ -+ env->CSR_TCFG = value; -+ if (value & STABLETIMER_ENABLE) { -+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -+ next = now + (value & STABLETIMER_TICK_MASK) * TIMER_PERIOD; -+ timer_mod(env->timer, next); -+ } -+ debug_timer("0x%lx 0x%lx now 0x%lx, next 0x%lx", -+ value, env->CSR_TCFG, now, next); -+} -+ -+static void loongarch_stable_timer_cb(void *opaque) -+{ -+ CPULOONGARCHState *env; -+ uint64_t now, next; -+ -+ env = opaque; -+ debug_timer(); -+ if (env->CSR_TCFG & STABLETIMER_PERIOD) { -+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -+ next = now + (env->CSR_TCFG & STABLETIMER_TICK_MASK) * TIMER_PERIOD; -+ timer_mod(env->timer, next); -+ } else { -+ env->CSR_TCFG &= ~STABLETIMER_ENABLE; -+ } -+ -+ qemu_irq_raise(env->irq[IRQ_TIMER]); -+ -+} -+ -+void cpu_loongarch_clock_init(LOONGARCHCPU *cpu) -+{ -+ CPULOONGARCHState *env = &cpu->env; -+ -+ /* -+ * If we're in KVM mode, don't create the periodic timer, that is handled in -+ * kernel. -+ */ -+ if (!kvm_enabled()) { -+ env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, -+ &loongarch_stable_timer_cb, env); -+ } -+} -diff --git a/target/loongarch64/tlb_helper.c b/target/loongarch64/tlb_helper.c -new file mode 100644 -index 000000000..f5e68349a ---- /dev/null -+++ b/target/loongarch64/tlb_helper.c -@@ -0,0 +1,729 @@ -+/* -+ * loongarch tlb emulation helpers for qemu. -+ * -+ * Copyright (c) 2020 -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 "qemu/main-loop.h" -+#include "cpu.h" -+#include "internal.h" -+#include "qemu/host-utils.h" -+#include "exec/helper-proto.h" -+#include "exec/exec-all.h" -+#include "exec/cpu_ldst.h" -+ -+#ifndef CONFIG_USER_ONLY -+ -+#define HELPER_LD(name, insn, type) \ -+static inline type do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ int mem_idx, uintptr_t retaddr) \ -+{ \ -+/* \ -+ switch (mem_idx) { \ -+ case 0: return (type) cpu_##insn##_kernel_ra(env, addr, retaddr); \ -+ case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr); \ -+ default: \ -+ case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr); \ -+ case 3: return (type) cpu_##insn##_error_ra(env, addr, retaddr); \ -+ } \ -+*/ \ -+} -+#if 0 -+HELPER_LD(lw, ldl, int32_t) -+HELPER_LD(ld, ldq, int64_t) -+#endif -+ -+void helper_lddir(CPULOONGARCHState *env, target_ulong base, target_ulong rt, -+ target_ulong level, uint32_t mem_idx) -+{ -+#if 0 -+ target_ulong pointer = env->active_tc.gpr[base]; -+ target_ulong badvaddr; -+ target_ulong index; -+ target_ulong vaddr; -+ int shift; -+ -+ badvaddr = env->CSR_TLBRBADV; -+ -+ /* 0:8B, 1:16B, 2:32B, 3:64B */ -+ shift = (env->CSR_PWCTL0 >> 30) & 0x3; -+ shift = (shift + 1) * 3; -+ -+ switch (level) { -+ case 1: -+ index = (badvaddr >> ((env->CSR_PWCTL0 >> 10) & 0x1f)) & \ -+ ((1 << ((env->CSR_PWCTL0 >> 15) & 0x1f)) - 1); -+ break; -+ case 3: -+ index = (badvaddr >> ((env->CSR_PWCTL1 >> 0) & 0x3f)) & \ -+ ((1 << ((env->CSR_PWCTL1 >> 6) & 0x3f)) - 1); -+ break; -+ default: -+ do_raise_exception(env, EXCP_RI, GETPC()); -+ return; -+ } -+ -+ vaddr = pointer | index << shift; -+ env->active_tc.gpr[rt] = do_ld(env, vaddr, mem_idx, GETPC()); -+ return; -+#endif -+} -+ -+void helper_ldpte(CPULOONGARCHState *env, target_ulong base, target_ulong odd, -+ uint32_t mem_idx) -+{ -+#if 0 -+ target_ulong pointer = env->active_tc.gpr[base]; -+ target_ulong vaddr; -+ target_ulong tmp0 = 1; -+ target_ulong ptindex, ptoffset0, ptoffset1; -+ target_ulong pagesize; -+ target_ulong badv; -+ int shift; -+ bool huge = pointer & LOONGARCH_PAGE_HUGE; -+ -+ if (huge) { -+ /* Huge Page. pointer is paddr */ -+ tmp0 = pointer ^ LOONGARCH_PAGE_HUGE; -+ /* move Global bit */ -+ tmp0 |= ((tmp0 & LOONGARCH_HUGE_GLOBAL) -+ >> (LOONGARCH_HUGE_GLOBAL_SH - CSR_TLBLO0_GLOBAL_SHIFT)); -+ pagesize = (env->CSR_PWCTL0 & 0x1f) + -+ ((env->CSR_PWCTL0 >> 5) & 0x1f) - 1; -+ if (odd) { -+ tmp0 += (1 << pagesize); -+ } -+ } else { -+ /* 0:8B, 1:16B, 2:32B, 3:64B */ -+ shift = (env->CSR_PWCTL0 >> 30) & 0x3; -+ shift = (shift + 1) * 3; -+ badv = env->CSR_TLBRBADV; -+ -+ ptindex = (badv >> (env->CSR_PWCTL0 & 0x1f)) & -+ ((1 << ((env->CSR_PWCTL0 >> 5) & 0x1f)) - 1); -+ ptindex = ptindex & ~0x1; /* clear bit 0 */ -+ ptoffset0 = ptindex << shift; -+ ptoffset1 = (ptindex + 1) << shift; -+ -+ vaddr = pointer | (odd ? ptoffset1 : ptoffset0); -+ tmp0 = do_ld(env, vaddr, mem_idx, GETPC()); -+ pagesize = (env->CSR_PWCTL0 & 0x1f); -+ } -+ if (odd) { -+ env->CSR_TLBRELO1 = tmp0; -+ } else { -+ env->CSR_TLBRELO0 = tmp0; -+ } -+ env->CSR_TLBREHI = env->CSR_TLBREHI & (~0x3f); -+ env->CSR_TLBREHI = env->CSR_TLBREHI | pagesize; -+#endif -+ return; -+} -+ -+target_ulong helper_read_pgd(CPULOONGARCHState *env) -+{ -+ uint64_t badv; -+ -+ assert(env->CSR_TLBRERA & 0x1); -+ -+ if (env->CSR_TLBRERA & 0x1) { -+ badv = env->CSR_TLBRBADV; -+ } else { -+ badv = env->CSR_BADV; -+ } -+ -+ if ((badv >> 63) & 0x1) { -+ return env->CSR_PGDH; -+ } else { -+ return env->CSR_PGDL; -+ } -+} -+ -+/* TLB management */ -+static uint64_t ls3a5k_pagesize_to_mask(int pagesize) -+{ -+ /* 4KB - 1GB */ -+ if (pagesize < 12 && pagesize > 30) { -+ printf("[ERROR] unsupported page size %d\n", pagesize); -+ exit(-1); -+ } -+ -+ return (1 << (pagesize + 1)) - 1; -+} -+ -+static void ls3a5k_fill_tlb_entry(CPULOONGARCHState *env, -+ ls3a5k_tlb_t *tlb, int is_ftlb) -+{ -+ uint64_t page_mask; /* 0000...00001111...1111 */ -+ uint32_t page_size; -+ uint64_t entryhi; -+ uint64_t lo0, lo1; -+ -+ if (env->CSR_TLBRERA & 0x1) { -+ page_size = env->CSR_TLBREHI & 0x3f; -+ entryhi = env->CSR_TLBREHI; -+ lo0 = env->CSR_TLBRELO0; -+ lo1 = env->CSR_TLBRELO1; -+ } else { -+ page_size = (env->CSR_TLBIDX >> CSR_TLBIDX_PS_SHIFT) & 0x3f; -+ entryhi = env->CSR_TLBEHI; -+ lo0 = env->CSR_TLBELO0; -+ lo1 = env->CSR_TLBELO1; -+ } -+ -+ if (page_size == 0) { -+ printf("Warning: page_size is 0\n"); -+ } -+ -+ /* 15-12 11-8 7-4 3-0 -+ * 4KB: 0001 1111 1111 1111 // double 4KB mask [12:0] -+ * 16KB: 0111 1111 1111 1111 // double 16KB mask [14:0] -+ */ -+ if (is_ftlb) { -+ page_mask = env->tlb->mmu.ls3a5k.ftlb_mask; -+ } else { -+ page_mask = ls3a5k_pagesize_to_mask(page_size); -+ } -+ -+ tlb->VPN = entryhi & 0xffffffffe000 & ~page_mask; -+ -+ tlb->ASID = env->CSR_ASID & 0x3ff; /* CSR_ASID[9:0] */ -+ tlb->EHINV = 0; -+ tlb->G = (lo0 >> CSR_TLBLO0_GLOBAL_SHIFT) & /* CSR_TLBLO[6] */ -+ (lo1 >> CSR_TLBLO1_GLOBAL_SHIFT) & 1; -+ -+ tlb->PageMask = page_mask; -+ tlb->PageSize = page_size; -+ -+ tlb->V0 = (lo0 >> CSR_TLBLO0_V_SHIFT) & 0x1; /* [0] */ -+ tlb->WE0 = (lo0 >> CSR_TLBLO0_WE_SHIFT) & 0x1; /* [1] */ -+ tlb->PLV0 = (lo0 >> CSR_TLBLO0_PLV_SHIFT) & 0x3; /* [3:2] */ -+ tlb->C0 = (lo0 >> CSR_TLBLO0_CCA_SHIFT) & 0x3; /* [5:4] */ -+ tlb->PPN0 = (lo0 & 0xfffffffff000 & ~(page_mask >> 1)); -+ tlb->RI0 = (lo0 >> CSR_TLBLO0_RI_SHIFT) & 0x1; /* [61] */ -+ tlb->XI0 = (lo0 >> CSR_TLBLO0_XI_SHIFT) & 0x1; /* [62] */ -+ tlb->RPLV0 = (lo0 >> CSR_TLBLO0_RPLV_SHIFT) & 0x1; /* [63] */ -+ -+ tlb->V1 = (lo1 >> CSR_TLBLO1_V_SHIFT) & 0x1; /* [0] */ -+ tlb->WE1 = (lo1 >> CSR_TLBLO1_WE_SHIFT) & 0x1; /* [1] */ -+ tlb->PLV1 = (lo1 >> CSR_TLBLO1_PLV_SHIFT) & 0x3; /* [3:2] */ -+ tlb->C1 = (lo1 >> CSR_TLBLO1_CCA_SHIFT) & 0x3; /* [5:4] */ -+ tlb->PPN1 = (lo1 & 0xfffffffff000 & ~(page_mask >> 1)); -+ tlb->RI1 = (lo1 >> CSR_TLBLO1_RI_SHIFT) & 0x1; /* [61] */ -+ tlb->XI1 = (lo1 >> CSR_TLBLO1_XI_SHIFT) & 0x1; /* [62] */ -+ tlb->RPLV1 = (lo1 >> CSR_TLBLO1_RPLV_SHIFT) & 0x1; /* [63] */ -+} -+ -+static void ls3a5k_fill_tlb(CPULOONGARCHState *env, int idx, bool tlbwr) -+{ -+ ls3a5k_tlb_t *tlb; -+ -+ tlb = &env->tlb->mmu.ls3a5k.tlb[idx]; -+ if (tlbwr) { -+ if ((env->CSR_TLBIDX >> CSR_TLBIDX_EHINV_SHIFT) & 0x1) { -+ tlb->EHINV = 1; -+ return; -+ } -+ } -+ -+ if (idx < 2048) { -+ ls3a5k_fill_tlb_entry(env, tlb, 1); -+ } else { -+ ls3a5k_fill_tlb_entry(env, tlb, 0); -+ } -+} -+ -+void ls3a5k_flush_vtlb(CPULOONGARCHState *env) -+{ -+ uint32_t ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ uint32_t vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; -+ int i; -+ -+ ls3a5k_tlb_t *tlb; -+ -+ for (i = ftlb_size; i < ftlb_size + vtlb_size; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ tlb->EHINV = 1; -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+void ls3a5k_flush_ftlb(CPULOONGARCHState *env) -+{ -+ uint32_t ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ int i; -+ -+ ls3a5k_tlb_t *tlb; -+ -+ for (i = 0; i < ftlb_size; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ tlb->EHINV = 1; -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+void ls3a5k_helper_tlbclr(CPULOONGARCHState *env) -+{ -+ int i; -+ uint16_t asid; -+ int vsize, fsize, index; -+ int start = 0, end = -1; -+ -+ asid = env->CSR_ASID & 0x3ff; -+ vsize = env->tlb->mmu.ls3a5k.vtlb_size; -+ fsize = env->tlb->mmu.ls3a5k.ftlb_size; -+ index = env->CSR_TLBIDX & CSR_TLBIDX_IDX; -+ -+ if (index < fsize) { -+ /* FTLB. One line per operation */ -+ int set = index % 256; -+ start = set * 8; -+ end = start + 7; -+ } else if (index < (fsize + vsize)) { -+ /* VTLB. All entries */ -+ start = fsize; -+ end = fsize + vsize - 1; -+ } else { -+ /* Ignore */ -+ } -+ -+ for (i = start; i <= end; i++) { -+ ls3a5k_tlb_t *tlb; -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ if (!tlb->G && tlb->ASID == asid) { -+ tlb->EHINV = 1; -+ } -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+void ls3a5k_helper_tlbflush(CPULOONGARCHState *env) -+{ -+ int i; -+ int vsize, fsize, index; -+ int start = 0, end = -1; -+ -+ vsize = env->tlb->mmu.ls3a5k.vtlb_size; -+ fsize = env->tlb->mmu.ls3a5k.ftlb_size; -+ index = env->CSR_TLBIDX & CSR_TLBIDX_IDX; -+ -+ if (index < fsize) { -+ /* FTLB. One line per operation */ -+ int set = index % 256; -+ start = set * 8; -+ end = start + 7; -+ } else if (index < (fsize + vsize)) { -+ /* VTLB. All entries */ -+ start = fsize; -+ end = fsize + vsize - 1; -+ } else { -+ /* Ignore */ -+ } -+ -+ for (i = start; i <= end; i++) { -+ env->tlb->mmu.ls3a5k.tlb[i].EHINV = 1; -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+void ls3a5k_helper_invtlb(CPULOONGARCHState *env, target_ulong addr, -+ target_ulong info, int op) -+{ -+ uint32_t asid = info & 0x3ff; -+ int i; -+ -+ switch (op) { -+ case 0: -+ case 1: -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ env->tlb->mmu.ls3a5k.tlb[i].EHINV = 1; -+ } -+ break; -+ case 4: { -+ int i; -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ struct ls3a5k_tlb_t *tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ -+ if (!tlb->G && tlb->ASID == asid) { -+ tlb->EHINV = 1; -+ } -+ } -+ break; -+ } -+ -+ case 5: { -+ int i; -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ struct ls3a5k_tlb_t *tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ uint64_t vpn = addr & 0xffffffffe000 & ~tlb->PageMask; -+ -+ if (!tlb->G && tlb->ASID == asid && vpn == tlb->VPN) { -+ tlb->EHINV = 1; -+ } -+ } -+ break; -+ } -+ case 6: { -+ int i; -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ struct ls3a5k_tlb_t *tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ uint64_t vpn = addr & 0xffffffffe000 & ~tlb->PageMask; -+ -+ if ((tlb->G || tlb->ASID == asid) && vpn == tlb->VPN) { -+ tlb->EHINV = 1; -+ } -+ } -+ break; -+ } -+ default: -+ helper_raise_exception(env, EXCP_RI); -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+static void ls3a5k_invalidate_tlb_entry(CPULOONGARCHState *env, -+ ls3a5k_tlb_t *tlb) -+{ -+ LOONGARCHCPU *cpu = loongarch_env_get_cpu(env); -+ CPUState *cs = CPU(cpu); -+ target_ulong addr; -+ target_ulong end; -+ target_ulong mask; -+ -+ mask = tlb->PageMask; /* 000...000111...111 */ -+ -+ if (tlb->V0) { -+ addr = tlb->VPN & ~mask; /* xxx...xxx[0]000..0000 */ -+ end = addr | (mask >> 1); /* xxx...xxx[0]111..1111 */ -+ while (addr < end) { -+ tlb_flush_page(cs, addr); -+ addr += TARGET_PAGE_SIZE; -+ } -+ } -+ -+ if (tlb->V1) { -+ /* xxx...xxx[1]000..0000 */ -+ addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); -+ end = addr | mask; /* xxx...xxx[1]111..1111 */ -+ while (addr - 1 < end) { -+ tlb_flush_page(cs, addr); -+ addr += TARGET_PAGE_SIZE; -+ } -+ } -+} -+ -+void ls3a5k_invalidate_tlb(CPULOONGARCHState *env, int idx) -+{ -+ ls3a5k_tlb_t *tlb; -+ int asid = env->CSR_ASID & 0x3ff; -+ tlb = &env->tlb->mmu.ls3a5k.tlb[idx]; -+ if (tlb->G == 0 && tlb->ASID != asid) { -+ return; -+ } -+ ls3a5k_invalidate_tlb_entry(env, tlb); -+} -+ -+void ls3a5k_helper_tlbwr(CPULOONGARCHState *env) -+{ -+ int idx = env->CSR_TLBIDX & CSR_TLBIDX_IDX; /* [11:0] */ -+ -+ /* Convert idx if in FTLB */ -+ if (idx < env->tlb->mmu.ls3a5k.ftlb_size) { -+ /* -+ * 0 3 6 0 1 2 -+ * 1 4 7 => 3 4 5 -+ * 2 5 8 6 7 8 -+ */ -+ int set = idx % 256; -+ int way = idx / 256; -+ idx = set * 8 + way; -+ } -+ ls3a5k_invalidate_tlb(env, idx); -+ ls3a5k_fill_tlb(env, idx, true); -+} -+ -+void ls3a5k_helper_tlbfill(CPULOONGARCHState *env) -+{ -+ uint64_t mask; -+ uint64_t address; -+ int idx; -+ int set, ftlb_idx; -+ -+ uint64_t entryhi; -+ uint32_t pagesize; -+ -+ if (env->CSR_TLBRERA & 0x1) { -+ entryhi = env->CSR_TLBREHI & ~0x3f; -+ pagesize = env->CSR_TLBREHI & 0x3f; -+ } else { -+ entryhi = env->CSR_TLBEHI; -+ pagesize = (env->CSR_TLBIDX >> CSR_TLBIDX_PS_SHIFT) & 0x3f; -+ } -+ -+ uint32_t ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ uint32_t vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; -+ -+ mask = ls3a5k_pagesize_to_mask(pagesize); -+ -+ if (mask == env->tlb->mmu.ls3a5k.ftlb_mask && -+ env->tlb->mmu.ls3a5k.ftlb_size > 0) { -+ /* only write into FTLB */ -+ address = entryhi & 0xffffffffe000; /* [47:13] */ -+ -+ /* choose one set ramdomly */ -+ set = cpu_loongarch_get_random_ls3a5k_tlb(0, 7); -+ -+ /* index in one set */ -+ ftlb_idx = (address >> 15) & 0xff; /* [0,255] */ -+ -+ /* final idx */ -+ idx = ftlb_idx * 8 + set; /* max is 7 + 8 * 255 = 2047 */ -+ } else { -+ /* only write into VTLB */ -+ int wired_nr = env->CSR_TLBWIRED & 0x3f; -+ idx = cpu_loongarch_get_random_ls3a5k_tlb( -+ ftlb_size + wired_nr, ftlb_size + vtlb_size - 1); -+ } -+ -+ ls3a5k_invalidate_tlb(env, idx); -+ ls3a5k_fill_tlb(env, idx, false); -+} -+ -+void ls3a5k_helper_tlbsrch(CPULOONGARCHState *env) -+{ -+ uint64_t mask; -+ uint64_t vpn; -+ uint64_t tag; -+ uint16_t asid; -+ -+ int ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ int vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; -+ int i; -+ int ftlb_idx; /* [0,255] 2^8 0xff */ -+ -+ ls3a5k_tlb_t *tlb; -+ -+ asid = env->CSR_ASID & 0x3ff; -+ -+ /* search VTLB */ -+ for (i = ftlb_size; i < ftlb_size + vtlb_size; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ mask = tlb->PageMask; -+ -+ vpn = env->CSR_TLBEHI & 0xffffffffe000 & ~mask; -+ tag = tlb->VPN & ~mask; -+ -+ if ((tlb->G == 1 || tlb->ASID == asid) && vpn == tag && tlb->EHINV != 1) -+ { -+ env->CSR_TLBIDX = (i & 0xfff) | -+ ((tlb->PageSize & 0x3f) << CSR_TLBIDX_PS_SHIFT); -+ goto _MATCH_OUT_; -+ } -+ } -+ -+ if (ftlb_size == 0) { -+ goto _NO_MATCH_OUT_; -+ } -+ -+ /* search FTLB */ -+ mask = env->tlb->mmu.ls3a5k.ftlb_mask; -+ vpn = env->CSR_TLBEHI & 0xffffffffe000 & ~mask; -+ -+ ftlb_idx = (env->CSR_TLBEHI & 0xffffffffe000) >> 15; /* 16 KB */ -+ ftlb_idx = ftlb_idx & 0xff; /* [0,255] */ -+ -+ for (i = 0; i < 8; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[ftlb_idx * 8 + i]; -+ tag = tlb->VPN & ~mask; -+ -+ if ((tlb->G == 1 || tlb->ASID == asid) && vpn == tag && tlb->EHINV != 1) -+ { -+ env->CSR_TLBIDX = ((i * 256 + ftlb_idx) & 0xfff) | -+ ((tlb->PageSize & 0x3f) << CSR_TLBIDX_PS_SHIFT); -+ goto _MATCH_OUT_; -+ } -+ } -+ -+_NO_MATCH_OUT_: -+ env->CSR_TLBIDX = 1 << CSR_TLBIDX_EHINV_SHIFT; -+_MATCH_OUT_: -+ return; -+} -+ -+void ls3a5k_helper_tlbrd(CPULOONGARCHState *env) -+{ -+ ls3a5k_tlb_t *tlb; -+ int idx; -+ uint16_t asid; -+ -+ idx = env->CSR_TLBIDX & CSR_TLBIDX_IDX; -+ if (idx < env->tlb->mmu.ls3a5k.ftlb_size) { -+ int set = idx % 256; -+ int way = idx / 256; -+ idx = set * 8 + way; -+ } -+ -+ tlb = &env->tlb->mmu.ls3a5k.tlb[idx]; -+ -+ asid = env->CSR_ASID & 0x3ff; -+ -+ if (asid != tlb->ASID) { -+ cpu_loongarch_tlb_flush(env); -+ } -+ -+ if (tlb->EHINV) { -+ /* invalid TLB entry */ -+ env->CSR_TLBIDX = 1 << CSR_TLBIDX_EHINV_SHIFT; -+ env->CSR_TLBEHI = 0; -+ env->CSR_TLBELO0 = 0; -+ env->CSR_TLBELO1 = 0; -+ } else { -+ /* valid TLB entry */ -+ env->CSR_TLBIDX = (env->CSR_TLBIDX & 0xfff) | -+ ((tlb->PageSize & 0x3f) << CSR_TLBIDX_PS_SHIFT); -+ env->CSR_TLBEHI = tlb->VPN; -+ env->CSR_TLBELO0 = (tlb->V0 << CSR_TLBLO0_V_SHIFT) | -+ (tlb->WE0 << CSR_TLBLO0_WE_SHIFT) | -+ (tlb->PLV0 << CSR_TLBLO0_PLV_SHIFT) | -+ (tlb->C0 << CSR_TLBLO0_CCA_SHIFT) | -+ (tlb->G << CSR_TLBLO0_GLOBAL_SHIFT) | -+ (tlb->PPN0 & 0xfffffffff000) | -+ ((uint64_t)tlb->RI0 << CSR_TLBLO0_RI_SHIFT) | -+ ((uint64_t)tlb->XI0 << CSR_TLBLO0_XI_SHIFT) | -+ ((uint64_t)tlb->RPLV0 << CSR_TLBLO0_RPLV_SHIFT); -+ env->CSR_TLBELO1 = (tlb->V1 << CSR_TLBLO1_V_SHIFT) | -+ (tlb->WE1 << CSR_TLBLO1_WE_SHIFT) | -+ (tlb->PLV1 << CSR_TLBLO1_PLV_SHIFT) | -+ (tlb->C1 << CSR_TLBLO1_CCA_SHIFT) | -+ (tlb->G << CSR_TLBLO0_GLOBAL_SHIFT) | -+ (tlb->PPN1 & 0xfffffffff000) | -+ ((uint64_t)tlb->RI1 << CSR_TLBLO1_RI_SHIFT) | -+ ((uint64_t)tlb->XI1 << CSR_TLBLO1_XI_SHIFT) | -+ ((uint64_t)tlb->RPLV1 << CSR_TLBLO1_RPLV_SHIFT); -+ env->CSR_ASID = (tlb->ASID << CSR_ASID_ASID_SHIFT) | -+ (env->CSR_ASID & 0xff0000); -+ } -+} -+ -+void helper_tlbwr(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbwr(env); -+} -+ -+void helper_tlbfill(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbfill(env); -+} -+ -+void helper_tlbsrch(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbsrch(env); -+} -+ -+void helper_tlbrd(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbrd(env); -+} -+ -+void helper_tlbclr(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbclr(env); -+} -+ -+void helper_tlbflush(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbflush(env); -+} -+ -+void helper_invtlb(CPULOONGARCHState *env, target_ulong addr, target_ulong info, -+ target_ulong op) -+{ -+ env->tlb->helper_invtlb(env, addr, info, op); -+} -+ -+static void ls3a5k_mmu_init(CPULOONGARCHState *env, const loongarch_def_t *def) -+{ -+ /* number of VTLB */ -+ env->tlb->nb_tlb = 64; -+ env->tlb->mmu.ls3a5k.vtlb_size = 64; -+ -+ /* number of FTLB */ -+ env->tlb->nb_tlb += 2048; -+ env->tlb->mmu.ls3a5k.ftlb_size = 2048; -+ env->tlb->mmu.ls3a5k.ftlb_mask = (1 << 15) - 1; /* 16 KB */ -+ /* -+ * page_size | ftlb_mask | party field -+ * ---------------------------------------------------------------- -+ * 4 KB = 12 | ( 1 << 13 ) - 1 = [12:0] | [12] -+ * 16 KB = 14 | ( 1 << 15 ) - 1 = [14:0] | [14] -+ * 64 KB = 16 | ( 1 << 17 ) - 1 = [16:0] | [16] -+ * 256 KB = 18 | ( 1 << 19 ) - 1 = [18:0] | [18] -+ * 1 MB = 20 | ( 1 << 21 ) - 1 = [20:0] | [20] -+ * 4 MB = 22 | ( 1 << 23 ) - 1 = [22:0] | [22] -+ * 16 MB = 24 | ( 1 << 25 ) - 1 = [24:0] | [24] -+ * 64 MB = 26 | ( 1 << 27 ) - 1 = [26:0] | [26] -+ * 256 MB = 28 | ( 1 << 29 ) - 1 = [28:0] | [28] -+ * 1 GB = 30 | ( 1 << 31 ) - 1 = [30:0] | [30] -+ * ---------------------------------------------------------------- -+ * take party field index as @n. eg. For 16 KB, n = 14 -+ * ---------------------------------------------------------------- -+ * tlb->VPN = TLBEHI & 0xffffffffe000[47:13] & ~mask = [47:n+1] -+ * tlb->PPN = TLBLO0 & 0xffffffffe000[47:13] & ~mask = [47:n+1] -+ * tlb->PPN = TLBLO1 & 0xffffffffe000[47:13] & ~mask = [47:n+1] -+ * ---------------------------------------------------------------- -+ * On mapping : -+ * > vpn = address & 0xffffffffe000[47:13] & ~mask = [47:n+1] -+ * > tag = tlb->VPN & ~mask = [47:n+1] -+ * ---------------------------------------------------------------- -+ * physical address = [47:n+1] | [n:0] -+ * physical address = tlb->PPN0 | (address & mask) -+ * physical address = tlb->PPN1 | (address & mask) -+ */ -+ -+ int i; -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ env->tlb->mmu.ls3a5k.tlb[i].EHINV = 1; -+ } -+ -+ /* TLB's helper functions */ -+ env->tlb->map_address = &ls3a5k_map_address; -+ env->tlb->helper_tlbwr = ls3a5k_helper_tlbwr; -+ env->tlb->helper_tlbfill = ls3a5k_helper_tlbfill; -+ env->tlb->helper_tlbsrch = ls3a5k_helper_tlbsrch; -+ env->tlb->helper_tlbrd = ls3a5k_helper_tlbrd; -+ env->tlb->helper_tlbclr = ls3a5k_helper_tlbclr; -+ env->tlb->helper_tlbflush = ls3a5k_helper_tlbflush; -+ env->tlb->helper_invtlb = ls3a5k_helper_invtlb; -+} -+ -+void mmu_init(CPULOONGARCHState *env, const loongarch_def_t *def) -+{ -+ env->tlb = g_malloc0(sizeof(CPULOONGARCHTLBContext)); -+ -+ switch (def->mmu_type) { -+ case MMU_TYPE_LS3A5K: -+ ls3a5k_mmu_init(env, def); -+ break; -+ default: -+ cpu_abort(CPU(loongarch_env_get_cpu(env)), "MMU type not supported\n"); -+ } -+} -+#endif /* !CONFIG_USER_ONLY */ -diff --git a/target/loongarch64/trace-events b/target/loongarch64/trace-events -new file mode 100644 -index 000000000..e0bca4f82 ---- /dev/null -+++ b/target/loongarch64/trace-events -@@ -0,0 +1,3 @@ -+# See docs/devel/tracing.txt for syntax documentation. -+ -+# target/loongarch/translate.c -diff --git a/target/loongarch64/trans.inc.c b/target/loongarch64/trans.inc.c -new file mode 100644 -index 000000000..e50670be4 ---- /dev/null -+++ b/target/loongarch64/trans.inc.c -@@ -0,0 +1,3472 @@ -+static bool trans_syscall(DisasContext *ctx, arg_syscall *a) -+{ -+ generate_exception_end(ctx, EXCP_SYSCALL); -+ return true; -+} -+ -+static bool trans_break(DisasContext *ctx, arg_break *a) -+{ -+ generate_exception_end(ctx, EXCP_BREAK); -+ return true; -+} -+ -+static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) -+{ -+ /* -+ * dbcl instruction is not support in tcg -+ */ -+ generate_exception_end(ctx, EXCP_RI); -+ return true; -+} -+ -+static bool trans_addi_w(DisasContext *ctx, arg_addi_w *a) -+{ -+ gen_arith_imm(ctx, OPC_LARCH_ADDI_W, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_addi_d(DisasContext *ctx, arg_addi_d *a) -+{ -+ gen_arith_imm(ctx, OPC_LARCH_ADDI_D, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_slli_d(DisasContext *ctx, arg_slli_d *a) -+{ -+ if (a->rd == 0) { -+ /* Nop */ -+ return true; -+ } -+ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_shli_tl(cpu_gpr[a->rd], t0, a->ui6); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_andi(DisasContext *ctx, arg_andi *a) -+{ -+ gen_logic_imm(ctx, OPC_LARCH_ANDI, a->rd, a->rj, a->ui12); -+ return true; -+} -+ -+static bool trans_srli_d(DisasContext *ctx, arg_srli_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_shri_tl(cpu_gpr[a->rd], t0, a->ui6); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_slli_w(DisasContext *ctx, arg_slli_w *a) -+{ -+ if (a->rd == 0) { -+ /* Nop */ -+ return true; -+ } -+ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_shli_tl(t0, t0, a->ui5); -+ tcg_gen_ext32s_tl(cpu_gpr[a->rd], t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) -+{ -+ if (a->rj != 0) { -+ tcg_gen_addi_tl(cpu_gpr[a->rd], cpu_gpr[a->rj], a->si16 << 16); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->si16 << 16); -+ } -+ return true; -+} -+ -+static bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a) -+{ -+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->si20 << 12); -+ return true; -+} -+ -+static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) -+{ -+ TCGv_i64 t0, t1; -+ t0 = tcg_temp_new_i64(); -+ t1 = tcg_temp_new_i64(); -+ -+ tcg_gen_movi_tl(t0, a->si20); -+ tcg_gen_concat_tl_i64(t1, cpu_gpr[a->rd], t0); -+ gen_store_gpr(t1, a->rd); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_pcaddi(DisasContext *ctx, arg_pcaddi *a) -+{ -+ target_ulong pc = ctx->base.pc_next; -+ target_ulong addr = pc + (a->si20 << 2); -+ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); -+ return true; -+} -+ -+static bool trans_pcalau12i(DisasContext *ctx, arg_pcalau12i *a) -+{ -+ target_ulong pc = ctx->base.pc_next; -+ target_ulong addr = (pc + (a->si20 << 12)) & ~0xfff; -+ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); -+ return true; -+} -+ -+static bool trans_pcaddu12i(DisasContext *ctx, arg_pcaddu12i *a) -+{ -+ target_ulong pc = ctx->base.pc_next; -+ target_ulong addr = pc + (a->si20 << 12); -+ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); -+ return true; -+} -+ -+static bool trans_pcaddu18i(DisasContext *ctx, arg_pcaddu18i *a) -+{ -+ target_ulong pc = ctx->base.pc_next; -+ target_ulong addr = pc + ((target_ulong)(a->si20) << 18); -+ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); -+ return true; -+} -+ -+static bool trans_slti(DisasContext *ctx, arg_slti *a) -+{ -+ gen_slt_imm(ctx, OPC_LARCH_SLTI, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_sltui(DisasContext *ctx, arg_sltui *a) -+{ -+ gen_slt_imm(ctx, OPC_LARCH_SLTIU, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ gen_load_gpr(t1, a->rj); -+ -+ tcg_gen_movi_tl(t0, a->si12); -+ tcg_gen_shli_tl(t0, t0, 52); -+ tcg_gen_andi_tl(t1, t1, 0xfffffffffffffU); -+ tcg_gen_or_tl(cpu_gpr[a->rd], t0, t1); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ori(DisasContext *ctx, arg_ori *a) -+{ -+ gen_logic_imm(ctx, OPC_LARCH_ORI, a->rd, a->rj, a->ui12); -+ return true; -+} -+ -+static bool trans_xori(DisasContext *ctx, arg_xori *a) -+{ -+ gen_logic_imm(ctx, OPC_LARCH_XORI, a->rd, a->rj, a->ui12); -+ return true; -+} -+ -+static bool trans_bstrins_d(DisasContext *ctx, arg_bstrins_d *a) -+{ -+ int lsb = a->lsbd; -+ int msb = a->msbd; -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ if (lsb > msb) { -+ return false; -+ } -+ -+ gen_load_gpr(t1, a->rj); -+ gen_load_gpr(t0, a->rd); -+ tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); -+ gen_store_gpr(t0, a->rd); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_bstrpick_d(DisasContext *ctx, arg_bstrpick_d *a) -+{ -+ int lsb = a->lsbd; -+ int msb = a->msbd; -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ if (lsb > msb) { -+ return false; -+ } -+ -+ gen_load_gpr(t1, a->rj); -+ gen_load_gpr(t0, a->rd); -+ tcg_gen_extract_tl(t0, t1, lsb, msb - lsb + 1); -+ gen_store_gpr(t0, a->rd); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_bstrins_w(DisasContext *ctx, arg_bstrins_w *a) -+{ -+ gen_bitops(ctx, OPC_LARCH_TRINS_W, a->rd, a->rj, a->lsbw, a->msbw); -+ return true; -+} -+ -+static bool trans_bstrpick_w(DisasContext *ctx, arg_bstrpick_w *a) -+{ -+ if (a->lsbw > a->msbw) { -+ return false; -+ } -+ gen_bitops(ctx, OPC_LARCH_TRPICK_W, -+ a->rd, a->rj, a->lsbw, a->msbw - a->lsbw); -+ return true; -+} -+ -+static bool trans_ldptr_w(DisasContext *ctx, arg_ldptr_w *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LDPTR_W, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_stptr_w(DisasContext *ctx, arg_stptr_w *a) -+{ -+ gen_st(ctx, OPC_LARCH_STPTR_W, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_ldptr_d(DisasContext *ctx, arg_ldptr_d *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LDPTR_D, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_stptr_d(DisasContext *ctx, arg_stptr_d *a) -+{ -+ gen_st(ctx, OPC_LARCH_STPTR_D, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_ld_b(DisasContext *ctx, arg_ld_b *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_B, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_h(DisasContext *ctx, arg_ld_h *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_H, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_w(DisasContext *ctx, arg_ld_w *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_W, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_d(DisasContext *ctx, arg_ld_d *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_D, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_st_b(DisasContext *ctx, arg_st_b *a) -+{ -+ gen_st(ctx, OPC_LARCH_ST_B, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_st_h(DisasContext *ctx, arg_st_h *a) -+{ -+ gen_st(ctx, OPC_LARCH_ST_H, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_st_w(DisasContext *ctx, arg_st_w *a) -+{ -+ gen_st(ctx, OPC_LARCH_ST_W, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_st_d(DisasContext *ctx, arg_st_d *a) -+{ -+ gen_st(ctx, OPC_LARCH_ST_D, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_bu(DisasContext *ctx, arg_ld_bu *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_BU, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_hu(DisasContext *ctx, arg_ld_hu *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_HU, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_wu(DisasContext *ctx, arg_ld_wu *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_WU, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_preld(DisasContext *ctx, arg_preld *a) -+{ -+ /* Treat as NOP. */ -+ return true; -+} -+ -+static bool trans_ll_w(DisasContext *ctx, arg_ll_w *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LL_W, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a) -+{ -+ gen_st_cond(ctx, a->rd, a->rj, a->si14 << 2, MO_TESL, false); -+ return true; -+} -+ -+static bool trans_ll_d(DisasContext *ctx, arg_ll_d *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LL_D, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a) -+{ -+ gen_st_cond(ctx, a->rd, a->rj, a->si14 << 2, MO_TEQ, false); -+ return true; -+} -+ -+static bool trans_fld_s(DisasContext *ctx, arg_fld_s *a) -+{ -+ gen_fp_ldst(ctx, OPC_LARCH_FLD_S, a->fd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_fst_s(DisasContext *ctx, arg_fst_s *a) -+{ -+ gen_fp_ldst(ctx, OPC_LARCH_FST_S, a->fd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_fld_d(DisasContext *ctx, arg_fld_d *a) -+{ -+ gen_fp_ldst(ctx, OPC_LARCH_FLD_D, a->fd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_fst_d(DisasContext *ctx, arg_fst_d *a) -+{ -+ gen_fp_ldst(ctx, OPC_LARCH_FST_D, a->fd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ldx_b(DisasContext *ctx, arg_ldx_b *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_SB); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_h(DisasContext *ctx, arg_ldx_h *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TESW | ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_w(DisasContext *ctx, arg_ldx_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TESL | ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_ldx_d(DisasContext *ctx, arg_ldx_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEQ | ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_stx_b(DisasContext *ctx, arg_stx_b *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ gen_load_gpr(t1, a->rd); -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_8); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_stx_h(DisasContext *ctx, arg_stx_h *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ gen_load_gpr(t1, a->rd); -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUW | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_stx_w(DisasContext *ctx, arg_stx_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ gen_load_gpr(t1, a->rd); -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_stx_d(DisasContext *ctx, arg_stx_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ gen_load_gpr(t1, a->rd); -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_bu(DisasContext *ctx, arg_ldx_bu *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_hu(DisasContext *ctx, arg_ldx_hu *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEUW | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_wu(DisasContext *ctx, arg_ldx_wu *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_fldx_s(DisasContext *ctx, arg_fldx_s *a) -+{ -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDX_S, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fldx_d(DisasContext *ctx, arg_fldx_d *a) -+{ -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDX_D, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstx_s(DisasContext *ctx, arg_fstx_s *a) -+{ -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTX_S, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstx_d(DisasContext *ctx, arg_fstx_d *a) -+{ -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTX_D, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+#define TRANS_AM_W(name, op) \ -+static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ -+{ \ -+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ -+ printf("%s: warning, register equal\n", __func__); \ -+ return false; \ -+ } \ -+ int mem_idx = ctx->mem_idx; \ -+ TCGv addr = tcg_temp_new(); \ -+ TCGv val = tcg_temp_new(); \ -+ TCGv ret = tcg_temp_new(); \ -+\ -+ gen_load_gpr(addr, a->rj); \ -+ gen_load_gpr(val, a->rk); \ -+ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TESL | \ -+ ctx->default_tcg_memop_mask); \ -+ gen_store_gpr(ret, a->rd); \ -+\ -+ tcg_temp_free(addr); \ -+ tcg_temp_free(val); \ -+ tcg_temp_free(ret); \ -+ return true; \ -+} -+#define TRANS_AM_D(name, op) \ -+static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ -+{ \ -+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ -+ printf("%s: warning, register equal\n", __func__); \ -+ return false; \ -+ } \ -+ int mem_idx = ctx->mem_idx; \ -+ TCGv addr = tcg_temp_new(); \ -+ TCGv val = tcg_temp_new(); \ -+ TCGv ret = tcg_temp_new(); \ -+\ -+ gen_load_gpr(addr, a->rj); \ -+ gen_load_gpr(val, a->rk); \ -+ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TEQ | \ -+ ctx->default_tcg_memop_mask); \ -+ gen_store_gpr(ret, a->rd); \ -+\ -+ tcg_temp_free(addr); \ -+ tcg_temp_free(val); \ -+ tcg_temp_free(ret); \ -+ return true; \ -+} -+#define TRANS_AM(name, op) \ -+ TRANS_AM_W(name##_w, op) \ -+ TRANS_AM_D(name##_d, op) -+TRANS_AM(amswap, xchg) /* trans_amswap_w, trans_amswap_d */ -+TRANS_AM(amadd, fetch_add) /* trans_amadd_w, trans_amadd_d */ -+TRANS_AM(amand, fetch_and) /* trans_amand_w, trans_amand_d */ -+TRANS_AM(amor, fetch_or) /* trans_amor_w, trans_amor_d */ -+TRANS_AM(amxor, fetch_xor) /* trans_amxor_w, trans_amxor_d */ -+TRANS_AM(ammax, fetch_smax) /* trans_ammax_w, trans_ammax_d */ -+TRANS_AM(ammin, fetch_smin) /* trans_ammin_w, trans_ammin_d */ -+TRANS_AM_W(ammax_wu, fetch_umax) /* trans_ammax_wu */ -+TRANS_AM_D(ammax_du, fetch_umax) /* trans_ammax_du */ -+TRANS_AM_W(ammin_wu, fetch_umin) /* trans_ammin_wu */ -+TRANS_AM_D(ammin_du, fetch_umin) /* trans_ammin_du */ -+#undef TRANS_AM -+#undef TRANS_AM_W -+#undef TRANS_AM_D -+ -+#define TRANS_AM_DB_W(name, op) \ -+static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ -+{ \ -+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ -+ printf("%s: warning, register equal\n", __func__); \ -+ return false; \ -+ } \ -+ int mem_idx = ctx->mem_idx; \ -+ TCGv addr = tcg_temp_new(); \ -+ TCGv val = tcg_temp_new(); \ -+ TCGv ret = tcg_temp_new(); \ -+\ -+ gen_sync(0x10); /* TCG_MO_ALL */ \ -+ gen_load_gpr(addr, a->rj); \ -+ gen_load_gpr(val, a->rk); \ -+ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TESL | \ -+ ctx->default_tcg_memop_mask); \ -+ gen_store_gpr(ret, a->rd); \ -+\ -+ tcg_temp_free(addr); \ -+ tcg_temp_free(val); \ -+ tcg_temp_free(ret); \ -+ return true; \ -+} -+#define TRANS_AM_DB_D(name, op) \ -+static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ -+{ \ -+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ -+ printf("%s: warning, register equal\n", __func__); \ -+ return false; \ -+ } \ -+ int mem_idx = ctx->mem_idx; \ -+ TCGv addr = tcg_temp_new(); \ -+ TCGv val = tcg_temp_new(); \ -+ TCGv ret = tcg_temp_new(); \ -+\ -+ gen_sync(0x10); /* TCG_MO_ALL */ \ -+ gen_load_gpr(addr, a->rj); \ -+ gen_load_gpr(val, a->rk); \ -+ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TEQ | \ -+ ctx->default_tcg_memop_mask); \ -+ gen_store_gpr(ret, a->rd); \ -+\ -+ tcg_temp_free(addr); \ -+ tcg_temp_free(val); \ -+ tcg_temp_free(ret); \ -+ return true; \ -+} -+#define TRANS_AM_DB(name, op) \ -+ TRANS_AM_DB_W(name##_db_w, op) \ -+ TRANS_AM_DB_D(name##_db_d, op) -+TRANS_AM_DB(amswap, xchg) /* trans_amswap_db_w, trans_amswap_db_d */ -+TRANS_AM_DB(amadd, fetch_add) /* trans_amadd_db_w, trans_amadd_db_d */ -+TRANS_AM_DB(amand, fetch_and) /* trans_amand_db_w, trans_amand_db_d */ -+TRANS_AM_DB(amor, fetch_or) /* trans_amor_db_w, trans_amor_db_d */ -+TRANS_AM_DB(amxor, fetch_xor) /* trans_amxor_db_w, trans_amxor_db_d */ -+TRANS_AM_DB(ammax, fetch_smax) /* trans_ammax_db_w, trans_ammax_db_d */ -+TRANS_AM_DB(ammin, fetch_smin) /* trans_ammin_db_w, trans_ammin_db_d */ -+TRANS_AM_DB_W(ammax_db_wu, fetch_umax) /* trans_ammax_db_wu */ -+TRANS_AM_DB_D(ammax_db_du, fetch_umax) /* trans_ammax_db_du */ -+TRANS_AM_DB_W(ammin_db_wu, fetch_umin) /* trans_ammin_db_wu */ -+TRANS_AM_DB_D(ammin_db_du, fetch_umin) /* trans_ammin_db_du */ -+#undef TRANS_AM_DB -+#undef TRANS_AM_DB_W -+#undef TRANS_AM_DB_D -+ -+static bool trans_dbar(DisasContext *ctx, arg_dbar * a) -+{ -+ gen_sync(a->whint); -+ return true; -+} -+ -+static bool trans_ibar(DisasContext *ctx, arg_ibar *a) -+{ -+ /* -+ * FENCE_I is a no-op in QEMU, -+ * however we need to end the translation block -+ */ -+ ctx->base.is_jmp = DISAS_STOP; -+ return true; -+} -+ -+#define ASRTGT \ -+do { \ -+ TCGv t1 = tcg_temp_new(); \ -+ TCGv t2 = tcg_temp_new(); \ -+ gen_load_gpr(t1, a->rj); \ -+ gen_load_gpr(t2, a->rk); \ -+ gen_helper_asrtgt_d(cpu_env, t1, t2); \ -+ tcg_temp_free(t1); \ -+ tcg_temp_free(t2); \ -+} while (0) -+ -+#define ASRTLE \ -+do {\ -+ TCGv t1 = tcg_temp_new(); \ -+ TCGv t2 = tcg_temp_new(); \ -+ gen_load_gpr(t1, a->rj); \ -+ gen_load_gpr(t2, a->rk); \ -+ gen_helper_asrtle_d(cpu_env, t1, t2); \ -+ tcg_temp_free(t1); \ -+ tcg_temp_free(t2); \ -+} while (0) -+ -+static bool trans_fldgt_s(DisasContext *ctx, arg_fldgt_s *a) -+{ -+ ASRTGT; -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDGT_S, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fldgt_d(DisasContext *ctx, arg_fldgt_d *a) -+{ -+ ASRTGT; -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDGT_D, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fldle_s(DisasContext *ctx, arg_fldle_s *a) -+{ -+ ASRTLE; -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDLE_S, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fldle_d(DisasContext *ctx, arg_fldle_d *a) -+{ -+ ASRTLE; -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDLE_D, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstgt_s(DisasContext *ctx, arg_fstgt_s *a) -+{ -+ ASRTGT; -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTGT_S, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstgt_d(DisasContext *ctx, arg_fstgt_d *a) -+{ -+ ASRTGT; -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTGT_D, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstle_s(DisasContext *ctx, arg_fstle_s *a) -+{ -+ ASRTLE; -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTLE_S, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstle_d(DisasContext *ctx, arg_fstle_d *a) -+{ -+ ASRTLE; -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTLE_D, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+#define DECL_ARG(name) \ -+ arg_ ## name arg = { \ -+ .rd = a->rd, \ -+ .rj = a->rj, \ -+ .rk = a->rk, \ -+ }; -+ -+static bool trans_ldgt_b(DisasContext *ctx, arg_ldgt_b *a) -+{ -+ ASRTGT; -+ DECL_ARG(ldx_b) -+ trans_ldx_b(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldgt_h(DisasContext *ctx, arg_ldgt_h *a) -+{ -+ ASRTGT; -+ DECL_ARG(ldx_h) -+ trans_ldx_h(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldgt_w(DisasContext *ctx, arg_ldgt_w *a) -+{ -+ ASRTGT; -+ DECL_ARG(ldx_w) -+ trans_ldx_w(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldgt_d(DisasContext *ctx, arg_ldgt_d *a) -+{ -+ ASRTGT; -+ DECL_ARG(ldx_d) -+ trans_ldx_d(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldle_b(DisasContext *ctx, arg_ldle_b *a) -+{ -+ ASRTLE; -+ DECL_ARG(ldx_b) -+ trans_ldx_b(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldle_h(DisasContext *ctx, arg_ldle_h *a) -+{ -+ ASRTLE; -+ DECL_ARG(ldx_h) -+ trans_ldx_h(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldle_w(DisasContext *ctx, arg_ldle_w *a) -+{ -+ ASRTLE; -+ DECL_ARG(ldx_w) -+ trans_ldx_w(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldle_d(DisasContext *ctx, arg_ldle_d *a) -+{ -+ ASRTLE; -+ DECL_ARG(ldx_d) -+ trans_ldx_d(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stgt_b(DisasContext *ctx, arg_stgt_b *a) -+{ -+ ASRTGT; -+ DECL_ARG(stx_b) -+ trans_stx_b(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stgt_h(DisasContext *ctx, arg_stgt_h *a) -+{ -+ ASRTGT; -+ DECL_ARG(stx_h) -+ trans_stx_h(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stgt_w(DisasContext *ctx, arg_stgt_w *a) -+{ -+ ASRTGT; -+ DECL_ARG(stx_w) -+ trans_stx_w(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stgt_d(DisasContext *ctx, arg_stgt_d *a) -+{ -+ ASRTGT; -+ DECL_ARG(stx_d) -+ trans_stx_d(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stle_b(DisasContext *ctx, arg_stle_b *a) -+{ -+ ASRTLE; -+ DECL_ARG(stx_b) -+ trans_stx_b(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stle_h(DisasContext *ctx, arg_stle_h *a) -+{ -+ ASRTLE; -+ DECL_ARG(stx_h) -+ trans_stx_h(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stle_w(DisasContext *ctx, arg_stle_w *a) -+{ -+ ASRTLE; -+ DECL_ARG(stx_w) -+ trans_stx_w(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stle_d(DisasContext *ctx, arg_stle_d *a) -+{ -+ ASRTLE; -+ DECL_ARG(stx_d) -+ trans_stx_d(ctx, &arg); -+ return true; -+} -+ -+#undef ASRTGT -+#undef ASRTLE -+#undef DECL_ARG -+ -+static bool trans_beqz(DisasContext *ctx, arg_beqz *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BEQZ, 4, a->rj, 0, a->offs21 << 2); -+ return true; -+} -+ -+static bool trans_bnez(DisasContext *ctx, arg_bnez *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BNEZ, 4, a->rj, 0, a->offs21 << 2); -+ return true; -+} -+ -+static bool trans_bceqz(DisasContext *ctx, arg_bceqz *a) -+{ -+ TCGv_i32 cj = tcg_const_i32(a->cj); -+ TCGv v0 = tcg_temp_new(); -+ TCGv v1 = tcg_const_i64(0); -+ -+ gen_helper_movcf2reg(v0, cpu_env, cj); -+ tcg_gen_setcond_tl(TCG_COND_EQ, bcond, v0, v1); -+ ctx->hflags |= LARCH_HFLAG_BC; -+ ctx->btarget = ctx->base.pc_next + (a->offs21 << 2); -+ -+ tcg_temp_free_i32(cj); -+ tcg_temp_free(v0); -+ tcg_temp_free(v1); -+ return true; -+} -+ -+static bool trans_bcnez(DisasContext *ctx, arg_bcnez *a) -+{ -+ TCGv_i32 cj = tcg_const_i32(a->cj); -+ TCGv v0 = tcg_temp_new(); -+ TCGv v1 = tcg_const_i64(0); -+ -+ gen_helper_movcf2reg(v0, cpu_env, cj); -+ tcg_gen_setcond_tl(TCG_COND_NE, bcond, v0, v1); -+ ctx->hflags |= LARCH_HFLAG_BC; -+ ctx->btarget = ctx->base.pc_next + (a->offs21 << 2); -+ -+ tcg_temp_free_i32(cj); -+ tcg_temp_free(v0); -+ tcg_temp_free(v1); -+ return true; -+} -+ -+static bool trans_b(DisasContext *ctx, arg_b *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_B, 4, 0, 0, a->offs << 2); -+ return true; -+} -+ -+static bool trans_bl(DisasContext *ctx, arg_bl *a) -+{ -+ ctx->btarget = ctx->base.pc_next + (a->offs << 2); -+ tcg_gen_movi_tl(cpu_gpr[1], ctx->base.pc_next + 4); -+ ctx->hflags |= LARCH_HFLAG_B; -+ gen_branch(ctx, 4); -+ return true; -+} -+ -+static bool trans_blt(DisasContext *ctx, arg_blt *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BLT, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_bge(DisasContext *ctx, arg_bge *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BGE, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_bltu(DisasContext *ctx, arg_bltu *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BLTU, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BGEU, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_beq(DisasContext *ctx, arg_beq *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BEQ, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_bne(DisasContext *ctx, arg_bne *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BNE, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_jirl(DisasContext *ctx, arg_jirl *a) -+{ -+ gen_base_offset_addr(ctx, btarget, a->rj, a->offs16 << 2); -+ if (a->rd != 0) { -+ tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->base.pc_next + 4); -+ } -+ ctx->hflags |= LARCH_HFLAG_BR; -+ gen_branch(ctx, 4); -+ -+ return true; -+} -+ -+#define TRANS_F4FR(name, fmt, op, bits) \ -+static bool trans_ ## name ## _ ## fmt(DisasContext *ctx, \ -+ arg_##name##_##fmt * a) \ -+{ \ -+ check_cp1_enabled(ctx); \ -+ TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \ -+ TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \ -+ TCGv_i ## bits fp2 = tcg_temp_new_i ## bits(); \ -+ TCGv_i ## bits fp3 = tcg_temp_new_i ## bits(); \ -+ check_cp1_enabled(ctx); \ -+ gen_load_fpr ## bits(ctx, fp0, a->fj); \ -+ gen_load_fpr ## bits(ctx, fp1, a->fk); \ -+ gen_load_fpr ## bits(ctx, fp2, a->fa); \ -+ gen_helper_float_ ## op ## _ ## fmt(fp3, \ -+ cpu_env, fp0, fp1, fp2); \ -+ gen_store_fpr ## bits(ctx, fp3, a->fd); \ -+ tcg_temp_free_i ## bits(fp3); \ -+ tcg_temp_free_i ## bits(fp2); \ -+ tcg_temp_free_i ## bits(fp1); \ -+ tcg_temp_free_i ## bits(fp0); \ -+ return true; \ -+} -+ -+TRANS_F4FR(fmadd , s, maddf , 32) /* trans_fmadd_s */ -+TRANS_F4FR(fmadd , d, maddf , 64) /* trans_fmadd_d */ -+TRANS_F4FR(fmsub , s, msubf , 32) /* trans_fmsub_s */ -+TRANS_F4FR(fmsub , d, msubf , 64) /* trans_fmsub_d */ -+TRANS_F4FR(fnmadd, s, nmaddf, 32) /* trans_fnmadd_s */ -+TRANS_F4FR(fnmadd, d, nmaddf, 64) /* trans_fnmadd_d */ -+TRANS_F4FR(fnmsub, s, nmsubf, 32) /* trans_fnmsub_s */ -+TRANS_F4FR(fnmsub, d, nmsubf, 64) /* trans_fnmsub_d */ -+#undef TRANS_F4FR -+ -+static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s * a) -+{ -+ gen_farith(ctx, OPC_LARCH_FADD_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FADD_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FSUB_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FSUB_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMUL_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMUL_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FDIV_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FDIV_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMAX_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMAX_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMIN_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMIN_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmaxa_s(DisasContext *ctx, arg_fmaxa_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMAXA_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmaxa_d(DisasContext *ctx, arg_fmaxa_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMAXA_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmina_s(DisasContext *ctx, arg_fmina_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMINA_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmina_d(DisasContext *ctx, arg_fmina_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMINA_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fscaleb_s(DisasContext *ctx, arg_fscaleb_s *a) -+{ -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr32(ctx, fp0, a->fj); -+ gen_load_fpr32(ctx, fp1, a->fk); -+ gen_helper_float_exp2_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, a->fd); -+ tcg_temp_free_i32(fp0); -+ return true; -+} -+ -+static bool trans_fscaleb_d(DisasContext *ctx, arg_fscaleb_d *a) -+{ -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fp0, a->fj); -+ gen_load_fpr64(ctx, fp1, a->fk); -+ gen_helper_float_exp2_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, a->fd); -+ tcg_temp_free_i64(fp0); -+ return true; -+} -+ -+static bool trans_fcopysign_s(DisasContext *ctx, arg_fcopysign_s *a) -+{ -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ TCGv_i32 fp2 = tcg_temp_new_i32(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr32(ctx, fp0, a->fj); -+ gen_load_fpr32(ctx, fp1, a->fk); -+ tcg_gen_deposit_i32(fp2, fp1, fp0, 0, 31); -+ gen_store_fpr32(ctx, fp2, a->fd); -+ -+ tcg_temp_free_i32(fp2); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ return true; -+} -+ -+static bool trans_fcopysign_d(DisasContext *ctx, arg_fcopysign_d *a) -+{ -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ TCGv_i64 fp2 = tcg_temp_new_i64(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fp0, a->fj); -+ gen_load_fpr64(ctx, fp1, a->fk); -+ tcg_gen_deposit_i64(fp2, fp1, fp0, 0, 63); -+ gen_store_fpr64(ctx, fp2, a->fd); -+ -+ tcg_temp_free_i64(fp2); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ return true; -+} -+ -+static bool trans_fabs_s(DisasContext *ctx, arg_fabs_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FABS_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fabs_d(DisasContext *ctx, arg_fabs_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FABS_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fneg_s(DisasContext *ctx, arg_fneg_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FNEG_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FNEG_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_flogb_s(DisasContext *ctx, arg_flogb_s *a) -+{ -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr32(ctx, fp0, a->fj); -+ gen_helper_float_logb_s(fp1, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp1, a->fd); -+ -+ tcg_temp_free_i32(fp0); -+ tcg_temp_free_i32(fp1); -+ return true; -+} -+ -+static bool trans_flogb_d(DisasContext *ctx, arg_flogb_d *a) -+{ -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fp0, a->fj); -+ gen_helper_float_logb_d(fp1, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp1, a->fd); -+ -+ tcg_temp_free_i64(fp0); -+ tcg_temp_free_i64(fp1); -+ return true; -+} -+ -+static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FCLASS_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FCLASS_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FSQRT_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FSQRT_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frecip_s(DisasContext *ctx, arg_frecip_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRECIP_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frecip_d(DisasContext *ctx, arg_frecip_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRECIP_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frsqrt_s(DisasContext *ctx, arg_frsqrt_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRSQRT_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frsqrt_d(DisasContext *ctx, arg_frsqrt_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRSQRT_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmov_s(DisasContext *ctx, arg_fmov_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMOV_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmov_d(DisasContext *ctx, arg_fmov_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMOV_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_movgr2fr_w(DisasContext *ctx, arg_movgr2fr_w *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_GR2FR_W, a->rj, a->fd); -+ return true; -+} -+ -+static bool trans_movgr2fr_d(DisasContext *ctx, arg_movgr2fr_d *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_GR2FR_D, a->rj, a->fd); -+ return true; -+} -+ -+static bool trans_movgr2frh_w(DisasContext *ctx, arg_movgr2frh_w *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_GR2FRH_W, a->rj, a->fd); -+ return true; -+} -+ -+static bool trans_movfr2gr_s(DisasContext *ctx, arg_movfr2gr_s *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_FR2GR_S, a->rd, a->fj); -+ return true; -+} -+ -+static bool trans_movfr2gr_d(DisasContext *ctx, arg_movfr2gr_d *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_FR2GR_D, a->rd, a->fj); -+ return true; -+} -+ -+static bool trans_movfrh2gr_s(DisasContext *ctx, arg_movfrh2gr_s *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_FRH2GR_S, a->rd, a->fj); -+ return true; -+} -+ -+static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_gpr(t0, a->rj); -+ save_cpu_state(ctx, 0); -+ { -+ TCGv_i32 fs_tmp = tcg_const_i32(a->fcsrd); -+ gen_helper_0e2i(movgr2fcsr, t0, fs_tmp, a->rj); -+ tcg_temp_free_i32(fs_tmp); -+ } -+ /* Stop translation as we may have changed hflags */ -+ ctx->base.is_jmp = DISAS_STOP; -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_helper_1e0i(movfcsr2gr, t0, a->fcsrs); -+ gen_store_gpr(t0, a->rd); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) -+{ -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i32 cd = tcg_const_i32(a->cd); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fp0, a->fj); -+ gen_helper_movreg2cf(cpu_env, cd, fp0); -+ -+ tcg_temp_free_i64(fp0); -+ tcg_temp_free_i32(cd); -+ return true; -+} -+ -+static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv_i32 cj = tcg_const_i32(a->cj); -+ -+ check_cp1_enabled(ctx); -+ gen_helper_movcf2reg(t0, cpu_env, cj); -+ gen_store_fpr64(ctx, t0, a->fd); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv_i32 cd = tcg_const_i32(a->cd); -+ -+ check_cp1_enabled(ctx); -+ gen_load_gpr(t0, a->rj); -+ gen_helper_movreg2cf(cpu_env, cd, t0); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free_i32(cd); -+ return true; -+} -+ -+static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) -+{ -+ TCGv_i32 cj = tcg_const_i32(a->cj); -+ -+ check_cp1_enabled(ctx); -+ gen_helper_movcf2reg(cpu_gpr[a->rd], cpu_env, cj); -+ -+ tcg_temp_free_i32(cj); -+ return true; -+} -+ -+static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FCVT_S_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FCVT_D_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrm_w_s(DisasContext *ctx, arg_ftintrm_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRM_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrm_w_d(DisasContext *ctx, arg_ftintrm_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRM_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrm_l_s(DisasContext *ctx, arg_ftintrm_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRM_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrm_l_d(DisasContext *ctx, arg_ftintrm_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRM_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrp_w_s(DisasContext *ctx, arg_ftintrp_w_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRP_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrp_w_d(DisasContext *ctx, arg_ftintrp_w_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRP_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrp_l_s(DisasContext *ctx, arg_ftintrp_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRP_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrp_l_d(DisasContext *ctx, arg_ftintrp_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRP_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrz_w_s(DisasContext *ctx, arg_ftintrz_w_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRZ_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrz_w_d(DisasContext *ctx, arg_ftintrz_w_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRZ_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrz_l_s(DisasContext *ctx, arg_ftintrz_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRZ_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrz_l_d(DisasContext *ctx, arg_ftintrz_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRZ_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrne_w_s(DisasContext *ctx, arg_ftintrne_w_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRNE_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrne_w_d(DisasContext *ctx, arg_ftintrne_w_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRNE_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrne_l_s(DisasContext *ctx, arg_ftintrne_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRNE_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrne_l_d(DisasContext *ctx, arg_ftintrne_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRNE_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftint_w_s(DisasContext *ctx, arg_ftint_w_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINT_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftint_w_d(DisasContext *ctx, arg_ftint_w_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINT_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftint_l_s(DisasContext *ctx, arg_ftint_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINT_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftint_l_d(DisasContext *ctx, arg_ftint_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINT_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ffint_s_w(DisasContext *ctx, arg_ffint_s_w *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FFINT_S_W, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ffint_s_l(DisasContext *ctx, arg_ffint_s_l *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FFINT_S_L, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ffint_d_w(DisasContext *ctx, arg_ffint_d_w *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FFINT_D_W, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ffint_d_l(DisasContext *ctx, arg_ffint_d_l *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FFINT_D_L, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frint_s(DisasContext *ctx, arg_frint_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRINT_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frint_d(DisasContext *ctx, arg_frint_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRINT_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_alsl_w(DisasContext *ctx, arg_alsl_w *a) -+{ -+ gen_lsa(ctx, OPC_LARCH_ALSL_W, a->rd, a->rj, a->rk, a->sa2); -+ return true; -+} -+ -+static bool trans_alsl_wu(DisasContext *ctx, arg_alsl_wu *a) -+{ -+ TCGv t0, t1; -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ gen_load_gpr(t1, a->rk); -+ tcg_gen_shli_tl(t0, t0, a->sa2 + 1); -+ tcg_gen_add_tl(t0, t0, t1); -+ tcg_gen_ext32u_tl(cpu_gpr[a->rd], t0); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ -+ return true; -+} -+ -+static bool trans_alsl_d(DisasContext *ctx, arg_alsl_d *a) -+{ -+ check_larch_64(ctx); -+ gen_lsa(ctx, OPC_LARCH_ALSL_D, a->rd, a->rj, a->rk, a->sa2); -+ return true; -+} -+ -+static bool trans_bytepick_w(DisasContext *ctx, arg_bytepick_w *a) -+{ -+ gen_align(ctx, 32, a->rd, a->rj, a->rk, a->sa2); -+ return true; -+} -+ -+static bool trans_bytepick_d(DisasContext *ctx, arg_bytepick_d *a) -+{ -+ check_larch_64(ctx); -+ gen_align(ctx, 64, a->rd, a->rj, a->rk, a->sa3); -+ return true; -+} -+ -+static bool trans_add_w(DisasContext *ctx, arg_add_w *a) -+{ -+ gen_arith(ctx, OPC_LARCH_ADD_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_sub_w(DisasContext *ctx, arg_sub_w *a) -+{ -+ gen_arith(ctx, OPC_LARCH_SUB_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_add_d(DisasContext *ctx, arg_add_d *a) -+{ -+ gen_arith(ctx, OPC_LARCH_ADD_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_sub_d(DisasContext *ctx, arg_sub_d *a) -+{ -+ check_larch_64(ctx); -+ gen_arith(ctx, OPC_LARCH_SUB_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_slt(DisasContext *ctx, arg_slt *a) -+{ -+ gen_slt(ctx, OPC_LARCH_SLT, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_sltu(DisasContext *ctx, arg_sltu *a) -+{ -+ gen_slt(ctx, OPC_LARCH_SLTU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_maskeqz(DisasContext *ctx, arg_maskeqz *a) -+{ -+ gen_cond_move(ctx, OPC_LARCH_MASKEQZ, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_masknez(DisasContext *ctx, arg_masknez *a) -+{ -+ gen_cond_move(ctx, OPC_LARCH_MASKNEZ, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_nor(DisasContext *ctx, arg_nor *a) -+{ -+ gen_logic(ctx, OPC_LARCH_NOR, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_and(DisasContext *ctx, arg_and *a) -+{ -+ gen_logic(ctx, OPC_LARCH_AND, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_or(DisasContext *ctx, arg_or *a) -+{ -+ gen_logic(ctx, OPC_LARCH_OR, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_xor(DisasContext *ctx, arg_xor *a) -+{ -+ gen_logic(ctx, OPC_LARCH_XOR, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_orn(DisasContext *ctx, arg_orn *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rk); -+ tcg_gen_not_tl(t0, t0); -+ tcg_gen_or_tl(cpu_gpr[a->rd], cpu_gpr[a->rj], t0); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_andn(DisasContext *ctx, arg_andn *a) -+{ -+ TCGv t0, t1; -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rk); -+ gen_load_gpr(t1, a->rj); -+ tcg_gen_not_tl(t0, t0); -+ tcg_gen_and_tl(cpu_gpr[a->rd], t1, t0); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_sll_w(DisasContext *ctx, arg_sll_w *a) -+{ -+ gen_shift(ctx, OPC_LARCH_SLL_W, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_srl_w(DisasContext *ctx, arg_srl_w *a) -+{ -+ gen_shift(ctx, OPC_LARCH_SRL_W, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_sra_w(DisasContext *ctx, arg_sra_w *a) -+{ -+ gen_shift(ctx, OPC_LARCH_SRA_W, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_sll_d(DisasContext *ctx, arg_sll_d *a) -+{ -+ check_larch_64(ctx); -+ gen_shift(ctx, OPC_LARCH_SLL_D, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_srl_d(DisasContext *ctx, arg_srl_d *a) -+{ -+ check_larch_64(ctx); -+ gen_shift(ctx, OPC_LARCH_SRL_D, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_sra_d(DisasContext *ctx, arg_sra_d *a) -+{ -+ check_larch_64(ctx); -+ gen_shift(ctx, OPC_LARCH_SRA_D, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_rotr_w(DisasContext *ctx, arg_rotr_w *a) -+{ -+ gen_shift(ctx, OPC_LARCH_ROTR_W, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_rotr_d(DisasContext *ctx, arg_rotr_d *a) -+{ -+ check_larch_64(ctx); -+ gen_shift(ctx, OPC_LARCH_ROTR_D, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_crc_w_b_w(DisasContext *ctx, arg_crc_w_b_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 1, 0); -+ return true; -+} -+ -+static bool trans_crc_w_h_w(DisasContext *ctx, arg_crc_w_h_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 2, 0); -+ return true; -+} -+ -+static bool trans_crc_w_w_w(DisasContext *ctx, arg_crc_w_w_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 4, 0); -+ return true; -+} -+ -+static bool trans_crc_w_d_w(DisasContext *ctx, arg_crc_w_d_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 8, 0); -+ return true; -+} -+ -+static bool trans_crcc_w_b_w(DisasContext *ctx, arg_crcc_w_b_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 1, 1); -+ return true; -+} -+ -+static bool trans_crcc_w_h_w(DisasContext *ctx, arg_crcc_w_h_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 2, 1); -+ return true; -+} -+ -+static bool trans_crcc_w_w_w(DisasContext *ctx, arg_crcc_w_w_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 4, 1); -+ return true; -+} -+ -+static bool trans_crcc_w_d_w(DisasContext *ctx, arg_crcc_w_d_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 8, 1); -+ return true; -+} -+ -+static bool trans_mul_w(DisasContext *ctx, arg_mul_w *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MUL_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulh_w(DisasContext *ctx, arg_mulh_w *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MULH_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulh_wu(DisasContext *ctx, arg_mulh_wu *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MULH_WU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mul_d(DisasContext *ctx, arg_mul_d *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MUL_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulh_d(DisasContext *ctx, arg_mulh_d *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MULH_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulh_du(DisasContext *ctx, arg_mulh_du *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MULH_DU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulw_d_w(DisasContext *ctx, arg_mulw_d_w *a) -+{ -+ TCGv_i64 t0 = tcg_temp_new_i64(); -+ TCGv_i64 t1 = tcg_temp_new_i64(); -+ TCGv_i64 t2 = tcg_temp_new_i64(); -+ gen_load_gpr(t0, a->rj); -+ gen_load_gpr(t1, a->rk); -+ tcg_gen_ext32s_i64(t0, t0); -+ tcg_gen_ext32s_i64(t1, t1); -+ tcg_gen_mul_i64(t2, t0, t1); -+ gen_store_gpr(t2, a->rd); -+ tcg_temp_free_i64(t0); -+ tcg_temp_free_i64(t1); -+ tcg_temp_free_i64(t2); -+ return true; -+} -+ -+static bool trans_mulw_d_wu(DisasContext *ctx, arg_mulw_d_wu *a) -+{ -+ TCGv_i64 t0 = tcg_temp_new_i64(); -+ TCGv_i64 t1 = tcg_temp_new_i64(); -+ TCGv_i64 t2 = tcg_temp_new_i64(); -+ gen_load_gpr(t0, a->rj); -+ gen_load_gpr(t1, a->rk); -+ tcg_gen_ext32u_i64(t0, t0); -+ tcg_gen_ext32u_i64(t1, t1); -+ tcg_gen_mul_i64(t2, t0, t1); -+ gen_store_gpr(t2, a->rd); -+ tcg_temp_free_i64(t0); -+ tcg_temp_free_i64(t1); -+ tcg_temp_free_i64(t2); -+ return true; -+} -+ -+static bool trans_div_w(DisasContext *ctx, arg_div_w *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_DIV_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mod_w(DisasContext *ctx, arg_mod_w *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MOD_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_div_wu(DisasContext *ctx, arg_div_wu *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_DIV_WU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mod_wu(DisasContext *ctx, arg_mod_wu *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MOD_WU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_div_d(DisasContext *ctx, arg_div_d *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_DIV_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mod_d(DisasContext *ctx, arg_mod_d *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MOD_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_div_du(DisasContext *ctx, arg_div_du *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_DIV_DU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mod_du(DisasContext *ctx, arg_mod_du *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MOD_DU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+/* do not update CP0.BadVaddr */ -+static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a) -+{ -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_temp_new(); -+ gen_load_gpr(t1, a->rj); -+ gen_load_gpr(t2, a->rk); -+ gen_helper_asrtle_d(cpu_env, t1, t2); -+ tcg_temp_free(t1); -+ tcg_temp_free(t2); -+ return true; -+} -+ -+/* do not update CP0.BadVaddr */ -+static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) -+{ -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_temp_new(); -+ gen_load_gpr(t1, a->rj); -+ gen_load_gpr(t2, a->rk); -+ gen_helper_asrtgt_d(cpu_env, t1, t2); -+ tcg_temp_free(t1); -+ tcg_temp_free(t2); -+ return true; -+} -+ -+#ifdef CONFIG_USER_ONLY -+static bool trans_gr2scr(DisasContext *ctx, arg_gr2scr *a) -+{ -+ return false; -+} -+ -+static bool trans_scr2gr(DisasContext *ctx, arg_scr2gr *a) -+{ -+ return false; -+} -+#else -+static bool trans_gr2scr(DisasContext *ctx, arg_gr2scr *a) -+{ -+ TCGv_i32 sd = tcg_const_i32(a->sd); -+ TCGv val = tcg_temp_new(); -+ check_lbt_enabled(ctx); -+ gen_load_gpr(val, a->rj); -+ gen_helper_store_scr(cpu_env, sd, val); -+ tcg_temp_free_i32(sd); -+ tcg_temp_free(val); -+ return true; -+} -+ -+static bool trans_scr2gr(DisasContext *ctx, arg_scr2gr *a) -+{ -+ if (a->rd == 0) { -+ /* Nop */ -+ return true; -+ } -+ -+ TCGv_i32 tsj = tcg_const_i32(a->sj); -+ check_lbt_enabled(ctx); -+ gen_helper_load_scr(cpu_gpr[a->rd], cpu_env, tsj); -+ tcg_temp_free_i32(tsj); -+ return true; -+} -+#endif -+ -+static bool trans_clo_w(DisasContext *ctx, arg_clo_w *a) -+{ -+ gen_cl(ctx, OPC_LARCH_CLO_W, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_clz_w(DisasContext *ctx, arg_clz_w *a) -+{ -+ gen_cl(ctx, OPC_LARCH_CLZ_W, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_cto_w(DisasContext *ctx, arg_cto_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ gen_helper_cto_w(cpu_gpr[a->rd], cpu_env, t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_ctz_w(DisasContext *ctx, arg_ctz_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ gen_helper_ctz_w(cpu_gpr[a->rd], cpu_env, t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_clo_d(DisasContext *ctx, arg_clo_d *a) -+{ -+ check_larch_64(ctx); -+ gen_cl(ctx, OPC_LARCH_CLO_D, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_clz_d(DisasContext *ctx, arg_clz_d *a) -+{ -+ check_larch_64(ctx); -+ gen_cl(ctx, OPC_LARCH_CLZ_D, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_cto_d(DisasContext *ctx, arg_cto_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ gen_helper_cto_d(cpu_gpr[a->rd], cpu_env, t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_ctz_d(DisasContext *ctx, arg_ctz_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ gen_helper_ctz_d(cpu_gpr[a->rd], cpu_env, t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_revb_2h(DisasContext *ctx, arg_revb_2h *a) -+{ -+ gen_bshfl(ctx, OPC_LARCH_REVB_2H, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revb_4h(DisasContext *ctx, arg_revb_4h *a) -+{ -+ check_larch_64(ctx); -+ gen_bshfl(ctx, OPC_LARCH_REVB_4H, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revb_2w(DisasContext *ctx, arg_revb_2w *a) -+{ -+ handle_rev32(ctx, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revb_d(DisasContext *ctx, arg_revb_d *a) -+{ -+ handle_rev64(ctx, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revh_2w(DisasContext *ctx, arg_revh_2w *a) -+{ -+ handle_rev16(ctx, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revh_d(DisasContext *ctx, arg_revh_d *a) -+{ -+ check_larch_64(ctx); -+ gen_bshfl(ctx, OPC_LARCH_REVH_D, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_bitrev_4b(DisasContext *ctx, arg_bitrev_4b *a) -+{ -+ gen_bitswap(ctx, OPC_LARCH_BREV_4B, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_bitrev_8b(DisasContext *ctx, arg_bitrev_8b *a) -+{ -+ check_larch_64(ctx); -+ gen_bitswap(ctx, OPC_LARCH_BREV_8B, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_bitrev_w(DisasContext *ctx, arg_bitrev_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ gen_helper_bitrev_w(cpu_gpr[a->rd], cpu_env, t0); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_bitrev_d(DisasContext *ctx, arg_bitrev_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ gen_helper_bitrev_d(cpu_gpr[a->rd], cpu_env, t0); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_ext_w_h(DisasContext *ctx, arg_ext_w_h *a) -+{ -+ gen_bshfl(ctx, OPC_LARCH_EXT_WH, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_ext_w_b(DisasContext *ctx, arg_ext_w_b *a) -+{ -+ gen_bshfl(ctx, OPC_LARCH_EXT_WB, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_srli_w(DisasContext *ctx, arg_srli_w *a) -+{ -+ gen_shift_imm(ctx, OPC_LARCH_SRLI_W, a->rd, a->rj, a->ui5); -+ return true; -+} -+ -+static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) -+{ -+ gen_shift_imm(ctx, OPC_LARCH_SRAI_W, a->rd, a->rj, a->ui5); -+ return true; -+} -+ -+static bool trans_srai_d(DisasContext *ctx, arg_srai_d *a) -+{ -+ TCGv t0; -+ check_larch_64(ctx); -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_sari_tl(cpu_gpr[a->rd], t0, a->ui6); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_rotri_w(DisasContext *ctx, arg_rotri_w *a) -+{ -+ gen_shift_imm(ctx, OPC_LARCH_ROTRI_W, a->rd, a->rj, a->ui5); -+ return true; -+} -+ -+static bool trans_rotri_d(DisasContext *ctx, arg_rotri_d *a) -+{ -+ TCGv t0; -+ check_larch_64(ctx); -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_rotri_tl(cpu_gpr[a->rd], t0, a->ui6); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) -+{ -+ check_cp1_enabled(ctx); -+ gen_fcmp_s(ctx, a->fcond, a->fk, a->fj, a->cd); -+ return true; -+} -+ -+static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) -+{ -+ check_cp1_enabled(ctx); -+ gen_fcmp_d(ctx, a->fcond, a->fk, a->fj, a->cd); -+ return true; -+} -+ -+static bool trans_fsel(DisasContext *ctx, arg_fsel *a) -+{ -+ TCGv_i64 fj = tcg_temp_new_i64(); -+ TCGv_i64 fk = tcg_temp_new_i64(); -+ TCGv_i64 fd = tcg_temp_new_i64(); -+ TCGv_i32 ca = tcg_const_i32(a->ca); -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fj, a->fj); -+ gen_load_fpr64(ctx, fk, a->fk); -+ gen_helper_fsel(fd, cpu_env, fj, fk, ca); -+ gen_store_fpr64(ctx, fd, a->fd); -+ tcg_temp_free_i64(fj); -+ tcg_temp_free_i64(fk); -+ tcg_temp_free_i64(fd); -+ tcg_temp_free_i32(ca); -+ return true; -+} -+ -+#include "cpu-csr.h" -+ -+#ifdef CONFIG_USER_ONLY -+ -+static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) -+{ -+ return false; -+} -+ -+#else -+ -+ -+#define GEN_CSRRQ_CASE(name) \ -+ do { \ -+ case LOONGARCH_CSR_ ## name: \ -+ gen_csr_rdq(ctx, cpu_gpr[rd], LOONGARCH_CSR_ ## name);\ -+ } while (0) -+ -+static bool trans_csrrd(DisasContext *ctx, unsigned rd, unsigned csr) -+{ -+ switch (csr) { -+ GEN_CSRRQ_CASE(CRMD); -+ break; -+ GEN_CSRRQ_CASE(PRMD); -+ break; -+ GEN_CSRRQ_CASE(EUEN); -+ break; -+ GEN_CSRRQ_CASE(MISC); -+ break; -+ GEN_CSRRQ_CASE(ECFG); -+ break; -+ GEN_CSRRQ_CASE(ESTAT); -+ break; -+ GEN_CSRRQ_CASE(ERA); -+ break; -+ GEN_CSRRQ_CASE(BADV); -+ break; -+ GEN_CSRRQ_CASE(BADI); -+ break; -+ GEN_CSRRQ_CASE(EEPN); -+ break; -+ GEN_CSRRQ_CASE(TLBIDX); -+ break; -+ GEN_CSRRQ_CASE(TLBEHI); -+ break; -+ GEN_CSRRQ_CASE(TLBELO0); -+ break; -+ GEN_CSRRQ_CASE(TLBELO1); -+ break; -+ GEN_CSRRQ_CASE(TLBWIRED); -+ break; -+ GEN_CSRRQ_CASE(GTLBC); -+ break; -+ GEN_CSRRQ_CASE(TRGP); -+ break; -+ GEN_CSRRQ_CASE(ASID); -+ break; -+ GEN_CSRRQ_CASE(PGDL); -+ break; -+ GEN_CSRRQ_CASE(PGDH); -+ break; -+ case LOONGARCH_CSR_PGD: -+ gen_helper_read_pgd(cpu_gpr[rd], cpu_env); -+ break; -+ GEN_CSRRQ_CASE(PWCTL0); -+ break; -+ GEN_CSRRQ_CASE(PWCTL1); -+ break; -+ GEN_CSRRQ_CASE(STLBPGSIZE); -+ break; -+ GEN_CSRRQ_CASE(RVACFG); -+ break; -+ GEN_CSRRQ_CASE(CPUID); -+ break; -+ GEN_CSRRQ_CASE(PRCFG1); -+ break; -+ GEN_CSRRQ_CASE(PRCFG2); -+ break; -+ GEN_CSRRQ_CASE(PRCFG3); -+ break; -+ GEN_CSRRQ_CASE(KS0); -+ break; -+ GEN_CSRRQ_CASE(KS1); -+ break; -+ GEN_CSRRQ_CASE(KS2); -+ break; -+ GEN_CSRRQ_CASE(KS3); -+ break; -+ GEN_CSRRQ_CASE(KS4); -+ break; -+ GEN_CSRRQ_CASE(KS5); -+ break; -+ GEN_CSRRQ_CASE(KS6); -+ break; -+ GEN_CSRRQ_CASE(KS7); -+ break; -+ GEN_CSRRQ_CASE(KS8); -+ break; -+ GEN_CSRRQ_CASE(TMID); -+ break; -+ GEN_CSRRQ_CASE(TCFG); -+ break; -+ GEN_CSRRQ_CASE(TVAL); -+ break; -+ GEN_CSRRQ_CASE(CNTC); -+ break; -+ GEN_CSRRQ_CASE(TINTCLR); -+ break; -+ GEN_CSRRQ_CASE(GSTAT); -+ break; -+ GEN_CSRRQ_CASE(GCFG); -+ break; -+ GEN_CSRRQ_CASE(GINTC); -+ break; -+ GEN_CSRRQ_CASE(GCNTC); -+ break; -+ GEN_CSRRQ_CASE(LLBCTL); -+ break; -+ GEN_CSRRQ_CASE(IMPCTL1); -+ break; -+ GEN_CSRRQ_CASE(IMPCTL2); -+ break; -+ GEN_CSRRQ_CASE(GNMI); -+ break; -+ GEN_CSRRQ_CASE(TLBRENT); -+ break; -+ GEN_CSRRQ_CASE(TLBRBADV); -+ break; -+ GEN_CSRRQ_CASE(TLBRERA); -+ break; -+ GEN_CSRRQ_CASE(TLBRSAVE); -+ break; -+ GEN_CSRRQ_CASE(TLBRELO0); -+ break; -+ GEN_CSRRQ_CASE(TLBRELO1); -+ break; -+ GEN_CSRRQ_CASE(TLBREHI); -+ break; -+ GEN_CSRRQ_CASE(TLBRPRMD); -+ break; -+ GEN_CSRRQ_CASE(ERRCTL); -+ break; -+ GEN_CSRRQ_CASE(ERRINFO); -+ break; -+ GEN_CSRRQ_CASE(ERRINFO1); -+ break; -+ GEN_CSRRQ_CASE(ERRENT); -+ break; -+ GEN_CSRRQ_CASE(ERRERA); -+ break; -+ GEN_CSRRQ_CASE(ERRSAVE); -+ break; -+ GEN_CSRRQ_CASE(CTAG); -+ break; -+ GEN_CSRRQ_CASE(DMWIN0); -+ break; -+ GEN_CSRRQ_CASE(DMWIN1); -+ break; -+ GEN_CSRRQ_CASE(DMWIN2); -+ break; -+ GEN_CSRRQ_CASE(DMWIN3); -+ break; -+ GEN_CSRRQ_CASE(PERFCTRL0); -+ break; -+ GEN_CSRRQ_CASE(PERFCNTR0); -+ break; -+ GEN_CSRRQ_CASE(PERFCTRL1); -+ break; -+ GEN_CSRRQ_CASE(PERFCNTR1); -+ break; -+ GEN_CSRRQ_CASE(PERFCTRL2); -+ break; -+ GEN_CSRRQ_CASE(PERFCNTR2); -+ break; -+ GEN_CSRRQ_CASE(PERFCTRL3); -+ break; -+ GEN_CSRRQ_CASE(PERFCNTR3); -+ break; -+ /* debug */ -+ GEN_CSRRQ_CASE(MWPC); -+ break; -+ GEN_CSRRQ_CASE(MWPS); -+ break; -+ GEN_CSRRQ_CASE(DB0ADDR); -+ break; -+ GEN_CSRRQ_CASE(DB0MASK); -+ break; -+ GEN_CSRRQ_CASE(DB0CTL); -+ break; -+ GEN_CSRRQ_CASE(DB0ASID); -+ break; -+ GEN_CSRRQ_CASE(DB1ADDR); -+ break; -+ GEN_CSRRQ_CASE(DB1MASK); -+ break; -+ GEN_CSRRQ_CASE(DB1CTL); -+ break; -+ GEN_CSRRQ_CASE(DB1ASID); -+ break; -+ GEN_CSRRQ_CASE(DB2ADDR); -+ break; -+ GEN_CSRRQ_CASE(DB2MASK); -+ break; -+ GEN_CSRRQ_CASE(DB2CTL); -+ break; -+ GEN_CSRRQ_CASE(DB2ASID); -+ break; -+ GEN_CSRRQ_CASE(DB3ADDR); -+ break; -+ GEN_CSRRQ_CASE(DB3MASK); -+ break; -+ GEN_CSRRQ_CASE(DB3CTL); -+ break; -+ GEN_CSRRQ_CASE(DB3ASID); -+ break; -+ GEN_CSRRQ_CASE(FWPC); -+ break; -+ GEN_CSRRQ_CASE(FWPS); -+ break; -+ GEN_CSRRQ_CASE(IB0ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB0MASK); -+ break; -+ GEN_CSRRQ_CASE(IB0CTL); -+ break; -+ GEN_CSRRQ_CASE(IB0ASID); -+ break; -+ GEN_CSRRQ_CASE(IB1ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB1MASK); -+ break; -+ GEN_CSRRQ_CASE(IB1CTL); -+ break; -+ GEN_CSRRQ_CASE(IB1ASID); -+ break; -+ GEN_CSRRQ_CASE(IB2ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB2MASK); -+ break; -+ GEN_CSRRQ_CASE(IB2CTL); -+ break; -+ GEN_CSRRQ_CASE(IB2ASID); -+ break; -+ GEN_CSRRQ_CASE(IB3ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB3MASK); -+ break; -+ GEN_CSRRQ_CASE(IB3CTL); -+ break; -+ GEN_CSRRQ_CASE(IB3ASID); -+ break; -+ GEN_CSRRQ_CASE(IB4ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB4MASK); -+ break; -+ GEN_CSRRQ_CASE(IB4CTL); -+ break; -+ GEN_CSRRQ_CASE(IB4ASID); -+ break; -+ GEN_CSRRQ_CASE(IB5ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB5MASK); -+ break; -+ GEN_CSRRQ_CASE(IB5CTL); -+ break; -+ GEN_CSRRQ_CASE(IB5ASID); -+ break; -+ GEN_CSRRQ_CASE(IB6ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB6MASK); -+ break; -+ GEN_CSRRQ_CASE(IB6CTL); -+ break; -+ GEN_CSRRQ_CASE(IB6ASID); -+ break; -+ GEN_CSRRQ_CASE(IB7ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB7MASK); -+ break; -+ GEN_CSRRQ_CASE(IB7CTL); -+ break; -+ GEN_CSRRQ_CASE(IB7ASID); -+ break; -+ GEN_CSRRQ_CASE(DEBUG); -+ break; -+ GEN_CSRRQ_CASE(DERA); -+ break; -+ GEN_CSRRQ_CASE(DESAVE); -+ break; -+ default: -+ return false; -+ } -+ -+ #undef GEN_CSRRQ_CASE -+ -+ return true; -+} -+ -+#define GEN_CSRWQ_CASE(name) \ -+do { \ -+ case LOONGARCH_CSR_ ## name: \ -+ gen_csr_wrq(ctx, cpu_gpr[rd], LOONGARCH_CSR_ ## name); \ -+} while (0) -+ -+static bool trans_csrwr(DisasContext *ctx, unsigned rd, unsigned csr) -+{ -+ -+ switch (csr) { -+ case LOONGARCH_CSR_CRMD: -+ save_cpu_state(ctx, 1); -+ gen_csr_wrq(ctx, cpu_gpr[rd], LOONGARCH_CSR_CRMD); -+ gen_save_pc(ctx->base.pc_next + 4); -+ ctx->base.is_jmp = DISAS_EXIT; -+ break; -+ GEN_CSRWQ_CASE(PRMD); -+ break; -+ case LOONGARCH_CSR_EUEN: -+ gen_csr_wrq(ctx, cpu_gpr[rd], LOONGARCH_CSR_EUEN); -+ /* Stop translation */ -+ gen_save_pc(ctx->base.pc_next + 4); -+ ctx->base.is_jmp = DISAS_EXIT; -+ break; -+ GEN_CSRWQ_CASE(MISC); -+ break; -+ GEN_CSRWQ_CASE(ECFG); -+ break; -+ GEN_CSRWQ_CASE(ESTAT); -+ break; -+ GEN_CSRWQ_CASE(ERA); -+ break; -+ GEN_CSRWQ_CASE(BADV); -+ break; -+ GEN_CSRWQ_CASE(BADI); -+ break; -+ GEN_CSRWQ_CASE(EEPN); -+ break; -+ GEN_CSRWQ_CASE(TLBIDX); -+ break; -+ GEN_CSRWQ_CASE(TLBEHI); -+ break; -+ GEN_CSRWQ_CASE(TLBELO0); -+ break; -+ GEN_CSRWQ_CASE(TLBELO1); -+ break; -+ GEN_CSRWQ_CASE(TLBWIRED); -+ break; -+ GEN_CSRWQ_CASE(GTLBC); -+ break; -+ GEN_CSRWQ_CASE(TRGP); -+ break; -+ GEN_CSRWQ_CASE(ASID); -+ break; -+ GEN_CSRWQ_CASE(PGDL); -+ break; -+ GEN_CSRWQ_CASE(PGDH); -+ break; -+ GEN_CSRWQ_CASE(PGD); -+ break; -+ GEN_CSRWQ_CASE(PWCTL0); -+ break; -+ GEN_CSRWQ_CASE(PWCTL1); -+ break; -+ GEN_CSRWQ_CASE(STLBPGSIZE); -+ break; -+ GEN_CSRWQ_CASE(RVACFG); -+ break; -+ GEN_CSRWQ_CASE(CPUID); -+ break; -+ GEN_CSRWQ_CASE(PRCFG1); -+ break; -+ GEN_CSRWQ_CASE(PRCFG2); -+ break; -+ GEN_CSRWQ_CASE(PRCFG3); -+ break; -+ GEN_CSRWQ_CASE(KS0); -+ break; -+ GEN_CSRWQ_CASE(KS1); -+ break; -+ GEN_CSRWQ_CASE(KS2); -+ break; -+ GEN_CSRWQ_CASE(KS3); -+ break; -+ GEN_CSRWQ_CASE(KS4); -+ break; -+ GEN_CSRWQ_CASE(KS5); -+ break; -+ GEN_CSRWQ_CASE(KS6); -+ break; -+ GEN_CSRWQ_CASE(KS7); -+ break; -+ GEN_CSRWQ_CASE(KS8); -+ break; -+ GEN_CSRWQ_CASE(TMID); -+ break; -+ GEN_CSRWQ_CASE(TCFG); -+ break; -+ GEN_CSRWQ_CASE(TVAL); -+ break; -+ GEN_CSRWQ_CASE(CNTC); -+ break; -+ GEN_CSRWQ_CASE(TINTCLR); -+ break; -+ GEN_CSRWQ_CASE(GSTAT); -+ break; -+ GEN_CSRWQ_CASE(GCFG); -+ break; -+ GEN_CSRWQ_CASE(GINTC); -+ break; -+ GEN_CSRWQ_CASE(GCNTC); -+ break; -+ GEN_CSRWQ_CASE(LLBCTL); -+ break; -+ GEN_CSRWQ_CASE(IMPCTL1); -+ break; -+ GEN_CSRWQ_CASE(IMPCTL2); -+ break; -+ GEN_CSRWQ_CASE(GNMI); -+ break; -+ GEN_CSRWQ_CASE(TLBRENT); -+ break; -+ GEN_CSRWQ_CASE(TLBRBADV); -+ break; -+ GEN_CSRWQ_CASE(TLBRERA); -+ break; -+ GEN_CSRWQ_CASE(TLBRSAVE); -+ break; -+ GEN_CSRWQ_CASE(TLBRELO0); -+ break; -+ GEN_CSRWQ_CASE(TLBRELO1); -+ break; -+ GEN_CSRWQ_CASE(TLBREHI); -+ break; -+ GEN_CSRWQ_CASE(TLBRPRMD); -+ break; -+ GEN_CSRWQ_CASE(ERRCTL); -+ break; -+ GEN_CSRWQ_CASE(ERRINFO); -+ break; -+ GEN_CSRWQ_CASE(ERRINFO1); -+ break; -+ GEN_CSRWQ_CASE(ERRENT); -+ break; -+ GEN_CSRWQ_CASE(ERRERA); -+ break; -+ GEN_CSRWQ_CASE(ERRSAVE); -+ break; -+ GEN_CSRWQ_CASE(CTAG); -+ break; -+ GEN_CSRWQ_CASE(DMWIN0); -+ break; -+ GEN_CSRWQ_CASE(DMWIN1); -+ break; -+ GEN_CSRWQ_CASE(DMWIN2); -+ break; -+ GEN_CSRWQ_CASE(DMWIN3); -+ break; -+ GEN_CSRWQ_CASE(PERFCTRL0); -+ break; -+ GEN_CSRWQ_CASE(PERFCNTR0); -+ break; -+ GEN_CSRWQ_CASE(PERFCTRL1); -+ break; -+ GEN_CSRWQ_CASE(PERFCNTR1); -+ break; -+ GEN_CSRWQ_CASE(PERFCTRL2); -+ break; -+ GEN_CSRWQ_CASE(PERFCNTR2); -+ break; -+ GEN_CSRWQ_CASE(PERFCTRL3); -+ break; -+ GEN_CSRWQ_CASE(PERFCNTR3); -+ break; -+ /* debug */ -+ GEN_CSRWQ_CASE(MWPC); -+ break; -+ GEN_CSRWQ_CASE(MWPS); -+ break; -+ GEN_CSRWQ_CASE(DB0ADDR); -+ break; -+ GEN_CSRWQ_CASE(DB0MASK); -+ break; -+ GEN_CSRWQ_CASE(DB0CTL); -+ break; -+ GEN_CSRWQ_CASE(DB0ASID); -+ break; -+ GEN_CSRWQ_CASE(DB1ADDR); -+ break; -+ GEN_CSRWQ_CASE(DB1MASK); -+ break; -+ GEN_CSRWQ_CASE(DB1CTL); -+ break; -+ GEN_CSRWQ_CASE(DB1ASID); -+ break; -+ GEN_CSRWQ_CASE(DB2ADDR); -+ break; -+ GEN_CSRWQ_CASE(DB2MASK); -+ break; -+ GEN_CSRWQ_CASE(DB2CTL); -+ break; -+ GEN_CSRWQ_CASE(DB2ASID); -+ break; -+ GEN_CSRWQ_CASE(DB3ADDR); -+ break; -+ GEN_CSRWQ_CASE(DB3MASK); -+ break; -+ GEN_CSRWQ_CASE(DB3CTL); -+ break; -+ GEN_CSRWQ_CASE(DB3ASID); -+ break; -+ GEN_CSRWQ_CASE(FWPC); -+ break; -+ GEN_CSRWQ_CASE(FWPS); -+ break; -+ GEN_CSRWQ_CASE(IB0ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB0MASK); -+ break; -+ GEN_CSRWQ_CASE(IB0CTL); -+ break; -+ GEN_CSRWQ_CASE(IB0ASID); -+ break; -+ GEN_CSRWQ_CASE(IB1ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB1MASK); -+ break; -+ GEN_CSRWQ_CASE(IB1CTL); -+ break; -+ GEN_CSRWQ_CASE(IB1ASID); -+ break; -+ GEN_CSRWQ_CASE(IB2ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB2MASK); -+ break; -+ GEN_CSRWQ_CASE(IB2CTL); -+ break; -+ GEN_CSRWQ_CASE(IB2ASID); -+ break; -+ GEN_CSRWQ_CASE(IB3ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB3MASK); -+ break; -+ GEN_CSRWQ_CASE(IB3CTL); -+ break; -+ GEN_CSRWQ_CASE(IB3ASID); -+ break; -+ GEN_CSRWQ_CASE(IB4ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB4MASK); -+ break; -+ GEN_CSRWQ_CASE(IB4CTL); -+ break; -+ GEN_CSRWQ_CASE(IB4ASID); -+ break; -+ GEN_CSRWQ_CASE(IB5ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB5MASK); -+ break; -+ GEN_CSRWQ_CASE(IB5CTL); -+ break; -+ GEN_CSRWQ_CASE(IB5ASID); -+ break; -+ GEN_CSRWQ_CASE(IB6ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB6MASK); -+ break; -+ GEN_CSRWQ_CASE(IB6CTL); -+ break; -+ GEN_CSRWQ_CASE(IB6ASID); -+ break; -+ GEN_CSRWQ_CASE(IB7ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB7MASK); -+ break; -+ GEN_CSRWQ_CASE(IB7CTL); -+ break; -+ GEN_CSRWQ_CASE(IB7ASID); -+ break; -+ GEN_CSRWQ_CASE(DEBUG); -+ break; -+ GEN_CSRWQ_CASE(DERA); -+ break; -+ GEN_CSRWQ_CASE(DESAVE); -+ break; -+ default: -+ return false; -+ } -+ -+ #undef GEN_CSRWQ_CASE -+ -+ return true; -+} -+ -+#define GEN_CSRXQ_CASE(name) \ -+do { \ -+ case LOONGARCH_CSR_ ## name: \ -+ if (rd == 0) { \ -+ gen_csr_xchgq(ctx, zero, cpu_gpr[rj], \ -+ LOONGARCH_CSR_ ## name); \ -+ } else { \ -+ gen_csr_xchgq(ctx, cpu_gpr[rd], cpu_gpr[rj], \ -+ LOONGARCH_CSR_ ## name); \ -+ } \ -+} while (0) -+ -+static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) -+{ -+ unsigned rd, rj, csr; -+ TCGv zero = tcg_const_tl(0); -+ rd = a->rd; -+ rj = a->rj; -+ csr = a->csr; -+ -+ if (rj == 0) { -+ return trans_csrrd(ctx, rd, csr); -+ } else if (rj == 1) { -+ return trans_csrwr(ctx, rd, csr); -+ } -+ -+ switch (csr) { -+ case LOONGARCH_CSR_CRMD: -+ save_cpu_state(ctx, 1); -+ if (rd == 0) { -+ gen_csr_xchgq(ctx, zero, cpu_gpr[rj], LOONGARCH_CSR_CRMD); -+ } else { -+ gen_csr_xchgq(ctx, cpu_gpr[rd], cpu_gpr[rj], LOONGARCH_CSR_CRMD); -+ } -+ gen_save_pc(ctx->base.pc_next + 4); -+ ctx->base.is_jmp = DISAS_EXIT; -+ break; -+ -+ GEN_CSRXQ_CASE(PRMD); -+ break; -+ case LOONGARCH_CSR_EUEN: -+ if (rd == 0) { -+ gen_csr_xchgq(ctx, zero, cpu_gpr[rj], LOONGARCH_CSR_EUEN); -+ } else { -+ gen_csr_xchgq(ctx, cpu_gpr[rd], cpu_gpr[rj], LOONGARCH_CSR_EUEN); -+ } -+ /* Stop translation */ -+ gen_save_pc(ctx->base.pc_next + 4); -+ ctx->base.is_jmp = DISAS_EXIT; -+ break; -+ GEN_CSRXQ_CASE(MISC); -+ break; -+ GEN_CSRXQ_CASE(ECFG); -+ break; -+ GEN_CSRXQ_CASE(ESTAT); -+ break; -+ GEN_CSRXQ_CASE(ERA); -+ break; -+ GEN_CSRXQ_CASE(BADV); -+ break; -+ GEN_CSRXQ_CASE(BADI); -+ break; -+ GEN_CSRXQ_CASE(EEPN); -+ break; -+ GEN_CSRXQ_CASE(TLBIDX); -+ break; -+ GEN_CSRXQ_CASE(TLBEHI); -+ break; -+ GEN_CSRXQ_CASE(TLBELO0); -+ break; -+ GEN_CSRXQ_CASE(TLBELO1); -+ break; -+ GEN_CSRXQ_CASE(TLBWIRED); -+ break; -+ GEN_CSRXQ_CASE(GTLBC); -+ break; -+ GEN_CSRXQ_CASE(TRGP); -+ break; -+ GEN_CSRXQ_CASE(ASID); -+ break; -+ GEN_CSRXQ_CASE(PGDL); -+ break; -+ GEN_CSRXQ_CASE(PGDH); -+ break; -+ GEN_CSRXQ_CASE(PGD); -+ break; -+ GEN_CSRXQ_CASE(PWCTL0); -+ break; -+ GEN_CSRXQ_CASE(PWCTL1); -+ break; -+ GEN_CSRXQ_CASE(STLBPGSIZE); -+ break; -+ GEN_CSRXQ_CASE(RVACFG); -+ break; -+ GEN_CSRXQ_CASE(CPUID); -+ break; -+ GEN_CSRXQ_CASE(PRCFG1); -+ break; -+ GEN_CSRXQ_CASE(PRCFG2); -+ break; -+ GEN_CSRXQ_CASE(PRCFG3); -+ break; -+ GEN_CSRXQ_CASE(KS0); -+ break; -+ GEN_CSRXQ_CASE(KS1); -+ break; -+ GEN_CSRXQ_CASE(KS2); -+ break; -+ GEN_CSRXQ_CASE(KS3); -+ break; -+ GEN_CSRXQ_CASE(KS4); -+ break; -+ GEN_CSRXQ_CASE(KS5); -+ break; -+ GEN_CSRXQ_CASE(KS6); -+ break; -+ GEN_CSRXQ_CASE(KS7); -+ break; -+ GEN_CSRXQ_CASE(KS8); -+ break; -+ GEN_CSRXQ_CASE(TMID); -+ break; -+ GEN_CSRXQ_CASE(TCFG); -+ break; -+ GEN_CSRXQ_CASE(TVAL); -+ break; -+ GEN_CSRXQ_CASE(CNTC); -+ break; -+ GEN_CSRXQ_CASE(TINTCLR); -+ break; -+ GEN_CSRXQ_CASE(GSTAT); -+ break; -+ GEN_CSRXQ_CASE(GCFG); -+ break; -+ GEN_CSRXQ_CASE(GINTC); -+ break; -+ GEN_CSRXQ_CASE(GCNTC); -+ break; -+ GEN_CSRXQ_CASE(LLBCTL); -+ break; -+ GEN_CSRXQ_CASE(IMPCTL1); -+ break; -+ GEN_CSRXQ_CASE(IMPCTL2); -+ break; -+ GEN_CSRXQ_CASE(GNMI); -+ break; -+ GEN_CSRXQ_CASE(TLBRENT); -+ break; -+ GEN_CSRXQ_CASE(TLBRBADV); -+ break; -+ GEN_CSRXQ_CASE(TLBRERA); -+ break; -+ GEN_CSRXQ_CASE(TLBRSAVE); -+ break; -+ GEN_CSRXQ_CASE(TLBRELO0); -+ break; -+ GEN_CSRXQ_CASE(TLBRELO1); -+ break; -+ GEN_CSRXQ_CASE(TLBREHI); -+ break; -+ GEN_CSRXQ_CASE(TLBRPRMD); -+ break; -+ GEN_CSRXQ_CASE(ERRCTL); -+ break; -+ GEN_CSRXQ_CASE(ERRINFO); -+ break; -+ GEN_CSRXQ_CASE(ERRINFO1); -+ break; -+ GEN_CSRXQ_CASE(ERRENT); -+ break; -+ GEN_CSRXQ_CASE(ERRERA); -+ break; -+ GEN_CSRXQ_CASE(ERRSAVE); -+ break; -+ GEN_CSRXQ_CASE(CTAG); -+ break; -+ GEN_CSRXQ_CASE(DMWIN0); -+ break; -+ GEN_CSRXQ_CASE(DMWIN1); -+ break; -+ GEN_CSRXQ_CASE(DMWIN2); -+ break; -+ GEN_CSRXQ_CASE(DMWIN3); -+ break; -+ GEN_CSRXQ_CASE(PERFCTRL0); -+ break; -+ GEN_CSRXQ_CASE(PERFCNTR0); -+ break; -+ GEN_CSRXQ_CASE(PERFCTRL1); -+ break; -+ GEN_CSRXQ_CASE(PERFCNTR1); -+ break; -+ GEN_CSRXQ_CASE(PERFCTRL2); -+ break; -+ GEN_CSRXQ_CASE(PERFCNTR2); -+ break; -+ GEN_CSRXQ_CASE(PERFCTRL3); -+ break; -+ GEN_CSRXQ_CASE(PERFCNTR3); -+ break; -+ /* debug */ -+ GEN_CSRXQ_CASE(MWPC); -+ break; -+ GEN_CSRXQ_CASE(MWPS); -+ break; -+ GEN_CSRXQ_CASE(DB0ADDR); -+ break; -+ GEN_CSRXQ_CASE(DB0MASK); -+ break; -+ GEN_CSRXQ_CASE(DB0CTL); -+ break; -+ GEN_CSRXQ_CASE(DB0ASID); -+ break; -+ GEN_CSRXQ_CASE(DB1ADDR); -+ break; -+ GEN_CSRXQ_CASE(DB1MASK); -+ break; -+ GEN_CSRXQ_CASE(DB1CTL); -+ break; -+ GEN_CSRXQ_CASE(DB1ASID); -+ break; -+ GEN_CSRXQ_CASE(DB2ADDR); -+ break; -+ GEN_CSRXQ_CASE(DB2MASK); -+ break; -+ GEN_CSRXQ_CASE(DB2CTL); -+ break; -+ GEN_CSRXQ_CASE(DB2ASID); -+ break; -+ GEN_CSRXQ_CASE(DB3ADDR); -+ break; -+ GEN_CSRXQ_CASE(DB3MASK); -+ break; -+ GEN_CSRXQ_CASE(DB3CTL); -+ break; -+ GEN_CSRXQ_CASE(DB3ASID); -+ break; -+ GEN_CSRXQ_CASE(FWPC); -+ break; -+ GEN_CSRXQ_CASE(FWPS); -+ break; -+ GEN_CSRXQ_CASE(IB0ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB0MASK); -+ break; -+ GEN_CSRXQ_CASE(IB0CTL); -+ break; -+ GEN_CSRXQ_CASE(IB0ASID); -+ break; -+ GEN_CSRXQ_CASE(IB1ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB1MASK); -+ break; -+ GEN_CSRXQ_CASE(IB1CTL); -+ break; -+ GEN_CSRXQ_CASE(IB1ASID); -+ break; -+ GEN_CSRXQ_CASE(IB2ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB2MASK); -+ break; -+ GEN_CSRXQ_CASE(IB2CTL); -+ break; -+ GEN_CSRXQ_CASE(IB2ASID); -+ break; -+ GEN_CSRXQ_CASE(IB3ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB3MASK); -+ break; -+ GEN_CSRXQ_CASE(IB3CTL); -+ break; -+ GEN_CSRXQ_CASE(IB3ASID); -+ break; -+ GEN_CSRXQ_CASE(IB4ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB4MASK); -+ break; -+ GEN_CSRXQ_CASE(IB4CTL); -+ break; -+ GEN_CSRXQ_CASE(IB4ASID); -+ break; -+ GEN_CSRXQ_CASE(IB5ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB5MASK); -+ break; -+ GEN_CSRXQ_CASE(IB5CTL); -+ break; -+ GEN_CSRXQ_CASE(IB5ASID); -+ break; -+ GEN_CSRXQ_CASE(IB6ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB6MASK); -+ break; -+ GEN_CSRXQ_CASE(IB6CTL); -+ break; -+ GEN_CSRXQ_CASE(IB6ASID); -+ break; -+ GEN_CSRXQ_CASE(IB7ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB7MASK); -+ break; -+ GEN_CSRXQ_CASE(IB7CTL); -+ break; -+ GEN_CSRXQ_CASE(IB7ASID); -+ break; -+ GEN_CSRXQ_CASE(DEBUG); -+ break; -+ GEN_CSRXQ_CASE(DERA); -+ break; -+ GEN_CSRXQ_CASE(DESAVE); -+ break; -+ default: -+ return false; -+ } -+ -+ #undef GEN_CSRXQ_CASE -+ tcg_temp_free(zero); -+ return true; -+} -+ -+#endif -+ -+static bool trans_cacop(DisasContext *ctx, arg_cacop *a) -+{ -+ /* Treat as NOP. */ -+ return true; -+} -+ -+#ifdef CONFIG_USER_ONLY -+ -+static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) -+{ -+ return false; -+} -+ -+static bool trans_lddir(DisasContext *ctx, arg_lddir *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_b(DisasContext *ctx, arg_iocsrrd_b *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_h(DisasContext *ctx, arg_iocsrrd_h *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_w(DisasContext *ctx, arg_iocsrrd_w *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_d(DisasContext *ctx, arg_iocsrrd_d *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_b(DisasContext *ctx, arg_iocsrwr_b *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_h(DisasContext *ctx, arg_iocsrwr_h *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_w(DisasContext *ctx, arg_iocsrwr_w *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a) -+{ -+ return false; -+} -+#else -+ -+static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) -+{ -+ TCGv t0, t1; -+ TCGv_i32 t2; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->seq); -+ t2 = tcg_const_i32(ctx->mem_idx); -+ gen_helper_ldpte(cpu_env, t0, t1, t2); -+ -+ return true; -+} -+ -+static bool trans_lddir(DisasContext *ctx, arg_lddir *a) -+{ -+ TCGv t0, t1, t2; -+ TCGv_i32 t3; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ t2 = tcg_const_tl(a->level); -+ t3 = tcg_const_i32(ctx->mem_idx); -+ gen_helper_lddir(cpu_env, t0, t1, t2, t3); -+ -+ return true; -+} -+ -+static bool trans_iocsrrd_b(DisasContext *ctx, arg_iocsrrd_b *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_h(DisasContext *ctx, arg_iocsrrd_h *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_w(DisasContext *ctx, arg_iocsrrd_w *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_LD_W); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+ -+static bool trans_iocsrrd_d(DisasContext *ctx, arg_iocsrrd_d *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_LD_D); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+ -+static bool trans_iocsrwr_b(DisasContext *ctx, arg_iocsrwr_b *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_ST_B); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+ -+static bool trans_iocsrwr_h(DisasContext *ctx, arg_iocsrwr_h *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_w(DisasContext *ctx, arg_iocsrwr_w *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_ST_W); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+ -+static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_ST_D); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+#endif /* !CONFIG_USER_ONLY */ -+ -+ -+#ifdef CONFIG_USER_ONLY -+ -+#define GEN_FALSE_TRANS(name) \ -+static bool trans_##name(DisasContext *ctx, arg_##name * a) \ -+{ \ -+ return false; \ -+} -+ -+GEN_FALSE_TRANS(tlbclr) -+GEN_FALSE_TRANS(invtlb) -+GEN_FALSE_TRANS(tlbflush) -+GEN_FALSE_TRANS(tlbsrch) -+GEN_FALSE_TRANS(tlbrd) -+GEN_FALSE_TRANS(tlbwr) -+GEN_FALSE_TRANS(tlbfill) -+GEN_FALSE_TRANS(ertn) -+ -+#else -+ -+static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) -+{ -+ gen_helper_tlbclr(cpu_env); -+ return true; -+} -+ -+static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) -+{ -+ gen_helper_tlbflush(cpu_env); -+ return true; -+} -+ -+static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) -+{ -+ TCGv addr = tcg_temp_new(); -+ TCGv info = tcg_temp_new(); -+ TCGv op = tcg_const_tl(a->invop); -+ -+ gen_load_gpr(addr, a->addr); -+ gen_load_gpr(info, a->info); -+ gen_helper_invtlb(cpu_env, addr, info, op); -+ -+ tcg_temp_free(addr); -+ tcg_temp_free(info); -+ tcg_temp_free(op); -+ return true; -+} -+ -+static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a) -+{ -+ gen_helper_tlbsrch(cpu_env); -+ return true; -+} -+ -+static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a) -+{ -+ gen_helper_tlbrd(cpu_env); -+ return true; -+} -+ -+static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) -+{ -+ gen_helper_tlbwr(cpu_env); -+ return true; -+} -+ -+static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) -+{ -+ gen_helper_tlbfill(cpu_env); -+ return true; -+} -+ -+static bool trans_ertn(DisasContext *ctx, arg_ertn *a) -+{ -+ gen_helper_ertn(cpu_env); -+ ctx->base.is_jmp = DISAS_EXIT; -+ return true; -+} -+ -+#endif /* CONFIG_USER_ONLY */ -+ -+static bool trans_idle(DisasContext *ctx, arg_idle *a) -+{ -+ ctx->base.pc_next += 4; -+ save_cpu_state(ctx, 1); -+ ctx->base.pc_next -= 4; -+ gen_helper_idle(cpu_env); -+ ctx->base.is_jmp = DISAS_NORETURN; -+ return true; -+} -+ -+#ifdef CONFIG_USER_ONLY -+ -+static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) -+{ -+ /* Nop */ -+ return true; -+} -+ -+#else -+ -+static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) -+{ -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rd); -+ t1 = tcg_const_tl(a->rj); -+ gen_helper_drdtime(cpu_env, t0, t1); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+#endif -+ -+static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ gen_helper_cpucfg(cpu_gpr[a->rd], cpu_env, t0); -+ tcg_temp_free(t0); -+ return true; -+} -diff --git a/target/loongarch64/translate.c b/target/loongarch64/translate.c -new file mode 100644 -index 000000000..fe122e4c3 ---- /dev/null -+++ b/target/loongarch64/translate.c -@@ -0,0 +1,2892 @@ -+/* -+ * LOONGARCH emulation for QEMU - main translation routines -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 "cpu.h" -+#include "internal.h" -+#include "disas/disas.h" -+#include "exec/exec-all.h" -+#include "tcg/tcg-op.h" -+#include "exec/cpu_ldst.h" -+#include "hw/loongarch/cpudevs.h" -+ -+#include "exec/helper-proto.h" -+#include "exec/helper-gen.h" -+#include "semihosting/semihost.h" -+ -+#include "trace-tcg.h" -+#include "exec/translator.h" -+#include "exec/log.h" -+ -+#include "instmap.h" -+ -+#define LARCH_DEBUG_DISAS 0 -+ -+/* Values for the fmt field in FP instructions */ -+enum { -+ /* 0 - 15 are reserved */ -+ FMT_S = 16, /* single fp */ -+ FMT_D = 17, /* double fp */ -+}; -+ -+/* global register indices */ -+static TCGv cpu_gpr[32], cpu_PC; -+static TCGv btarget, bcond; -+static TCGv cpu_lladdr, cpu_llval; -+static TCGv_i32 hflags; -+static TCGv_i32 fpu_fcsr0; -+static TCGv_i64 fpu_f64[32]; -+ -+#include "exec/gen-icount.h" -+ -+#define gen_helper_0e0i(name, arg) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg); \ -+ gen_helper_##name(cpu_env, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_0e1i(name, arg1, arg2) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ -+ gen_helper_##name(cpu_env, arg1, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_1e0i(name, ret, arg1) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg1); \ -+ gen_helper_##name(ret, cpu_env, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_1e1i(name, ret, arg1, arg2) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ -+ gen_helper_##name(ret, cpu_env, arg1, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_0e2i(name, arg1, arg2, arg3) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ -+ gen_helper_##name(cpu_env, arg1, arg2, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_1e2i(name, ret, arg1, arg2, arg3) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ -+ gen_helper_##name(ret, cpu_env, arg1, arg2, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_0e3i(name, arg1, arg2, arg3, arg4) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg4); \ -+ gen_helper_##name(cpu_env, arg1, arg2, arg3, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+typedef struct DisasContext { -+ DisasContextBase base; -+ target_ulong saved_pc; -+ target_ulong page_start; -+ uint32_t opcode; -+ uint64_t insn_flags; -+ /* Routine used to access memory */ -+ int mem_idx; -+ MemOp default_tcg_memop_mask; -+ uint32_t hflags, saved_hflags; -+ target_ulong btarget; -+} DisasContext; -+ -+#define DISAS_STOP DISAS_TARGET_0 -+#define DISAS_EXIT DISAS_TARGET_1 -+ -+#define LOG_DISAS(...) \ -+ do { \ -+ if (LARCH_DEBUG_DISAS) { \ -+ qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \ -+ } \ -+ } while (0) -+ -+#define LARCH_INVAL(op) \ -+ do { \ -+ if (LARCH_DEBUG_DISAS) { \ -+ qemu_log_mask(CPU_LOG_TB_IN_ASM, \ -+ TARGET_FMT_lx ": %08x Invalid %s %03x %03x %03x\n", \ -+ ctx->base.pc_next, ctx->opcode, op, \ -+ ctx->opcode >> 26, ctx->opcode & 0x3F, \ -+ ((ctx->opcode >> 16) & 0x1F)); \ -+ } \ -+ } while (0) -+ -+/* General purpose registers moves. */ -+static inline void gen_load_gpr(TCGv t, int reg) -+{ -+ if (reg == 0) { -+ tcg_gen_movi_tl(t, 0); -+ } else { -+ tcg_gen_mov_tl(t, cpu_gpr[reg]); -+ } -+} -+ -+static inline void gen_store_gpr(TCGv t, int reg) -+{ -+ if (reg != 0) { -+ tcg_gen_mov_tl(cpu_gpr[reg], t); -+ } -+} -+ -+/* Moves to/from shadow registers. */ -+/* Tests */ -+static inline void gen_save_pc(target_ulong pc) -+{ -+ tcg_gen_movi_tl(cpu_PC, pc); -+} -+ -+static inline void save_cpu_state(DisasContext *ctx, int do_save_pc) -+{ -+ LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); -+ if (do_save_pc && ctx->base.pc_next != ctx->saved_pc) { -+ gen_save_pc(ctx->base.pc_next); -+ ctx->saved_pc = ctx->base.pc_next; -+ } -+ if (ctx->hflags != ctx->saved_hflags) { -+ tcg_gen_movi_i32(hflags, ctx->hflags); -+ ctx->saved_hflags = ctx->hflags; -+ switch (ctx->hflags & LARCH_HFLAG_BMASK) { -+ case LARCH_HFLAG_BR: -+ break; -+ case LARCH_HFLAG_BC: -+ case LARCH_HFLAG_B: -+ tcg_gen_movi_tl(btarget, ctx->btarget); -+ break; -+ } -+ } -+} -+ -+static inline void restore_cpu_state(CPULOONGARCHState *env, DisasContext *ctx) -+{ -+ ctx->saved_hflags = ctx->hflags; -+ switch (ctx->hflags & LARCH_HFLAG_BMASK) { -+ case LARCH_HFLAG_BR: -+ break; -+ case LARCH_HFLAG_BC: -+ case LARCH_HFLAG_B: -+ ctx->btarget = env->btarget; -+ break; -+ } -+} -+ -+static inline void generate_exception_err(DisasContext *ctx, int excp, int err) -+{ -+ TCGv_i32 texcp = tcg_const_i32(excp); -+ TCGv_i32 terr = tcg_const_i32(err); -+ save_cpu_state(ctx, 1); -+ gen_helper_raise_exception_err(cpu_env, texcp, terr); -+ tcg_temp_free_i32(terr); -+ tcg_temp_free_i32(texcp); -+ ctx->base.is_jmp = DISAS_NORETURN; -+} -+ -+static inline void generate_exception_end(DisasContext *ctx, int excp) -+{ -+ generate_exception_err(ctx, excp, 0); -+} -+ -+/* Floating point register moves. */ -+static void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) -+{ -+ tcg_gen_extrl_i64_i32(t, fpu_f64[reg]); -+} -+ -+static void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) -+{ -+ TCGv_i64 t64; -+ t64 = tcg_temp_new_i64(); -+ tcg_gen_extu_i32_i64(t64, t); -+ tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 0, 32); -+ tcg_temp_free_i64(t64); -+} -+ -+static void gen_load_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) -+{ -+ tcg_gen_extrh_i64_i32(t, fpu_f64[reg]); -+} -+ -+static void gen_store_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) -+{ -+ TCGv_i64 t64 = tcg_temp_new_i64(); -+ tcg_gen_extu_i32_i64(t64, t); -+ tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 32, 32); -+ tcg_temp_free_i64(t64); -+} -+ -+static void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) -+{ -+ tcg_gen_mov_i64(t, fpu_f64[reg]); -+} -+ -+static void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) -+{ -+ tcg_gen_mov_i64(fpu_f64[reg], t); -+} -+ -+static inline int get_fp_bit(int cc) -+{ -+ if (cc) { -+ return 24 + cc; -+ } else { -+ return 23; -+ } -+} -+ -+/* Addresses computation */ -+static inline void gen_op_addr_add(DisasContext *ctx, -+ TCGv ret, TCGv arg0, TCGv arg1) -+{ -+ tcg_gen_add_tl(ret, arg0, arg1); -+ -+ if (ctx->hflags & LARCH_HFLAG_AWRAP) { -+ tcg_gen_ext32s_i64(ret, ret); -+ } -+} -+ -+static inline void gen_op_addr_addi(DisasContext *ctx, TCGv ret, TCGv base, -+ target_long ofs) -+{ -+ tcg_gen_addi_tl(ret, base, ofs); -+ -+ if (ctx->hflags & LARCH_HFLAG_AWRAP) { -+ tcg_gen_ext32s_i64(ret, ret); -+ } -+} -+ -+/* Sign-extract the low 32-bits to a target_long. */ -+static inline void gen_move_low32(TCGv ret, TCGv_i64 arg) -+{ -+ tcg_gen_ext32s_i64(ret, arg); -+} -+ -+/* Sign-extract the high 32-bits to a target_long. */ -+static inline void gen_move_high32(TCGv ret, TCGv_i64 arg) -+{ -+ tcg_gen_sari_i64(ret, arg, 32); -+} -+ -+static inline void check_cp1_enabled(DisasContext *ctx) -+{ -+#ifndef CONFIG_USER_ONLY -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_FPU))) { -+ generate_exception_err(ctx, EXCP_FPDIS, 1); -+ } -+#endif -+} -+ -+static inline void check_lsx_enabled(DisasContext *ctx) -+{ -+#ifndef CONFIG_USER_ONLY -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_LSX))) { -+ generate_exception_err(ctx, EXCP_LSXDIS, 1); -+ } -+#endif -+} -+ -+static inline void check_lasx_enabled(DisasContext *ctx) -+{ -+#ifndef CONFIG_USER_ONLY -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_LASX))) { -+ generate_exception_err(ctx, EXCP_LASXDIS, 1); -+ } -+#endif -+} -+ -+static inline void check_lbt_enabled(DisasContext *ctx) -+{ -+#ifndef CONFIG_USER_ONLY -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_LBT))) { -+ generate_exception_err(ctx, EXCP_BTDIS, 1); -+ } -+#endif -+} -+ -+/* This code generates a "reserved instruction" exception if the -+ CPU does not support the instruction set corresponding to flags. */ -+static inline void check_insn(DisasContext *ctx, uint64_t flags) -+{ -+ if (unlikely(!(ctx->insn_flags & flags))) { -+ generate_exception_end(ctx, EXCP_RI); -+ } -+} -+ -+/* This code generates a "reserved instruction" exception if the -+ CPU has corresponding flag set which indicates that the instruction -+ has been removed. */ -+static inline void check_insn_opc_removed(DisasContext *ctx, uint64_t flags) -+{ -+ if (unlikely(ctx->insn_flags & flags)) { -+ generate_exception_end(ctx, EXCP_RI); -+ } -+} -+ -+/* -+ * The Linux kernel traps certain reserved instruction exceptions to -+ * emulate the corresponding instructions. QEMU is the kernel in user -+ * mode, so those traps are emulated by accepting the instructions. -+ * -+ * A reserved instruction exception is generated for flagged CPUs if -+ * QEMU runs in system mode. -+ */ -+static inline void check_insn_opc_user_only(DisasContext *ctx, uint64_t flags) -+{ -+#ifndef CONFIG_USER_ONLY -+ check_insn_opc_removed(ctx, flags); -+#endif -+} -+ -+/* This code generates a "reserved instruction" exception if 64-bit -+ instructions are not enabled. */ -+static inline void check_larch_64(DisasContext *ctx) -+{ -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_64))) { -+ generate_exception_end(ctx, EXCP_RI); -+ } -+} -+ -+/* Define small wrappers for gen_load_fpr* so that we have a uniform -+ calling interface for 32 and 64-bit FPRs. No sense in changing -+ all callers for gen_load_fpr32 when we need the CTX parameter for -+ this one use. */ -+#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(ctx, x, y) -+#define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y) -+#define FCOP_CONDNS(fmt, ifmt, bits, STORE) \ -+static inline void gen_fcmp_ ## fmt(DisasContext *ctx, int n, \ -+ int ft, int fs, int cd) \ -+{ \ -+ TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \ -+ TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \ -+ TCGv_i32 fcc = tcg_const_i32(cd); \ -+ check_cp1_enabled(ctx); \ -+ gen_ldcmp_fpr ## bits(ctx, fp0, fs); \ -+ gen_ldcmp_fpr ## bits(ctx, fp1, ft); \ -+ switch (n) { \ -+ case 0: \ -+ gen_helper_cmp_ ## fmt ## _af(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 1: \ -+ gen_helper_cmp_ ## fmt ## _saf(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 2: \ -+ gen_helper_cmp_ ## fmt ## _lt(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 3: \ -+ gen_helper_cmp_ ## fmt ## _slt(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 4: \ -+ gen_helper_cmp_ ## fmt ## _eq(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 5: \ -+ gen_helper_cmp_ ## fmt ## _seq(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 6: \ -+ gen_helper_cmp_ ## fmt ## _le(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 7: \ -+ gen_helper_cmp_ ## fmt ## _sle(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 8: \ -+ gen_helper_cmp_ ## fmt ## _un(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 9: \ -+ gen_helper_cmp_ ## fmt ## _sun(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 10: \ -+ gen_helper_cmp_ ## fmt ## _ult(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 11: \ -+ gen_helper_cmp_ ## fmt ## _sult(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 12: \ -+ gen_helper_cmp_ ## fmt ## _ueq(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 13: \ -+ gen_helper_cmp_ ## fmt ## _sueq(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 14: \ -+ gen_helper_cmp_ ## fmt ## _ule(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 15: \ -+ gen_helper_cmp_ ## fmt ## _sule(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 16: \ -+ gen_helper_cmp_ ## fmt ## _ne(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 17: \ -+ gen_helper_cmp_ ## fmt ## _sne(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 20: \ -+ gen_helper_cmp_ ## fmt ## _or(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 21: \ -+ gen_helper_cmp_ ## fmt ## _sor(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 24: \ -+ gen_helper_cmp_ ## fmt ## _une(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 25: \ -+ gen_helper_cmp_ ## fmt ## _sune(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ default: \ -+ abort(); \ -+ } \ -+ STORE; \ -+ tcg_temp_free_i ## bits(fp0); \ -+ tcg_temp_free_i ## bits(fp1); \ -+ tcg_temp_free_i32(fcc); \ -+} -+ -+FCOP_CONDNS(d, FMT_D, 64, gen_helper_movreg2cf_i64(cpu_env, fcc, fp0)) -+FCOP_CONDNS(s, FMT_S, 32, gen_helper_movreg2cf_i32(cpu_env, fcc, fp0)) -+#undef FCOP_CONDNS -+#undef gen_ldcmp_fpr32 -+#undef gen_ldcmp_fpr64 -+ -+/* load/store instructions. */ -+#ifdef CONFIG_USER_ONLY -+#define OP_LD_ATOMIC(insn, fname) \ -+static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \ -+ DisasContext *ctx) \ -+{ \ -+ TCGv t0 = tcg_temp_new(); \ -+ tcg_gen_mov_tl(t0, arg1); \ -+ tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ -+ tcg_gen_st_tl(t0, cpu_env, \ -+ offsetof(CPULOONGARCHState, lladdr)); \ -+ tcg_gen_st_tl(ret, cpu_env, \ -+ offsetof(CPULOONGARCHState, llval)); \ -+ tcg_temp_free(t0); \ -+} -+#else -+#define OP_LD_ATOMIC(insn, fname) \ -+static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \ -+ DisasContext *ctx) \ -+{ \ -+ gen_helper_1e1i(insn, ret, arg1, mem_idx); \ -+} -+#endif -+#if 0 -+OP_LD_ATOMIC(ll, ld32s); -+OP_LD_ATOMIC(lld, ld64); -+#endif -+#undef OP_LD_ATOMIC -+ -+static void gen_base_offset_addr(DisasContext *ctx, TCGv addr, -+ int base, int offset) -+{ -+ if (base == 0) { -+ tcg_gen_movi_tl(addr, offset); -+ } else if (offset == 0) { -+ gen_load_gpr(addr, base); -+ } else { -+ tcg_gen_movi_tl(addr, offset); -+ gen_op_addr_add(ctx, addr, cpu_gpr[base], addr); -+ } -+} -+ -+/* Load */ -+static void gen_ld(DisasContext *ctx, uint32_t opc, -+ int rt, int base, int offset) -+{ -+ TCGv t0; -+ int mem_idx = ctx->mem_idx; -+ -+ t0 = tcg_temp_new(); -+ gen_base_offset_addr(ctx, t0, base, offset); -+ -+ switch (opc) { -+ case OPC_LARCH_LD_WU: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LDPTR_D: -+ case OPC_LARCH_LD_D: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LL_D: -+#if 0 -+ op_ld_lld(t0, t0, mem_idx, ctx); -+#endif -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LDPTR_W: -+ case OPC_LARCH_LD_W: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESL | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LD_H: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESW | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LD_HU: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUW | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LD_B: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_SB); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LD_BU: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_UB); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LL_W: -+#if 0 -+ op_ld_ll(t0, t0, mem_idx, ctx); -+#endif -+ gen_store_gpr(t0, rt); -+ break; -+ } -+ -+ tcg_temp_free(t0); -+} -+ -+/* Store */ -+static void gen_st(DisasContext *ctx, uint32_t opc, int rt, -+ int base, int offset) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_base_offset_addr(ctx, t0, base, offset); -+ gen_load_gpr(t1, rt); -+ -+ switch (opc) { -+ case OPC_LARCH_STPTR_D: -+ case OPC_LARCH_ST_D: -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ break; -+ case OPC_LARCH_STPTR_W: -+ case OPC_LARCH_ST_W: -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ break; -+ case OPC_LARCH_ST_H: -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUW | -+ ctx->default_tcg_memop_mask); -+ break; -+ case OPC_LARCH_ST_B: -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_8); -+ break; -+ } -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+/* Store conditional */ -+static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset, -+ MemOp tcg_mo, bool eva) -+{ -+ TCGv addr, t0, val; -+ TCGLabel *l1 = gen_new_label(); -+ TCGLabel *done = gen_new_label(); -+ -+ t0 = tcg_temp_new(); -+ addr = tcg_temp_new(); -+ /* compare the address against that of the preceeding LL */ -+ gen_base_offset_addr(ctx, addr, base, offset); -+ tcg_gen_brcond_tl(TCG_COND_EQ, addr, cpu_lladdr, l1); -+ tcg_temp_free(addr); -+ tcg_gen_movi_tl(t0, 0); -+ gen_store_gpr(t0, rt); -+ tcg_gen_br(done); -+ -+ gen_set_label(l1); -+ /* generate cmpxchg */ -+ val = tcg_temp_new(); -+ gen_load_gpr(val, rt); -+ tcg_gen_atomic_cmpxchg_tl(t0, cpu_lladdr, cpu_llval, val, -+ eva ? LARCH_HFLAG_UM : ctx->mem_idx, tcg_mo); -+ tcg_gen_setcond_tl(TCG_COND_EQ, t0, t0, cpu_llval); -+ gen_store_gpr(t0, rt); -+ tcg_temp_free(val); -+ -+ gen_set_label(done); -+ tcg_temp_free(t0); -+} -+ -+/* Load and store */ -+static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft, -+ TCGv t0) -+{ -+ /* Don't do NOP if destination is zero: we must perform the actual -+ memory access. */ -+ switch (opc) { -+ case OPC_LARCH_FLD_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL | -+ ctx->default_tcg_memop_mask); -+ gen_store_fpr32(ctx, fp0, ft); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FST_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, ft); -+ tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FLD_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ gen_store_fpr64(ctx, fp0, ft); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FST_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, ft); -+ tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ default: -+ LARCH_INVAL("flt_ldst"); -+ generate_exception_end(ctx, EXCP_RI); -+ break; -+ } -+} -+ -+static void gen_fp_ldst(DisasContext *ctx, uint32_t op, int rt, -+ int rs, int16_t imm) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ check_cp1_enabled(ctx); -+ gen_base_offset_addr(ctx, t0, rs, imm); -+ gen_flt_ldst(ctx, op, rt, t0); -+ tcg_temp_free(t0); -+} -+ -+/* Arithmetic with immediate operand */ -+static void gen_arith_imm(DisasContext *ctx, uint32_t opc, -+ int rt, int rs, int imm) -+{ -+ target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ -+ -+ if (rt == 0) { -+ /* If no destination, treat it as a NOP. -+ For addi, we must generate the overflow exception when needed. */ -+ return; -+ } -+ switch (opc) { -+ case OPC_LARCH_ADDI_W: -+ if (rs != 0) { -+ tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], uimm); -+ } -+ break; -+ case OPC_LARCH_ADDI_D: -+ if (rs != 0) { -+ tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], uimm); -+ } -+ break; -+ } -+} -+ -+/* Logic with immediate operand */ -+static void gen_logic_imm(DisasContext *ctx, uint32_t opc, -+ int rt, int rs, int16_t imm) -+{ -+ target_ulong uimm; -+ -+ if (rt == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ uimm = (uint16_t)imm; -+ switch (opc) { -+ case OPC_LARCH_ANDI: -+ if (likely(rs != 0)) { -+ tcg_gen_andi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], 0); -+ } -+ break; -+ case OPC_LARCH_ORI: -+ if (rs != 0) { -+ tcg_gen_ori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], uimm); -+ } -+ break; -+ case OPC_LARCH_XORI: -+ if (likely(rs != 0)) { -+ tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], uimm); -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+/* Set on less than with immediate operand */ -+static void gen_slt_imm(DisasContext *ctx, uint32_t opc, -+ int rt, int rs, int16_t imm) -+{ -+ target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ -+ TCGv t0; -+ -+ if (rt == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ switch (opc) { -+ case OPC_LARCH_SLTI: -+ tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rt], t0, uimm); -+ break; -+ case OPC_LARCH_SLTIU: -+ tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, uimm); -+ break; -+ } -+ tcg_temp_free(t0); -+} -+ -+/* Shifts with immediate operand */ -+static void gen_shift_imm(DisasContext *ctx, uint32_t opc, -+ int rt, int rs, int16_t imm) -+{ -+ target_ulong uimm = ((uint16_t)imm) & 0x1f; -+ TCGv t0; -+ -+ if (rt == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ switch (opc) { -+ case OPC_LARCH_SRAI_W: -+ tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm); -+ break; -+ case OPC_LARCH_SRLI_W: -+ if (uimm != 0) { -+ tcg_gen_ext32u_tl(t0, t0); -+ tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm); -+ } else { -+ tcg_gen_ext32s_tl(cpu_gpr[rt], t0); -+ } -+ break; -+ case OPC_LARCH_ROTRI_W: -+ if (uimm != 0) { -+ TCGv_i32 t1 = tcg_temp_new_i32(); -+ -+ tcg_gen_trunc_tl_i32(t1, t0); -+ tcg_gen_rotri_i32(t1, t1, uimm); -+ tcg_gen_ext_i32_tl(cpu_gpr[rt], t1); -+ tcg_temp_free_i32(t1); -+ } else { -+ tcg_gen_ext32s_tl(cpu_gpr[rt], t0); -+ } -+ break; -+ } -+ tcg_temp_free(t0); -+} -+ -+/* Arithmetic */ -+static void gen_arith(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. -+ For add & sub, we must generate the -+ overflow exception when needed. */ -+ return; -+ } -+ -+ switch (opc) { -+ case OPC_LARCH_ADD_W: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_SUB_W: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_ADD_D: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_SUB_D: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ } -+} -+ -+/* Conditional move */ -+static void gen_cond_move(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ TCGv t0, t1, t2; -+ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rt); -+ t1 = tcg_const_tl(0); -+ t2 = tcg_temp_new(); -+ gen_load_gpr(t2, rs); -+ switch (opc) { -+ case OPC_LARCH_MASKEQZ: -+ tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[rd], t0, t1, t2, t1); -+ break; -+ case OPC_LARCH_MASKNEZ: -+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr[rd], t0, t1, t2, t1); -+ break; -+ } -+ tcg_temp_free(t2); -+ tcg_temp_free(t1); -+ tcg_temp_free(t0); -+} -+ -+/* Logic */ -+static void gen_logic(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ switch (opc) { -+ case OPC_LARCH_AND: -+ if (likely(rs != 0 && rt != 0)) { -+ tcg_gen_and_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_NOR: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_nor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], ~((target_ulong)0)); -+ } -+ break; -+ case OPC_LARCH_OR: -+ if (likely(rs != 0 && rt != 0)) { -+ tcg_gen_or_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_XOR: -+ if (likely(rs != 0 && rt != 0)) { -+ tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ } -+} -+ -+/* Set on lower than */ -+static void gen_slt(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ TCGv t0, t1; -+ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ switch (opc) { -+ case OPC_LARCH_SLT: -+ tcg_gen_setcond_tl(TCG_COND_LT, cpu_gpr[rd], t0, t1); -+ break; -+ case OPC_LARCH_SLTU: -+ tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t0, t1); -+ break; -+ } -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+/* Shifts */ -+static void gen_shift(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ TCGv t0, t1; -+ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. -+ For add & sub, we must generate the -+ overflow exception when needed. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ switch (opc) { -+ case OPC_LARCH_SLL_W: -+ tcg_gen_andi_tl(t0, t0, 0x1f); -+ tcg_gen_shl_tl(t0, t1, t0); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_SRA_W: -+ tcg_gen_andi_tl(t0, t0, 0x1f); -+ tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); -+ break; -+ case OPC_LARCH_SRL_W: -+ tcg_gen_ext32u_tl(t1, t1); -+ tcg_gen_andi_tl(t0, t0, 0x1f); -+ tcg_gen_shr_tl(t0, t1, t0); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_ROTR_W: -+ { -+ TCGv_i32 t2 = tcg_temp_new_i32(); -+ TCGv_i32 t3 = tcg_temp_new_i32(); -+ -+ tcg_gen_trunc_tl_i32(t2, t0); -+ tcg_gen_trunc_tl_i32(t3, t1); -+ tcg_gen_andi_i32(t2, t2, 0x1f); -+ tcg_gen_rotr_i32(t2, t3, t2); -+ tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); -+ tcg_temp_free_i32(t2); -+ tcg_temp_free_i32(t3); -+ } -+ break; -+ case OPC_LARCH_SLL_D: -+ tcg_gen_andi_tl(t0, t0, 0x3f); -+ tcg_gen_shl_tl(cpu_gpr[rd], t1, t0); -+ break; -+ case OPC_LARCH_SRA_D: -+ tcg_gen_andi_tl(t0, t0, 0x3f); -+ tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); -+ break; -+ case OPC_LARCH_SRL_D: -+ tcg_gen_andi_tl(t0, t0, 0x3f); -+ tcg_gen_shr_tl(cpu_gpr[rd], t1, t0); -+ break; -+ case OPC_LARCH_ROTR_D: -+ tcg_gen_andi_tl(t0, t0, 0x3f); -+ tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0); -+ break; -+ } -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+static inline void gen_r6_ld(target_long addr, int reg, int memidx, -+ MemOp memop) -+{ -+ TCGv t0 = tcg_const_tl(addr); -+ tcg_gen_qemu_ld_tl(t0, t0, memidx, memop); -+ gen_store_gpr(t0, reg); -+ tcg_temp_free(t0); -+} -+ -+static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt) -+{ -+ TCGv t0, t1; -+ -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ -+ switch (opc) { -+ case OPC_LARCH_DIV_W: -+ { -+ TCGv t2 = tcg_temp_new(); -+ TCGv t3 = tcg_temp_new(); -+ tcg_gen_ext32s_tl(t0, t0); -+ tcg_gen_ext32s_tl(t1, t1); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); -+ tcg_gen_and_tl(t2, t2, t3); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); -+ tcg_gen_or_tl(t2, t2, t3); -+ tcg_gen_movi_tl(t3, 0); -+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); -+ tcg_gen_div_tl(cpu_gpr[rd], t0, t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MOD_W: -+ { -+ TCGv t2 = tcg_temp_new(); -+ TCGv t3 = tcg_temp_new(); -+ tcg_gen_ext32s_tl(t0, t0); -+ tcg_gen_ext32s_tl(t1, t1); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); -+ tcg_gen_and_tl(t2, t2, t3); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); -+ tcg_gen_or_tl(t2, t2, t3); -+ tcg_gen_movi_tl(t3, 0); -+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); -+ tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_DIV_WU: -+ { -+ TCGv t2 = tcg_const_tl(0); -+ TCGv t3 = tcg_const_tl(1); -+ tcg_gen_ext32u_tl(t0, t0); -+ tcg_gen_ext32u_tl(t1, t1); -+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); -+ tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MOD_WU: -+ { -+ TCGv t2 = tcg_const_tl(0); -+ TCGv t3 = tcg_const_tl(1); -+ tcg_gen_ext32u_tl(t0, t0); -+ tcg_gen_ext32u_tl(t1, t1); -+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); -+ tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MUL_W: -+ { -+ TCGv_i32 t2 = tcg_temp_new_i32(); -+ TCGv_i32 t3 = tcg_temp_new_i32(); -+ tcg_gen_trunc_tl_i32(t2, t0); -+ tcg_gen_trunc_tl_i32(t3, t1); -+ tcg_gen_mul_i32(t2, t2, t3); -+ tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); -+ tcg_temp_free_i32(t2); -+ tcg_temp_free_i32(t3); -+ } -+ break; -+ case OPC_LARCH_MULH_W: -+ { -+ TCGv_i32 t2 = tcg_temp_new_i32(); -+ TCGv_i32 t3 = tcg_temp_new_i32(); -+ tcg_gen_trunc_tl_i32(t2, t0); -+ tcg_gen_trunc_tl_i32(t3, t1); -+ tcg_gen_muls2_i32(t2, t3, t2, t3); -+ tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); -+ tcg_temp_free_i32(t2); -+ tcg_temp_free_i32(t3); -+ } -+ break; -+ case OPC_LARCH_MULH_WU: -+ { -+ TCGv_i32 t2 = tcg_temp_new_i32(); -+ TCGv_i32 t3 = tcg_temp_new_i32(); -+ tcg_gen_trunc_tl_i32(t2, t0); -+ tcg_gen_trunc_tl_i32(t3, t1); -+ tcg_gen_mulu2_i32(t2, t3, t2, t3); -+ tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); -+ tcg_temp_free_i32(t2); -+ tcg_temp_free_i32(t3); -+ } -+ break; -+ case OPC_LARCH_DIV_D: -+ { -+ TCGv t2 = tcg_temp_new(); -+ TCGv t3 = tcg_temp_new(); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); -+ tcg_gen_and_tl(t2, t2, t3); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); -+ tcg_gen_or_tl(t2, t2, t3); -+ tcg_gen_movi_tl(t3, 0); -+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); -+ tcg_gen_div_tl(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MOD_D: -+ { -+ TCGv t2 = tcg_temp_new(); -+ TCGv t3 = tcg_temp_new(); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); -+ tcg_gen_and_tl(t2, t2, t3); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); -+ tcg_gen_or_tl(t2, t2, t3); -+ tcg_gen_movi_tl(t3, 0); -+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); -+ tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_DIV_DU: -+ { -+ TCGv t2 = tcg_const_tl(0); -+ TCGv t3 = tcg_const_tl(1); -+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); -+ tcg_gen_divu_i64(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MOD_DU: -+ { -+ TCGv t2 = tcg_const_tl(0); -+ TCGv t3 = tcg_const_tl(1); -+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); -+ tcg_gen_remu_i64(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MUL_D: -+ tcg_gen_mul_i64(cpu_gpr[rd], t0, t1); -+ break; -+ case OPC_LARCH_MULH_D: -+ { -+ TCGv t2 = tcg_temp_new(); -+ tcg_gen_muls2_i64(t2, cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MULH_DU: -+ { -+ TCGv t2 = tcg_temp_new(); -+ tcg_gen_mulu2_i64(t2, cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t2); -+ } -+ break; -+ default: -+ LARCH_INVAL("r6 mul/div"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ out: -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+static void gen_cl(DisasContext *ctx, uint32_t opc, -+ int rd, int rs) -+{ -+ TCGv t0; -+ -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = cpu_gpr[rd]; -+ gen_load_gpr(t0, rs); -+ -+ switch (opc) { -+ case OPC_LARCH_CLO_W: -+ case OPC_LARCH_CLO_D: -+ tcg_gen_not_tl(t0, t0); -+ break; -+ } -+ -+ switch (opc) { -+ case OPC_LARCH_CLO_W: -+ case OPC_LARCH_CLZ_W: -+ tcg_gen_ext32u_tl(t0, t0); -+ tcg_gen_clzi_tl(t0, t0, TARGET_LONG_BITS); -+ tcg_gen_subi_tl(t0, t0, TARGET_LONG_BITS - 32); -+ break; -+ case OPC_LARCH_CLO_D: -+ case OPC_LARCH_CLZ_D: -+ tcg_gen_clzi_i64(t0, t0, 64); -+ break; -+ } -+} -+ -+static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) -+{ -+ if (unlikely(ctx->base.singlestep_enabled)) { -+ return false; -+ } -+ -+#ifndef CONFIG_USER_ONLY -+ return (ctx->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); -+#else -+ return true; -+#endif -+} -+ -+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) -+{ -+ if (use_goto_tb(ctx, dest)) { -+ tcg_gen_goto_tb(n); -+ gen_save_pc(dest); -+ tcg_gen_exit_tb(ctx->base.tb, n); -+ } else { -+ gen_save_pc(dest); -+ if (ctx->base.singlestep_enabled) { -+ save_cpu_state(ctx, 0); -+ gen_helper_raise_exception_debug(cpu_env); -+ } -+ tcg_gen_lookup_and_goto_ptr(); -+ } -+} -+ -+/* Branches */ -+static void gen_compute_branch(DisasContext *ctx, uint32_t opc, -+ int insn_bytes, -+ int rs, int rt, int32_t offset) -+{ -+ target_ulong btgt = -1; -+ int bcond_compute = 0; -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ if (ctx->hflags & LARCH_HFLAG_BMASK) { -+#ifdef LARCH_DEBUG_DISAS -+ LOG_DISAS("Branch at PC 0x" -+ TARGET_FMT_lx "\n", ctx->base.pc_next); -+#endif -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ -+ /* Load needed operands */ -+ switch (opc) { -+ case OPC_LARCH_BLT: -+ case OPC_LARCH_BGE: -+ case OPC_LARCH_BLTU: -+ case OPC_LARCH_BGEU: -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ bcond_compute = 1; -+ btgt = ctx->base.pc_next + offset; -+ break; -+ case OPC_LARCH_BEQZ: -+ case OPC_LARCH_B: -+ case OPC_LARCH_BEQ: -+ case OPC_LARCH_BNEZ: -+ case OPC_LARCH_BNE: -+ /* Compare two registers */ -+ if (rs != rt) { -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ bcond_compute = 1; -+ } -+ btgt = ctx->base.pc_next + offset; -+ break; -+ default: -+ LARCH_INVAL("branch/jump"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ if (bcond_compute == 0) { -+ /* No condition to be computed */ -+ switch (opc) { -+ case OPC_LARCH_BEQZ: /* rx == rx */ -+ case OPC_LARCH_B: -+ case OPC_LARCH_BEQ: -+ /* Always take */ -+ ctx->hflags |= LARCH_HFLAG_B; -+ break; -+ case OPC_LARCH_BNEZ: -+ case OPC_LARCH_BNE: -+ /* Treat as NOP. */ -+ goto out; -+ default: -+ LARCH_INVAL("branch/jump"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ } else { -+ switch (opc) { -+ case OPC_LARCH_BLT: -+ tcg_gen_setcond_tl(TCG_COND_LT, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BGE: -+ tcg_gen_setcond_tl(TCG_COND_GE, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BLTU: -+ tcg_gen_setcond_tl(TCG_COND_LTU, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BGEU: -+ tcg_gen_setcond_tl(TCG_COND_GEU, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BEQZ: -+ case OPC_LARCH_B: -+ case OPC_LARCH_BEQ: -+ tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BNEZ: -+ case OPC_LARCH_BNE: -+ tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); -+ goto not_likely; -+ not_likely: -+ ctx->hflags |= LARCH_HFLAG_BC; -+ break; -+ default: -+ LARCH_INVAL("conditional branch/jump"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ } -+ -+ ctx->btarget = btgt; -+ -+ out: -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+/* special3 bitfield operations */ -+static void gen_bitops(DisasContext *ctx, uint32_t opc, int rt, -+ int rs, int lsb, int msb) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ gen_load_gpr(t1, rs); -+ switch (opc) { -+ case OPC_LARCH_TRPICK_W: -+ if (lsb + msb > 31) { -+ goto fail; -+ } -+ if (msb != 31) { -+ tcg_gen_extract_tl(t0, t1, lsb, msb + 1); -+ } else { -+ /* -+ * The two checks together imply that lsb == 0, -+ * so this is a simple sign-extension. -+ */ -+ tcg_gen_ext32s_tl(t0, t1); -+ } -+ break; -+ case OPC_LARCH_TRINS_W: -+ if (lsb > msb) { -+ goto fail; -+ } -+ gen_load_gpr(t0, rt); -+ tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); -+ tcg_gen_ext32s_tl(t0, t0); -+ break; -+ default: -+fail: -+ LARCH_INVAL("bitops"); -+ generate_exception_end(ctx, EXCP_RI); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return; -+ } -+ gen_store_gpr(t0, rt); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+static void gen_bshfl(DisasContext *ctx, uint32_t op2, int rt, int rd) -+{ -+ TCGv t0; -+ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rt); -+ switch (op2) { -+ case OPC_LARCH_REVB_2H: -+ { -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_const_tl(0x00FF00FF); -+ -+ tcg_gen_shri_tl(t1, t0, 8); -+ tcg_gen_and_tl(t1, t1, t2); -+ tcg_gen_and_tl(t0, t0, t2); -+ tcg_gen_shli_tl(t0, t0, 8); -+ tcg_gen_or_tl(t0, t0, t1); -+ tcg_temp_free(t2); -+ tcg_temp_free(t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); -+ } -+ break; -+ case OPC_LARCH_EXT_WB: -+ tcg_gen_ext8s_tl(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_EXT_WH: -+ tcg_gen_ext16s_tl(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_REVB_4H: -+ { -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_const_tl(0x00FF00FF00FF00FFULL); -+ -+ tcg_gen_shri_tl(t1, t0, 8); -+ tcg_gen_and_tl(t1, t1, t2); -+ tcg_gen_and_tl(t0, t0, t2); -+ tcg_gen_shli_tl(t0, t0, 8); -+ tcg_gen_or_tl(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t2); -+ tcg_temp_free(t1); -+ } -+ break; -+ case OPC_LARCH_REVH_D: -+ { -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_const_tl(0x0000FFFF0000FFFFULL); -+ -+ tcg_gen_shri_tl(t1, t0, 16); -+ tcg_gen_and_tl(t1, t1, t2); -+ tcg_gen_and_tl(t0, t0, t2); -+ tcg_gen_shli_tl(t0, t0, 16); -+ tcg_gen_or_tl(t0, t0, t1); -+ tcg_gen_shri_tl(t1, t0, 32); -+ tcg_gen_shli_tl(t0, t0, 32); -+ tcg_gen_or_tl(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t2); -+ tcg_temp_free(t1); -+ } -+ break; -+ default: -+ LARCH_INVAL("bsfhl"); -+ generate_exception_end(ctx, EXCP_RI); -+ tcg_temp_free(t0); -+ return; -+ } -+ tcg_temp_free(t0); -+} -+ -+/* REV with sf==1, opcode==3 ("REV64") */ -+static void handle_rev64(DisasContext *ctx, -+ unsigned int rn, unsigned int rd) -+{ -+ tcg_gen_bswap64_i64(cpu_gpr[rd], cpu_gpr[rn]); -+} -+ -+/* REV with sf==0, opcode==2 -+ * REV32 (sf==1, opcode==2) -+ */ -+static void handle_rev32(DisasContext *ctx, -+ unsigned int rn, unsigned int rd) -+{ -+ TCGv_i64 tcg_rd = tcg_temp_new_i64(); -+ gen_load_gpr(tcg_rd, rd); -+ -+ TCGv_i64 tcg_tmp = tcg_temp_new_i64(); -+ TCGv_i64 tcg_rn = tcg_temp_new_i64(); -+ gen_load_gpr(tcg_rn, rn); -+ -+ /* bswap32_i64 requires zero high word */ -+ tcg_gen_ext32u_i64(tcg_tmp, tcg_rn); -+ tcg_gen_bswap32_i64(tcg_rd, tcg_tmp, TCG_BSWAP_OZ); -+ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32); -+ tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp, TCG_BSWAP_OZ); -+ tcg_gen_concat32_i64(cpu_gpr[rd], tcg_rd, tcg_tmp); -+ -+ tcg_temp_free_i64(tcg_tmp); -+ tcg_temp_free_i64(tcg_rd); -+ tcg_temp_free_i64(tcg_rn); -+} -+ -+/* REV16 */ -+static void handle_rev16(DisasContext *ctx, unsigned int rn, unsigned int rd) -+{ -+ TCGv_i64 tcg_rd = tcg_temp_new_i64(); -+ TCGv_i64 tcg_rn = tcg_temp_new_i64(); -+ gen_load_gpr(tcg_rd, rd); -+ gen_load_gpr(tcg_rn, rn); -+ TCGv_i64 tcg_tmp = tcg_temp_new_i64(); -+ TCGv_i64 mask = tcg_const_i64(0x0000ffff0000ffffull); -+ -+ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 16); -+ tcg_gen_and_i64(tcg_rd, tcg_rn, mask); -+ tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask); -+ tcg_gen_shli_i64(tcg_rd, tcg_rd, 16); -+ tcg_gen_or_i64(cpu_gpr[rd], tcg_rd, tcg_tmp); -+ -+ tcg_temp_free_i64(mask); -+ tcg_temp_free_i64(tcg_tmp); -+ tcg_temp_free_i64(tcg_rd); -+ tcg_temp_free_i64(tcg_rn); -+} -+ -+static void gen_lsa(DisasContext *ctx, int opc, int rd, int rs, int rt, -+ int imm2) -+{ -+ TCGv t0; -+ TCGv t1; -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ tcg_gen_shli_tl(t0, t0, imm2 + 1); -+ tcg_gen_add_tl(cpu_gpr[rd], t0, t1); -+ if (opc == OPC_LARCH_ALSL_W) { -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ } -+ -+ tcg_temp_free(t1); -+ tcg_temp_free(t0); -+ -+ return; -+} -+ -+static void gen_align_bits(DisasContext *ctx, int wordsz, int rd, int rs, -+ int rt, int bits) -+{ -+ TCGv t0; -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ if (bits == 0 || bits == wordsz) { -+ if (bits == 0) { -+ gen_load_gpr(t0, rt); -+ } else { -+ gen_load_gpr(t0, rs); -+ } -+ switch (wordsz) { -+ case 32: -+ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); -+ break; -+ case 64: -+ tcg_gen_mov_tl(cpu_gpr[rd], t0); -+ break; -+ } -+ } else { -+ TCGv t1 = tcg_temp_new(); -+ gen_load_gpr(t0, rt); -+ gen_load_gpr(t1, rs); -+ switch (wordsz) { -+ case 32: -+ { -+ TCGv_i64 t2 = tcg_temp_new_i64(); -+ tcg_gen_concat_tl_i64(t2, t1, t0); -+ tcg_gen_shri_i64(t2, t2, 32 - bits); -+ gen_move_low32(cpu_gpr[rd], t2); -+ tcg_temp_free_i64(t2); -+ } -+ break; -+ case 64: -+ tcg_gen_shli_tl(t0, t0, bits); -+ tcg_gen_shri_tl(t1, t1, 64 - bits); -+ tcg_gen_or_tl(cpu_gpr[rd], t1, t0); -+ break; -+ } -+ tcg_temp_free(t1); -+ } -+ -+ tcg_temp_free(t0); -+} -+ -+static void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt, -+ int bp) -+{ -+ gen_align_bits(ctx, wordsz, rd, rs, rt, bp * 8); -+} -+ -+static void gen_bitswap(DisasContext *ctx, int opc, int rd, int rt) -+{ -+ TCGv t0; -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rt); -+ switch (opc) { -+ case OPC_LARCH_BREV_4B: -+ gen_helper_bitswap(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_BREV_8B: -+ gen_helper_dbitswap(cpu_gpr[rd], t0); -+ break; -+ } -+ tcg_temp_free(t0); -+} -+ -+static void gen_cp1(DisasContext *ctx, uint32_t opc, int rt, int fs) -+{ -+ TCGv t0 = tcg_temp_new(); -+ check_cp1_enabled(ctx); -+ -+ switch (opc) { -+ case OPC_LARCH_FR2GR_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ tcg_gen_ext_i32_tl(t0, fp0); -+ tcg_temp_free_i32(fp0); -+ } -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_GR2FR_W: -+ gen_load_gpr(t0, rt); -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ tcg_gen_trunc_tl_i32(fp0, t0); -+ gen_store_fpr32(ctx, fp0, fs); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FR2GR_D: -+ gen_load_fpr64(ctx, t0, fs); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_GR2FR_D: -+ gen_load_gpr(t0, rt); -+ gen_store_fpr64(ctx, t0, fs); -+ break; -+ case OPC_LARCH_FRH2GR_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32h(ctx, fp0, fs); -+ tcg_gen_ext_i32_tl(t0, fp0); -+ tcg_temp_free_i32(fp0); -+ } -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_GR2FRH_W: -+ gen_load_gpr(t0, rt); -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ tcg_gen_trunc_tl_i32(fp0, t0); -+ gen_store_fpr32h(ctx, fp0, fs); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ default: -+ LARCH_INVAL("cp1 move"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ -+ out: -+ tcg_temp_free(t0); -+} -+ -+static inline void gen_movcf_ps(DisasContext *ctx, int fs, int fd, -+ int cc, int tf) -+{ -+ int cond; -+ TCGv_i32 t0 = tcg_temp_new_i32(); -+ TCGLabel *l1 = gen_new_label(); -+ TCGLabel *l2 = gen_new_label(); -+ -+ if (tf) { -+ cond = TCG_COND_EQ; -+ } else { -+ cond = TCG_COND_NE; -+ } -+ -+ tcg_gen_andi_i32(t0, fpu_fcsr0, 1 << get_fp_bit(cc)); -+ tcg_gen_brcondi_i32(cond, t0, 0, l1); -+ gen_load_fpr32(ctx, t0, fs); -+ gen_store_fpr32(ctx, t0, fd); -+ gen_set_label(l1); -+ -+ tcg_gen_andi_i32(t0, fpu_fcsr0, 1 << get_fp_bit(cc + 1)); -+ tcg_gen_brcondi_i32(cond, t0, 0, l2); -+ gen_load_fpr32h(ctx, t0, fs); -+ gen_store_fpr32h(ctx, t0, fd); -+ tcg_temp_free_i32(t0); -+ gen_set_label(l2); -+} -+ -+static void gen_farith(DisasContext *ctx, uint32_t opc, -+ int ft, int fs, int fd, int cc) -+{ -+ check_cp1_enabled(ctx); -+ switch (opc) { -+ case OPC_LARCH_FADD_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_add_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FSUB_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_sub_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMUL_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_mul_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FDIV_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_div_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FSQRT_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_sqrt_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FABS_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_abs_s(fp0, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMOV_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FNEG_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_chs_s(fp0, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRNE_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_round_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINTRZ_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_trunc_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINTRP_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_ceil_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINTRM_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_floor_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINTRNE_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_round_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRZ_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_trunc_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRP_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_ceil_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRM_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_floor_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FRECIP_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_recip_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FRSQRT_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_rsqrt_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FRINT_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_rint_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FCLASS_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_class_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMIN_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ TCGv_i32 fp2 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_min_s(fp2, cpu_env, fp0, fp1); -+ gen_store_fpr32(ctx, fp2, fd); -+ tcg_temp_free_i32(fp2); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMINA_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ TCGv_i32 fp2 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_mina_s(fp2, cpu_env, fp0, fp1); -+ gen_store_fpr32(ctx, fp2, fd); -+ tcg_temp_free_i32(fp2); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMAX_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_max_s(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr32(ctx, fp1, fd); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMAXA_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_maxa_s(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr32(ctx, fp1, fd); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FCVT_D_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_cvtd_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINT_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_cvt_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINT_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_cvt_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FADD_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_add_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FSUB_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_sub_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMUL_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_mul_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FDIV_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_div_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FSQRT_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_sqrt_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FABS_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_abs_d(fp0, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMOV_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FNEG_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_chs_d(fp0, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRNE_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_round_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRZ_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_trunc_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRP_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_ceil_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRM_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_floor_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRNE_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_round_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINTRZ_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_trunc_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINTRP_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_ceil_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINTRM_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_floor_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FRECIP_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_recip_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FRSQRT_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_rsqrt_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FRINT_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_rint_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FCLASS_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_class_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMIN_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_min_d(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr64(ctx, fp1, fd); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMINA_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_mina_d(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr64(ctx, fp1, fd); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMAX_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_max_d(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr64(ctx, fp1, fd); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMAXA_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_maxa_d(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr64(ctx, fp1, fd); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FCVT_S_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_cvts_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINT_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_cvt_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINT_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_cvt_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FFINT_S_W: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_cvts_w(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FFINT_D_W: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_cvtd_w(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FFINT_S_L: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_cvts_l(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FFINT_D_L: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_cvtd_l(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ default: -+ LARCH_INVAL("farith"); -+ generate_exception_end(ctx, EXCP_RI); -+ return; -+ } -+} -+ -+/* Coprocessor 3 (FPU) */ -+static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc, -+ int fd, int fs, int base, int index) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ check_cp1_enabled(ctx); -+ if (base == 0) { -+ gen_load_gpr(t0, index); -+ } else if (index == 0) { -+ gen_load_gpr(t0, base); -+ } else { -+ gen_op_addr_add(ctx, t0, cpu_gpr[base], cpu_gpr[index]); -+ } -+ -+ /* -+ * Don't do NOP if destination is zero: we must perform the actual -+ * memory access. -+ */ -+ switch (opc) { -+ case OPC_LARCH_FLDX_S: -+ case OPC_LARCH_FLDGT_S: -+ case OPC_LARCH_FLDLE_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL); -+ tcg_gen_trunc_tl_i32(fp0, t0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FLDX_D: -+ case OPC_LARCH_FLDGT_D: -+ case OPC_LARCH_FLDLE_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FSTX_S: -+ case OPC_LARCH_FSTGT_S: -+ case OPC_LARCH_FSTLE_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FSTX_D: -+ case OPC_LARCH_FSTGT_D: -+ case OPC_LARCH_FSTLE_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ } -+ tcg_temp_free(t0); -+} -+ -+static inline void clear_branch_hflags(DisasContext *ctx) -+{ -+ ctx->hflags &= ~LARCH_HFLAG_BMASK; -+ if (ctx->base.is_jmp == DISAS_NEXT) { -+ save_cpu_state(ctx, 0); -+ } else { -+ /* -+ * It is not safe to save ctx->hflags as hflags may be changed -+ * in execution time. -+ */ -+ tcg_gen_andi_i32(hflags, hflags, ~LARCH_HFLAG_BMASK); -+ } -+} -+ -+static void gen_branch(DisasContext *ctx, int insn_bytes) -+{ -+ if (ctx->hflags & LARCH_HFLAG_BMASK) { -+ int proc_hflags = ctx->hflags & LARCH_HFLAG_BMASK; -+ /* Branches completion */ -+ clear_branch_hflags(ctx); -+ ctx->base.is_jmp = DISAS_NORETURN; -+ /* FIXME: Need to clear can_do_io. */ -+ switch (proc_hflags & LARCH_HFLAG_BMASK) { -+ case LARCH_HFLAG_B: -+ /* unconditional branch */ -+ gen_goto_tb(ctx, 0, ctx->btarget); -+ break; -+ case LARCH_HFLAG_BC: -+ /* Conditional branch */ -+ { -+ TCGLabel *l1 = gen_new_label(); -+ -+ tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1); -+ gen_goto_tb(ctx, 1, ctx->base.pc_next + insn_bytes); -+ gen_set_label(l1); -+ gen_goto_tb(ctx, 0, ctx->btarget); -+ } -+ break; -+ case LARCH_HFLAG_BR: -+ /* unconditional branch to register */ -+ tcg_gen_mov_tl(cpu_PC, btarget); -+ if (ctx->base.singlestep_enabled) { -+ save_cpu_state(ctx, 0); -+ gen_helper_raise_exception_debug(cpu_env); -+ } -+ tcg_gen_lookup_and_goto_ptr(); -+ break; -+ default: -+ fprintf(stderr, "unknown branch 0x%x\n", proc_hflags); -+ abort(); -+ } -+ } -+} -+ -+/* Signed immediate */ -+#define SIMM(op, start, width) \ -+ ((int32_t)(((op >> start) & ((~0U) >> (32 - width))) \ -+ << (32 - width)) \ -+ >> (32 - width)) -+/* Zero-extended immediate */ -+#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32 - width))) -+ -+static void gen_sync(int stype) -+{ -+ TCGBar tcg_mo = TCG_BAR_SC; -+ -+ switch (stype) { -+ case 0x4: /* SYNC_WMB */ -+ tcg_mo |= TCG_MO_ST_ST; -+ break; -+ case 0x10: /* SYNC_MB */ -+ tcg_mo |= TCG_MO_ALL; -+ break; -+ case 0x11: /* SYNC_ACQUIRE */ -+ tcg_mo |= TCG_MO_LD_LD | TCG_MO_LD_ST; -+ break; -+ case 0x12: /* SYNC_RELEASE */ -+ tcg_mo |= TCG_MO_ST_ST | TCG_MO_LD_ST; -+ break; -+ case 0x13: /* SYNC_RMB */ -+ tcg_mo |= TCG_MO_LD_LD; -+ break; -+ default: -+ tcg_mo |= TCG_MO_ALL; -+ break; -+ } -+ -+ tcg_gen_mb(tcg_mo); -+} -+ -+static void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz, -+ int crc32c) -+{ -+ TCGv t0; -+ TCGv t1; -+ TCGv_i32 tsz = tcg_const_i32(1 << sz); -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, rt); -+ gen_load_gpr(t1, rs); -+ -+ if (crc32c) { -+ gen_helper_crc32c(cpu_gpr[rd], t0, t1, tsz); -+ } else { -+ gen_helper_crc32(cpu_gpr[rd], t0, t1, tsz); -+ } -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ tcg_temp_free_i32(tsz); -+} -+ -+#include "cpu-csr.h" -+ -+#ifndef CONFIG_USER_ONLY -+ -+/* -+ * 64-bit CSR read -+ * -+ * @arg : GPR to store the value of CSR register -+ * @csr : CSR register number -+ */ -+static void gen_csr_rdq(DisasContext *ctx, TCGv rd, int64_t a1) -+{ -+ TCGv_i64 csr = tcg_const_i64(a1); -+ gen_helper_csr_rdq(rd, cpu_env, csr); -+} -+ -+/* -+ * 64-bit CSR write -+ * -+ * @arg : GPR that stores the new value of CSR register -+ * @csr : CSR register number -+ */ -+static void gen_csr_wrq(DisasContext *ctx, TCGv val, int64_t a1) -+{ -+ TCGv_i64 csr = tcg_const_i64(a1); -+ gen_helper_csr_wrq(val, cpu_env, val, csr); -+} -+ -+/* -+ * 64-bit CSR exchange -+ * -+ * @arg : GPR that stores the new value of CSR register -+ * @csr : CSR register number -+ */ -+static void gen_csr_xchgq(DisasContext *ctx, TCGv val, TCGv mask, int64_t a1) -+{ -+ TCGv_i64 csr = tcg_const_i64(a1); -+ gen_helper_csr_xchgq(val, cpu_env, val, mask, csr); -+} -+#endif /* !CONFIG_USER_ONLY */ -+ -+static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, -+ CPUState *cs) -+{ -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ CPULOONGARCHState *env = cs->env_ptr; -+ -+ ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; -+ ctx->saved_pc = -1; -+ ctx->insn_flags = env->insn_flags; -+ ctx->btarget = 0; -+ /* Restore state from the tb context. */ -+ ctx->hflags = (uint32_t)ctx->base.tb->flags; /* FIXME: maybe use 64 bits? */ -+ restore_cpu_state(env, ctx); -+#ifdef CONFIG_USER_ONLY -+ ctx->mem_idx = LARCH_HFLAG_UM; -+#else -+ ctx->mem_idx = hflags_mmu_index(ctx->hflags); -+#endif -+ ctx->default_tcg_memop_mask = MO_ALIGN; -+ -+ LOG_DISAS("\ntb %p idx %d hflags %04x\n", ctx->base.tb, ctx->mem_idx, -+ ctx->hflags); -+} -+ -+static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) -+{ -+} -+ -+static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) -+{ -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ -+ tcg_gen_insn_start(ctx->base.pc_next, ctx->hflags & LARCH_HFLAG_BMASK, -+ ctx->btarget); -+} -+#if 0 -+static bool loongarch_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, -+ const CPUBreakpoint *bp) -+{ -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ -+ save_cpu_state(ctx, 1); -+ ctx->base.is_jmp = DISAS_NORETURN; -+ gen_helper_raise_exception_debug(cpu_env); -+ /* The address covered by the breakpoint must be included in -+ [tb->pc, tb->pc + tb->size) in order to for it to be -+ properly cleared -- thus we increment the PC here so that -+ the logic setting tb->size below does the right thing. */ -+ ctx->base.pc_next += 4; -+ return true; -+} -+#endif -+/* 128 and 256 lsx vector instructions are not supported yet */ -+static bool decode_vector_lsx(uint32_t opcode) -+{ -+ uint32_t value = (opcode & 0xff000000); -+ -+ if ((opcode & 0xf0000000) == 0x70000000) { -+ return true; -+ } else if ((opcode & 0xfff00000) == 0x38400000) { -+ return true; -+ } else { -+ switch (value) { -+ case 0x09000000: -+ case 0x0a000000: -+ case 0x0e000000: -+ case 0x0f000000: -+ case 0x2c000000: -+ case 0x30000000: -+ case 0x31000000: -+ case 0x32000000: -+ case 0x33000000: -+ return true; -+ } -+ } -+ return false; -+} -+ -+static bool decode_insn(DisasContext *ctx, uint32_t insn); -+#include "decode-insn.c.inc" -+#include "trans.inc.c" -+ -+static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) -+{ -+ CPULOONGARCHState *env = cs->env_ptr; -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ int insn_bytes = 4; -+ -+ ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next); -+ -+ if (!decode_insn(ctx, ctx->opcode)) { -+ if (decode_vector_lsx(ctx->opcode)) { -+ generate_exception_end(ctx, EXCP_RI); -+ } else { -+ fprintf(stderr, "Error: unkown opcode. 0x%lx: 0x%x\n", -+ ctx->base.pc_next, ctx->opcode); -+ generate_exception_end(ctx, EXCP_RI); -+ } -+ } -+ -+ if (ctx->hflags & LARCH_HFLAG_BMASK) { -+ gen_branch(ctx, insn_bytes); -+ } -+ ctx->base.pc_next += insn_bytes; -+} -+ -+static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) -+{ -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ -+ if (ctx->base.singlestep_enabled && ctx->base.is_jmp != DISAS_NORETURN) { -+ save_cpu_state(ctx, ctx->base.is_jmp != DISAS_EXIT); -+ gen_helper_raise_exception_debug(cpu_env); -+ } else { -+ switch (ctx->base.is_jmp) { -+ case DISAS_STOP: -+ gen_save_pc(ctx->base.pc_next); -+ tcg_gen_lookup_and_goto_ptr(); -+ break; -+ case DISAS_NEXT: -+ case DISAS_TOO_MANY: -+ save_cpu_state(ctx, 0); -+ gen_goto_tb(ctx, 0, ctx->base.pc_next); -+ break; -+ case DISAS_EXIT: -+ tcg_gen_exit_tb(NULL, 0); -+ break; -+ case DISAS_NORETURN: -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ } -+} -+ -+static void loongarch_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) -+{ -+ qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); -+ log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); -+} -+ -+static const TranslatorOps loongarch_tr_ops = { -+ .init_disas_context = loongarch_tr_init_disas_context, -+ .tb_start = loongarch_tr_tb_start, -+ .insn_start = loongarch_tr_insn_start, -+#if 0 -+ .breakpoint_check = loongarch_tr_breakpoint_check, -+#endif -+ .translate_insn = loongarch_tr_translate_insn, -+ .tb_stop = loongarch_tr_tb_stop, -+ .disas_log = loongarch_tr_disas_log, -+}; -+ -+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb, int max_insns) -+{ -+ DisasContext ctx; -+ -+ translator_loop(&loongarch_tr_ops, &ctx.base, cs, tb, max_insns); -+} -+ -+void loongarch_tcg_init(void) -+{ -+ int i; -+ -+ for (i = 0; i < 32; i++) -+ cpu_gpr[i] = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, -+ active_tc.gpr[i]), -+ regnames[i]); -+ -+ for (i = 0; i < 32; i++) { -+ int off = offsetof(CPULOONGARCHState, active_fpu.fpr[i].d); -+ fpu_f64[i] = tcg_global_mem_new_i64(cpu_env, off, fregnames[i]); -+ } -+ -+ cpu_PC = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, active_tc.PC), "PC"); -+ bcond = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, bcond), "bcond"); -+ btarget = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, btarget), "btarget"); -+ hflags = tcg_global_mem_new_i32(cpu_env, -+ offsetof(CPULOONGARCHState, hflags), "hflags"); -+ fpu_fcsr0 = tcg_global_mem_new_i32(cpu_env, -+ offsetof(CPULOONGARCHState, active_fpu.fcsr0), -+ "fcsr0"); -+ cpu_lladdr = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, lladdr), -+ "lladdr"); -+ cpu_llval = tcg_global_mem_new(cpu_env, offsetof(CPULOONGARCHState, llval), -+ "llval"); -+} -+ -+void restore_state_to_opc(CPULOONGARCHState *env, TranslationBlock *tb, -+ target_ulong *data) -+{ -+ env->active_tc.PC = data[0]; -+ env->hflags &= ~LARCH_HFLAG_BMASK; -+ env->hflags |= data[1]; -+ switch (env->hflags & LARCH_HFLAG_BMASK) { -+ case LARCH_HFLAG_BR: -+ break; -+ case LARCH_HFLAG_BC: -+ case LARCH_HFLAG_B: -+ env->btarget = data[2]; -+ break; -+ } -+} -diff --git a/target/meson.build b/target/meson.build -index 2f6940255..ac0ce618b 100644 ---- a/target/meson.build -+++ b/target/meson.build -@@ -5,6 +5,7 @@ subdir('cris') - subdir('hexagon') - subdir('hppa') - subdir('i386') -+subdir('loongarch64') - subdir('m68k') - subdir('microblaze') - subdir('mips') --- -2.43.5 - diff --git a/0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch b/0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch deleted file mode 100644 index 1ea643b..0000000 --- a/0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 630d76cc15bd98669162f785861cdd81f2ee8f01 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Wed, 25 Aug 2021 12:25:05 +0800 -Subject: [PATCH 4/8] anolis: csv/i386: add command to load vmcb to guest - memory - -The KVM_CSV_LAUNCH_ENCRYPT_VMCB command is used to load and encrypt -the initial VMCB data to secure memory in an isolated region -that guest owns. - -Signed-off-by: Xin Jiang -Change-Id: I821bc8ab726f1bd22df36c163196951504eaa8da ---- - linux-headers/linux/kvm.h | 1 + - target/i386/csv-sysemu-stub.c | 5 +++++ - target/i386/csv.c | 21 +++++++++++++++++++++ - target/i386/csv.h | 1 + - target/i386/sev.c | 7 +++++-- - 5 files changed, 33 insertions(+), 2 deletions(-) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 53f9202ffb..c6cd3a619a 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1814,6 +1814,7 @@ enum csv_cmd_id { - - KVM_CSV_INIT = KVM_CSV_NR_MIN, - KVM_CSV_LAUNCH_ENCRYPT_DATA, -+ KVM_CSV_LAUNCH_ENCRYPT_VMCB, - }; - - struct kvm_csv_launch_encrypt_data { -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index 236a6909d2..a5ce986e3c 100644 ---- a/target/i386/csv-sysemu-stub.c -+++ b/target/i386/csv-sysemu-stub.c -@@ -24,3 +24,8 @@ int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) - { - g_assert_not_reached(); - } -+ -+int csv_launch_encrypt_vmcb(void) -+{ -+ g_assert_not_reached(); -+} -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 3b3dff5174..d166d3775e 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -162,3 +162,24 @@ csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) - - return ret; - } -+ -+int -+csv_launch_encrypt_vmcb(void) -+{ -+ int ret, fw_error; -+ -+ if (!csv_enabled()) { -+ error_report("%s: CSV is not enabled",__func__); -+ return -1; -+ } -+ -+ ret = csv_ioctl(KVM_CSV_LAUNCH_ENCRYPT_VMCB, NULL, &fw_error); -+ if (ret) { -+ error_report("%s: CSV LAUNCH_ENCRYPT_VMCB ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+err: -+ return ret; -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 6f7b112d96..7dc5c75366 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -34,6 +34,7 @@ typedef struct CsvGuestState CsvGuestState; - - extern struct CsvGuestState csv_guest; - extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); -+extern int csv_launch_encrypt_vmcb(void); - - int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 023532f4ec..73a794ef74 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -770,8 +770,11 @@ sev_launch_get_measure(Notifier *notifier, void *unused) - } - - if (sev_es_enabled()) { -- /* measure all the VM save areas before getting launch_measure */ -- ret = sev_launch_update_vmsa(sev); -+ if (csv_enabled()) -+ ret = csv_launch_encrypt_vmcb(); -+ else -+ /* measure all the VM save areas before getting launch_measure */ -+ ret = sev_launch_update_vmsa(sev); - if (ret) { - exit(1); - } --- -2.17.1 - diff --git a/0005-Add-linux-headers-and-linux-user.patch b/0005-Add-linux-headers-and-linux-user.patch deleted file mode 100644 index 8e5b37e..0000000 --- a/0005-Add-linux-headers-and-linux-user.patch +++ /dev/null @@ -1,1663 +0,0 @@ -From be4aee607329aee902b9a03936523c7d57d47100 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:47:06 -0400 -Subject: [PATCH 05/28] Add linux-headers and linux-user. - -Change-Id: If052442a981fed87c03ca431c010629dc8e872ca -Signed-off-by: lixianglai ---- - linux-headers/asm-loongarch64/bitsperlong.h | 9 + - linux-headers/asm-loongarch64/kvm.h | 346 ++++++++++++++++++++ - linux-headers/asm-loongarch64/sgidefs.h | 20 ++ - linux-headers/asm-loongarch64/unistd.h | 23 ++ - linux-user/loongarch64/cpu_loop.c | 193 +++++++++++ - linux-user/loongarch64/meson.build | 6 + - linux-user/loongarch64/signal.c | 212 ++++++++++++ - linux-user/loongarch64/sockbits.h | 1 + - linux-user/loongarch64/syscall_nr.h | 287 ++++++++++++++++ - linux-user/loongarch64/target_cpu.h | 45 +++ - linux-user/loongarch64/target_elf.h | 14 + - linux-user/loongarch64/target_fcntl.h | 13 + - linux-user/loongarch64/target_signal.h | 23 ++ - linux-user/loongarch64/target_structs.h | 62 ++++ - linux-user/loongarch64/target_syscall.h | 44 +++ - linux-user/loongarch64/termbits.h | 224 +++++++++++++ - 16 files changed, 1522 insertions(+) - create mode 100644 linux-headers/asm-loongarch64/bitsperlong.h - create mode 100644 linux-headers/asm-loongarch64/kvm.h - create mode 100644 linux-headers/asm-loongarch64/sgidefs.h - create mode 100644 linux-headers/asm-loongarch64/unistd.h - create mode 100644 linux-user/loongarch64/cpu_loop.c - create mode 100644 linux-user/loongarch64/meson.build - create mode 100644 linux-user/loongarch64/signal.c - create mode 100644 linux-user/loongarch64/sockbits.h - create mode 100644 linux-user/loongarch64/syscall_nr.h - create mode 100644 linux-user/loongarch64/target_cpu.h - create mode 100644 linux-user/loongarch64/target_elf.h - create mode 100644 linux-user/loongarch64/target_fcntl.h - create mode 100644 linux-user/loongarch64/target_signal.h - create mode 100644 linux-user/loongarch64/target_structs.h - create mode 100644 linux-user/loongarch64/target_syscall.h - create mode 100644 linux-user/loongarch64/termbits.h - -diff --git a/linux-headers/asm-loongarch64/bitsperlong.h b/linux-headers/asm-loongarch64/bitsperlong.h -new file mode 100644 -index 000000000..5c2c8779a ---- /dev/null -+++ b/linux-headers/asm-loongarch64/bitsperlong.h -@@ -0,0 +1,9 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+#ifndef __ASM_LOONGARCH_BITSPERLONG_H -+#define __ASM_LOONGARCH_BITSPERLONG_H -+ -+#define __BITS_PER_LONG _LOONGARCH_SZLONG -+ -+#include -+ -+#endif /* __ASM_LOONGARCH_BITSPERLONG_H */ -diff --git a/linux-headers/asm-loongarch64/kvm.h b/linux-headers/asm-loongarch64/kvm.h -new file mode 100644 -index 000000000..a24375ee5 ---- /dev/null -+++ b/linux-headers/asm-loongarch64/kvm.h -@@ -0,0 +1,346 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * Copyright (C) 2020 Loongson Technologies, Inc. All rights reserved. -+ * Authors: Sanjay Lal -+ * Authors: Xing Li -+ */ -+ -+#ifndef __LINUX_KVM_LOONGARCH_H -+#define __LINUX_KVM_LOONGARCH_H -+ -+#include -+ -+#define __KVM_HAVE_GUEST_DEBUG -+#define KVM_GUESTDBG_USE_SW_BP 0x00010000 -+#define KVM_GUESTDBG_USE_HW_BP 0x00020000 -+#define KVM_DATA_HW_BREAKPOINT_NUM 8 -+#define KVM_INST_HW_BREAKPOINT_NUM 8 -+ -+/* -+ * KVM Loongarch specific structures and definitions. -+ * -+ * Some parts derived from the x86 version of this file. -+ */ -+ -+#define __KVM_HAVE_READONLY_MEM -+ -+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 -+ -+#define KVM_LARCH_VCPU_PVTIME_CTRL 2 -+#define KVM_LARCH_VCPU_PVTIME_IPA 0 -+ -+/* -+ * for KVM_GET_REGS and KVM_SET_REGS -+ */ -+struct kvm_regs { -+ /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ -+ __u64 gpr[32]; -+ __u64 pc; -+}; -+ -+/* -+ * for KVM_GET_CPUCFG -+ */ -+struct kvm_cpucfg { -+ /* out (KVM_GET_CPUCFG) */ -+ __u32 cpucfg[64]; -+}; -+ -+/* -+ * for KVM_GET_FPU and KVM_SET_FPU -+ */ -+struct kvm_fpu { -+ __u32 fcsr; -+ __u32 vcsr; -+ __u64 fcc; /* 8x8 */ -+ struct kvm_fpureg { -+ __u64 val64[4]; //support max 256 bits -+ }fpr[32]; -+}; -+ -+/* -+ * For LOONGARCH, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various -+ * registers. The id field is broken down as follows: -+ * -+ * bits[63..52] - As per linux/kvm.h -+ * bits[51..32] - Must be zero. -+ * bits[31..16] - Register set. -+ * -+ * Register set = 0: GP registers from kvm_regs (see definitions below). -+ * -+ * Register set = 1: CP0 registers. -+ * bits[15..8] - COP0 register set. -+ * -+ * COP0 register set = 0: Main CP0 registers. -+ * bits[7..3] - Register 'rd' index. -+ * bits[2..0] - Register 'sel' index. -+ * -+ * COP0 register set = 1: MAARs. -+ * bits[7..0] - MAAR index. -+ * -+ * Register set = 2: KVM specific registers (see definitions below). -+ * -+ * Register set = 3: FPU / MSA registers (see definitions below). -+ * -+ * Other sets registers may be added in the future. Each set would -+ * have its own identifier in bits[31..16]. -+ */ -+ -+#define KVM_REG_LOONGARCH_GP (KVM_REG_LOONGARCH | 0x0000000000000000ULL) -+#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x0000000000010000ULL) -+#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x0000000000020000ULL) -+#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x0000000000030000ULL) -+ -+ -+/* -+ * KVM_REG_LOONGARCH_GP - General purpose registers from kvm_regs. -+ */ -+ -+#define KVM_REG_LOONGARCH_R0 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 0) -+#define KVM_REG_LOONGARCH_R1 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 1) -+#define KVM_REG_LOONGARCH_R2 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 2) -+#define KVM_REG_LOONGARCH_R3 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 3) -+#define KVM_REG_LOONGARCH_R4 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 4) -+#define KVM_REG_LOONGARCH_R5 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 5) -+#define KVM_REG_LOONGARCH_R6 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 6) -+#define KVM_REG_LOONGARCH_R7 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 7) -+#define KVM_REG_LOONGARCH_R8 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 8) -+#define KVM_REG_LOONGARCH_R9 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 9) -+#define KVM_REG_LOONGARCH_R10 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 10) -+#define KVM_REG_LOONGARCH_R11 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 11) -+#define KVM_REG_LOONGARCH_R12 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 12) -+#define KVM_REG_LOONGARCH_R13 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 13) -+#define KVM_REG_LOONGARCH_R14 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 14) -+#define KVM_REG_LOONGARCH_R15 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 15) -+#define KVM_REG_LOONGARCH_R16 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 16) -+#define KVM_REG_LOONGARCH_R17 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 17) -+#define KVM_REG_LOONGARCH_R18 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 18) -+#define KVM_REG_LOONGARCH_R19 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 19) -+#define KVM_REG_LOONGARCH_R20 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 20) -+#define KVM_REG_LOONGARCH_R21 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 21) -+#define KVM_REG_LOONGARCH_R22 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 22) -+#define KVM_REG_LOONGARCH_R23 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 23) -+#define KVM_REG_LOONGARCH_R24 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 24) -+#define KVM_REG_LOONGARCH_R25 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 25) -+#define KVM_REG_LOONGARCH_R26 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 26) -+#define KVM_REG_LOONGARCH_R27 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 27) -+#define KVM_REG_LOONGARCH_R28 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 28) -+#define KVM_REG_LOONGARCH_R29 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 29) -+#define KVM_REG_LOONGARCH_R30 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 30) -+#define KVM_REG_LOONGARCH_R31 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 31) -+ -+#define KVM_REG_LOONGARCH_HI (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 32) -+#define KVM_REG_LOONGARCH_LO (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 33) -+#define KVM_REG_LOONGARCH_PC (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 34) -+ -+ -+/* -+ * KVM_REG_LOONGARCH_KVM - KVM specific control registers. -+ */ -+ -+/* -+ * CP0_Count control -+ * DC: Set 0: Master disable CP0_Count and set COUNT_RESUME to now -+ * Set 1: Master re-enable CP0_Count with unchanged bias, handling timer -+ * interrupts since COUNT_RESUME -+ * This can be used to freeze the timer to get a consistent snapshot of -+ * the CP0_Count and timer interrupt pending state, while also resuming -+ * safely without losing time or guest timer interrupts. -+ * Other: Reserved, do not change. -+ */ -+#define KVM_REG_LOONGARCH_COUNT_CTL (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 0) -+#define KVM_REG_LOONGARCH_COUNT_CTL_DC 0x00000001 -+ -+/* -+ * CP0_Count resume monotonic nanoseconds -+ * The monotonic nanosecond time of the last set of COUNT_CTL.DC (master -+ * disable). Any reads and writes of Count related registers while -+ * COUNT_CTL.DC=1 will appear to occur at this time. When COUNT_CTL.DC is -+ * cleared again (master enable) any timer interrupts since this time will be -+ * emulated. -+ * Modifications to times in the future are rejected. -+ */ -+#define KVM_REG_LOONGARCH_COUNT_RESUME (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 1) -+/* -+ * CP0_Count rate in Hz -+ * Specifies the rate of the CP0_Count timer in Hz. Modifications occur without -+ * discontinuities in CP0_Count. -+ */ -+#define KVM_REG_LOONGARCH_COUNT_HZ (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 2) -+ -+#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3) -+ -+#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4) -+ -+struct kvm_iocsr_entry { -+ __u32 addr; -+ __u32 pad; -+ __u64 data; -+}; -+ -+struct kvm_csr_entry { -+ __u32 index; -+ __u32 reserved; -+ __u64 data; -+}; -+ -+/* for KVM_GET_MSRS and KVM_SET_MSRS */ -+struct kvm_msrs { -+ __u32 ncsrs; /* number of msrs in entries */ -+ __u32 pad; -+ struct kvm_csr_entry entries[0]; -+}; -+ -+#define __KVM_HAVE_IRQ_LINE -+ -+struct kvm_debug_exit_arch { -+ __u64 epc; -+ __u32 fwps; -+ __u32 mwps; -+ __u32 exception; -+}; -+ -+/* for KVM_SET_GUEST_DEBUG */ -+struct hw_breakpoint { -+ __u64 addr; -+ __u64 mask; -+ __u32 asid; -+ __u32 ctrl; -+}; -+ -+struct kvm_guest_debug_arch { -+ struct hw_breakpoint data_breakpoint[KVM_DATA_HW_BREAKPOINT_NUM]; -+ struct hw_breakpoint inst_breakpoint[KVM_INST_HW_BREAKPOINT_NUM]; -+ int inst_bp_nums, data_bp_nums; -+}; -+ -+/* definition of registers in kvm_run */ -+struct kvm_sync_regs { -+}; -+ -+/* dummy definition */ -+struct kvm_sregs { -+}; -+ -+struct kvm_loongarch_interrupt { -+ /* in */ -+ __u32 cpu; -+ __u32 irq; -+}; -+ -+#define KVM_IRQCHIP_LS7A_IOAPIC 0x0 -+#define KVM_IRQCHIP_LS3A_GIPI 0x1 -+#define KVM_IRQCHIP_LS3A_HT_IRQ 0x2 -+#define KVM_IRQCHIP_LS3A_ROUTE 0x3 -+#define KVM_IRQCHIP_LS3A_EXTIRQ 0x4 -+#define KVM_IRQCHIP_LS3A_IPMASK 0x5 -+#define KVM_NR_IRQCHIPS 1 -+#define KVM_IRQCHIP_NUM_PINS 64 -+ -+#define KVM_MAX_CORES 256 -+#define KVM_EXTIOI_IRQS (256) -+#define KVM_EXTIOI_IRQS_BITMAP_SIZE (KVM_EXTIOI_IRQS / 8) -+/* map to ipnum per 32 irqs */ -+#define KVM_EXTIOI_IRQS_IPMAP_SIZE (KVM_EXTIOI_IRQS / 32) -+#define KVM_EXTIOI_IRQS_PER_GROUP 32 -+#define KVM_EXTIOI_IRQS_COREMAP_SIZE (KVM_EXTIOI_IRQS) -+#define KVM_EXTIOI_IRQS_NODETYPE_SIZE 16 -+ -+struct ls7a_ioapic_state { -+ __u64 int_id; -+ /* 0x020 interrupt mask register */ -+ __u64 int_mask; -+ /* 0x040 1=msi */ -+ __u64 htmsi_en; -+ /* 0x060 edge=1 level =0 */ -+ __u64 intedge; -+ /* 0x080 for clean edge int,set 1 clean,set 0 is noused */ -+ __u64 intclr; -+ /* 0x0c0 */ -+ __u64 auto_crtl0; -+ /* 0x0e0 */ -+ __u64 auto_crtl1; -+ /* 0x100 - 0x140 */ -+ __u8 route_entry[64]; -+ /* 0x200 - 0x240 */ -+ __u8 htmsi_vector[64]; -+ /* 0x300 */ -+ __u64 intisr_chip0; -+ /* 0x320 */ -+ __u64 intisr_chip1; -+ /* edge detection */ -+ __u64 last_intirr; -+ /* 0x380 interrupt request register */ -+ __u64 intirr; -+ /* 0x3a0 interrupt service register */ -+ __u64 intisr; -+ /* 0x3e0 interrupt level polarity selection register, -+ * 0 for high level tirgger -+ */ -+ __u64 int_polarity; -+}; -+ -+struct loongarch_gipi_single { -+ __u32 status; -+ __u32 en; -+ __u32 set; -+ __u32 clear; -+ __u64 buf[4]; -+}; -+ -+struct loongarch_gipiState { -+ struct loongarch_gipi_single core[KVM_MAX_CORES]; -+}; -+ -+struct kvm_loongarch_ls3a_extirq_state { -+ union ext_en_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_BITMAP_SIZE]; -+ } ext_en_r; -+ union bounce_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_BITMAP_SIZE]; -+ } bounce_r; -+ union ext_isr_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_BITMAP_SIZE]; -+ } ext_isr_r; -+ union ext_core_isr_r { -+ uint64_t reg_u64[KVM_MAX_CORES][KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_MAX_CORES][KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_MAX_CORES][KVM_EXTIOI_IRQS_BITMAP_SIZE]; -+ } ext_core_isr_r; -+ union ip_map_r { -+ uint64_t reg_u64; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_IPMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_IPMAP_SIZE]; -+ } ip_map_r; -+ union core_map_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_COREMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_COREMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_COREMAP_SIZE]; -+ } core_map_r; -+ union node_type_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_NODETYPE_SIZE / 4]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_NODETYPE_SIZE / 2]; -+ uint16_t reg_u16[KVM_EXTIOI_IRQS_NODETYPE_SIZE]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_NODETYPE_SIZE * 2]; -+ } node_type_r; -+}; -+ -+struct loongarch_kvm_irqchip { -+ __u16 chip_id; -+ __u16 len; -+ __u16 vcpu_id; -+ __u16 reserved; -+ char data[0]; -+}; -+ -+#endif /* __LINUX_KVM_LOONGARCH_H */ -diff --git a/linux-headers/asm-loongarch64/sgidefs.h b/linux-headers/asm-loongarch64/sgidefs.h -new file mode 100644 -index 000000000..b80960834 ---- /dev/null -+++ b/linux-headers/asm-loongarch64/sgidefs.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -+/* -+* Copyright (C) 2020 Loongson Technology Corporation Limited -+* -+* Author: Hanlu Li -+*/ -+#ifndef __ASM_SGIDEFS_H -+#define __ASM_SGIDEFS_H -+ -+#define _LOONGARCH_ISA_LOONGARCH32 6 -+#define _LOONGARCH_ISA_LOONGARCH64 7 -+ -+/* -+ * Subprogram calling convention -+ */ -+#define _LOONGARCH_SIM_ABILP32 1 -+#define _LOONGARCH_SIM_ABILPX32 2 -+#define _LOONGARCH_SIM_ABILP64 3 -+ -+#endif /* __ASM_SGIDEFS_H */ -diff --git a/linux-headers/asm-loongarch64/unistd.h b/linux-headers/asm-loongarch64/unistd.h -new file mode 100644 -index 000000000..2a6014562 ---- /dev/null -+++ b/linux-headers/asm-loongarch64/unistd.h -@@ -0,0 +1,23 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program 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 General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ * Copyright (C) 2020 Loongson Technologies, Inc. -+ * Authors: Jun Yi -+ */ -+ -+#ifdef __LP64__ -+#define __ARCH_WANT_NEW_STAT -+#endif /* __LP64__ */ -+ -+#include -diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c -new file mode 100644 -index 000000000..6d4093e1d ---- /dev/null -+++ b/linux-user/loongarch64/cpu_loop.c -@@ -0,0 +1,193 @@ -+/* -+ * qemu user cpu loop -+ * -+ * Copyright (c) 2003-2008 Fabrice Bellard -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program 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 General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu.h" -+#include "cpu_loop-common.h" -+#include "elf.h" -+ -+/* Break codes */ -+enum { -+ BRK_OVERFLOW = 6, -+ BRK_DIVZERO = 7 -+}; -+ -+static int do_break(CPULOONGARCHState *env, target_siginfo_t *info, -+ unsigned int code) -+{ -+ int ret = -1; -+ -+ switch (code) { -+ case BRK_OVERFLOW: -+ case BRK_DIVZERO: -+ info->si_signo = TARGET_SIGFPE; -+ info->si_errno = 0; -+ info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV; -+ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); -+ ret = 0; -+ break; -+ default: -+ info->si_signo = TARGET_SIGTRAP; -+ info->si_errno = 0; -+ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); -+ ret = 0; -+ break; -+ } -+ -+ return ret; -+} -+ -+void cpu_loop(CPULOONGARCHState *env) -+{ -+ CPUState *cs = CPU(loongarch_env_get_cpu(env)); -+ target_siginfo_t info; -+ int trapnr; -+ abi_long ret; -+ -+ for (;;) { -+ cpu_exec_start(cs); -+ trapnr = cpu_exec(cs); -+ cpu_exec_end(cs); -+ process_queued_cpu_work(cs); -+ -+ switch (trapnr) { -+ case EXCP_SYSCALL: -+ env->active_tc.PC += 4; -+ ret = do_syscall(env, env->active_tc.gpr[11], -+ env->active_tc.gpr[4], env->active_tc.gpr[5], -+ env->active_tc.gpr[6], env->active_tc.gpr[7], -+ env->active_tc.gpr[8], env->active_tc.gpr[9], -+ -1, -1); -+ if (ret == -TARGET_ERESTARTSYS) { -+ env->active_tc.PC -= 4; -+ break; -+ } -+ if (ret == -TARGET_QEMU_ESIGRETURN) { -+ /* Returning from a successful sigreturn syscall. -+ Avoid clobbering register state. */ -+ break; -+ } -+ env->active_tc.gpr[4] = ret; -+ break; -+ case EXCP_TLBL: -+ case EXCP_TLBS: -+ case EXCP_AdEL: -+ case EXCP_AdES: -+ info.si_signo = TARGET_SIGSEGV; -+ info.si_errno = 0; -+ /* XXX: check env->error_code */ -+ info.si_code = TARGET_SEGV_MAPERR; -+ info._sifields._sigfault._addr = env->CSR_BADV; -+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); -+ break; -+ case EXCP_FPDIS: -+ case EXCP_LSXDIS: -+ case EXCP_LASXDIS: -+ case EXCP_RI: -+ info.si_signo = TARGET_SIGILL; -+ info.si_errno = 0; -+ info.si_code = 0; -+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); -+ break; -+ case EXCP_INTERRUPT: -+ /* just indicate that signals should be handled asap */ -+ break; -+ case EXCP_DEBUG: -+ info.si_signo = TARGET_SIGTRAP; -+ info.si_errno = 0; -+ info.si_code = TARGET_TRAP_BRKPT; -+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); -+ break; -+ case EXCP_FPE: -+ info.si_signo = TARGET_SIGFPE; -+ info.si_errno = 0; -+ info.si_code = TARGET_FPE_FLTUNK; -+ if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_INVALID) { -+ info.si_code = TARGET_FPE_FLTINV; -+ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_DIV0) { -+ info.si_code = TARGET_FPE_FLTDIV; -+ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_OVERFLOW) { -+ info.si_code = TARGET_FPE_FLTOVF; -+ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_UNDERFLOW) { -+ info.si_code = TARGET_FPE_FLTUND; -+ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_INEXACT) { -+ info.si_code = TARGET_FPE_FLTRES; -+ } -+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); -+ break; -+ case EXCP_BREAK: -+ { -+ abi_ulong trap_instr; -+ unsigned int code; -+ -+ ret = get_user_u32(trap_instr, env->active_tc.PC); -+ if (ret != 0) { -+ goto error; -+ } -+ -+ code = trap_instr & 0x7fff; -+ -+ if (do_break(env, &info, code) != 0) { -+ goto error; -+ } -+ } -+ break; -+ case EXCP_TRAP: -+ { -+ abi_ulong trap_instr; -+ unsigned int code = 0; -+ -+ ret = get_user_u32(trap_instr, env->active_tc.PC); -+ -+ if (ret != 0) { -+ goto error; -+ } -+ -+ /* The immediate versions don't provide a code. */ -+ if (!(trap_instr & 0xFC000000)) { -+ code = ((trap_instr >> 6) & ((1 << 10) - 1)); -+ } -+ -+ if (do_break(env, &info, code) != 0) { -+ goto error; -+ } -+ } -+ break; -+ case EXCP_ATOMIC: -+ cpu_exec_step_atomic(cs); -+ break; -+ default: -+error: -+ printf("111111\n"); -+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); -+ abort(); -+ } -+ process_pending_signals(env); -+ } -+} -+ -+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) -+{ -+ int i; -+ -+ for (i = 0; i < 32; i++) { -+ env->active_tc.gpr[i] = regs->regs[i]; -+ } -+ env->active_tc.PC = regs->csr_era & ~(target_ulong)1; -+} -diff --git a/linux-user/loongarch64/meson.build b/linux-user/loongarch64/meson.build -new file mode 100644 -index 000000000..c4c0b4d70 ---- /dev/null -+++ b/linux-user/loongarch64/meson.build -@@ -0,0 +1,6 @@ -+syscall_nr_generators += { -+ 'loongarch64': generator(sh, -+ arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@', -+ '', 'TARGET_SYSCALL_OFFSET' ], -+ output: '@BASENAME@_nr.h') -+} -diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c -new file mode 100644 -index 000000000..6fe685275 ---- /dev/null -+++ b/linux-user/loongarch64/signal.c -@@ -0,0 +1,212 @@ -+/* -+ * Emulation of Linux signals -+ * -+ * Copyright (c) 2003 Fabrice Bellard -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program 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 General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+#include "qemu/osdep.h" -+#include "qemu.h" -+#include "signal-common.h" -+#include "linux-user/trace.h" -+ -+#define FPU_REG_WIDTH 256 -+union fpureg { -+ uint32_t val32[FPU_REG_WIDTH / 32]; -+ uint64_t val64[FPU_REG_WIDTH / 64]; -+}; -+ -+struct target_sigcontext { -+ uint64_t sc_pc; -+ uint64_t sc_regs[32]; -+ uint32_t sc_flags; -+ -+ uint32_t sc_fcsr; -+ uint32_t sc_vcsr; -+ uint64_t sc_fcc; -+ union fpureg sc_fpregs[32] __attribute__((aligned(32))); -+ -+ uint32_t sc_reserved; -+ -+}; -+ -+struct sigframe { -+ uint32_t sf_ass[4]; /* argument save space for o32 */ -+ uint32_t sf_code[2]; /* signal trampoline */ -+ struct target_sigcontext sf_sc; -+ target_sigset_t sf_mask; -+}; -+ -+struct target_ucontext { -+ target_ulong tuc_flags; -+ target_ulong tuc_link; -+ target_stack_t tuc_stack; -+ target_ulong pad0; -+ struct target_sigcontext tuc_mcontext; -+ target_sigset_t tuc_sigmask; -+}; -+ -+struct target_rt_sigframe { -+ uint32_t rs_ass[4]; /* argument save space for o32 */ -+ uint32_t rs_code[2]; /* signal trampoline */ -+ struct target_siginfo rs_info; -+ struct target_ucontext rs_uc; -+}; -+ -+static inline void setup_sigcontext(CPULOONGARCHState *regs, -+ struct target_sigcontext *sc) -+{ -+ int i; -+ -+ __put_user(exception_resume_pc(regs), &sc->sc_pc); -+ regs->hflags &= ~LARCH_HFLAG_BMASK; -+ -+ __put_user(0, &sc->sc_regs[0]); -+ for (i = 1; i < 32; ++i) { -+ __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); -+ } -+ -+ for (i = 0; i < 32; ++i) { -+ __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i].val64[0]); -+ } -+} -+ -+static inline void -+restore_sigcontext(CPULOONGARCHState *regs, struct target_sigcontext *sc) -+{ -+ int i; -+ -+ __get_user(regs->CSR_ERA, &sc->sc_pc); -+ -+ for (i = 1; i < 32; ++i) { -+ __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); -+ } -+ -+ for (i = 0; i < 32; ++i) { -+ __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i].val64[0]); -+ } -+} -+ -+/* -+ * Determine which stack to use.. -+ */ -+static inline abi_ulong -+get_sigframe(struct target_sigaction *ka, CPULOONGARCHState *regs, -+ size_t frame_size) -+{ -+ unsigned long sp; -+ -+ /* -+ * FPU emulator may have its own trampoline active just -+ * above the user stack, 16-bytes before the next lowest -+ * 16 byte boundary. Try to avoid trashing it. -+ */ -+ sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka); -+ -+ return (sp - frame_size) & ~7; -+} -+ -+void setup_rt_frame(int sig, struct target_sigaction *ka, -+ target_siginfo_t *info, -+ target_sigset_t *set, CPULOONGARCHState *env) -+{ -+ struct target_rt_sigframe *frame; -+ abi_ulong frame_addr; -+ int i; -+ -+ frame_addr = get_sigframe(ka, env, sizeof(*frame)); -+ trace_user_setup_rt_frame(env, frame_addr); -+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { -+ goto give_sigsegv; -+ } -+ -+ /* ori a7, $r0, TARGET_NR_rt_sigreturn */ -+ /* syscall 0 */ -+ __put_user(0x0380000b + (TARGET_NR_rt_sigreturn << 10), &frame->rs_code[0]); -+ __put_user(0x002b0000, &frame->rs_code[1]); -+ -+ tswap_siginfo(&frame->rs_info, info); -+ -+ __put_user(0, &frame->rs_uc.tuc_flags); -+ __put_user(0, &frame->rs_uc.tuc_link); -+ target_save_altstack(&frame->rs_uc.tuc_stack, env); -+ -+ setup_sigcontext(env, &frame->rs_uc.tuc_mcontext); -+ -+ for (i = 0; i < TARGET_NSIG_WORDS; i++) { -+ __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); -+ } -+ -+ /* -+ * Arguments to signal handler: -+ * -+ * a0 = signal number -+ * a1 = pointer to siginfo_t -+ * a2 = pointer to ucontext_t -+ * -+ * $25 and PC point to the signal handler, $29 points to the -+ * struct sigframe. -+ */ -+ env->active_tc.gpr[4] = sig; -+ env->active_tc.gpr[5] = frame_addr -+ + offsetof(struct target_rt_sigframe, rs_info); -+ env->active_tc.gpr[6] = frame_addr -+ + offsetof(struct target_rt_sigframe, rs_uc); -+ env->active_tc.gpr[3] = frame_addr; -+ env->active_tc.gpr[1] = frame_addr -+ + offsetof(struct target_rt_sigframe, rs_code); -+ /* The original kernel code sets CP0_ERA to the handler -+ * since it returns to userland using ertn -+ * we cannot do this here, and we must set PC directly */ -+ env->active_tc.PC = env->active_tc.gpr[20] = ka->_sa_handler; -+ unlock_user_struct(frame, frame_addr, 1); -+ return; -+ -+give_sigsegv: -+ unlock_user_struct(frame, frame_addr, 1); -+ force_sigsegv(sig); -+} -+ -+long do_rt_sigreturn(CPULOONGARCHState *env) -+{ -+ struct target_rt_sigframe *frame; -+ abi_ulong frame_addr; -+ sigset_t blocked; -+ -+ frame_addr = env->active_tc.gpr[3]; -+ trace_user_do_rt_sigreturn(env, frame_addr); -+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { -+ goto badframe; -+ } -+ -+ target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); -+ set_sigmask(&blocked); -+ -+ restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); -+ -+ if (do_sigaltstack(frame_addr + -+ offsetof(struct target_rt_sigframe, rs_uc.tuc_stack), -+ 0, get_sp_from_cpustate(env)) == -EFAULT) -+ goto badframe; -+ -+ env->active_tc.PC = env->CSR_ERA; -+ /* I am not sure this is right, but it seems to work -+ * maybe a problem with nested signals ? */ -+ env->CSR_ERA = 0; -+ return -TARGET_QEMU_ESIGRETURN; -+ -+badframe: -+ force_sig(TARGET_SIGSEGV); -+ return -TARGET_QEMU_ESIGRETURN; -+} -diff --git a/linux-user/loongarch64/sockbits.h b/linux-user/loongarch64/sockbits.h -new file mode 100644 -index 000000000..0e4c8f012 ---- /dev/null -+++ b/linux-user/loongarch64/sockbits.h -@@ -0,0 +1 @@ -+#include "../generic/sockbits.h" -diff --git a/linux-user/loongarch64/syscall_nr.h b/linux-user/loongarch64/syscall_nr.h -new file mode 100644 -index 000000000..a30aca8d8 ---- /dev/null -+++ b/linux-user/loongarch64/syscall_nr.h -@@ -0,0 +1,287 @@ -+#ifndef LINUX_USER_LOONGARCH_SYSCALL_NR_H -+#define LINUX_USER_LOONGARCH_SYSCALL_NR_H -+ -+#define TARGET_NR_io_setup 0 -+#define TARGET_NR_io_destroy 1 -+#define TARGET_NR_io_submit 2 -+#define TARGET_NR_io_cancel 3 -+#define TARGET_NR_io_getevents 4 -+#define TARGET_NR_setxattr 5 -+#define TARGET_NR_lsetxattr 6 -+#define TARGET_NR_fsetxattr 7 -+#define TARGET_NR_getxattr 8 -+#define TARGET_NR_lgetxattr 9 -+#define TARGET_NR_fgetxattr 10 -+#define TARGET_NR_listxattr 11 -+#define TARGET_NR_llistxattr 12 -+#define TARGET_NR_flistxattr 13 -+#define TARGET_NR_removexattr 14 -+#define TARGET_NR_lremovexattr 15 -+#define TARGET_NR_fremovexattr 16 -+#define TARGET_NR_getcwd 17 -+#define TARGET_NR_lookup_dcookie 18 -+#define TARGET_NR_eventfd2 19 -+#define TARGET_NR_epoll_create1 20 -+#define TARGET_NR_epoll_ctl 21 -+#define TARGET_NR_epoll_pwait 22 -+#define TARGET_NR_dup 23 -+#define TARGET_NR_dup3 24 -+#define TARGET_NR_fcntl 25 -+#define TARGET_NR_inotify_init1 26 -+#define TARGET_NR_inotify_add_watch 27 -+#define TARGET_NR_inotify_rm_watch 28 -+#define TARGET_NR_ioctl 29 -+#define TARGET_NR_ioprio_set 30 -+#define TARGET_NR_ioprio_get 31 -+#define TARGET_NR_flock 32 -+#define TARGET_NR_mknodat 33 -+#define TARGET_NR_mkdirat 34 -+#define TARGET_NR_unlinkat 35 -+#define TARGET_NR_symlinkat 36 -+#define TARGET_NR_linkat 37 -+#define TARGET_NR_renameat 38 -+#define TARGET_NR_umount2 39 -+#define TARGET_NR_mount 40 -+#define TARGET_NR_pivot_root 41 -+#define TARGET_NR_nfsservctl 42 -+#define TARGET_NR_statfs 43 -+#define TARGET_NR_fstatfs 44 -+#define TARGET_NR_truncate 45 -+#define TARGET_NR_ftruncate 46 -+#define TARGET_NR_fallocate 47 -+#define TARGET_NR_faccessat 48 -+#define TARGET_NR_chdir 49 -+#define TARGET_NR_fchdir 50 -+#define TARGET_NR_chroot 51 -+#define TARGET_NR_fchmod 52 -+#define TARGET_NR_fchmodat 53 -+#define TARGET_NR_fchownat 54 -+#define TARGET_NR_fchown 55 -+#define TARGET_NR_openat 56 -+#define TARGET_NR_close 57 -+#define TARGET_NR_vhangup 58 -+#define TARGET_NR_pipe2 59 -+#define TARGET_NR_quotactl 60 -+#define TARGET_NR_getdents64 61 -+#define TARGET_NR_lseek 62 -+#define TARGET_NR_read 63 -+#define TARGET_NR_write 64 -+#define TARGET_NR_readv 65 -+#define TARGET_NR_writev 66 -+#define TARGET_NR_pread64 67 -+#define TARGET_NR_pwrite64 68 -+#define TARGET_NR_preadv 69 -+#define TARGET_NR_pwritev 70 -+#define TARGET_NR_sendfile 71 -+#define TARGET_NR_pselect6 72 -+#define TARGET_NR_ppoll 73 -+#define TARGET_NR_signalfd4 74 -+#define TARGET_NR_vmsplice 75 -+#define TARGET_NR_splice 76 -+#define TARGET_NR_tee 77 -+#define TARGET_NR_readlinkat 78 -+#define TARGET_NR_newfstatat 79 -+#define TARGET_NR_fstat 80 -+#define TARGET_NR_sync 81 -+#define TARGET_NR_fsync 82 -+#define TARGET_NR_fdatasync 83 -+#define TARGET_NR_sync_file_range 84 -+#define TARGET_NR_timerfd_create 85 -+#define TARGET_NR_timerfd_settime 86 -+#define TARGET_NR_timerfd_gettime 87 -+#define TARGET_NR_utimensat 88 -+#define TARGET_NR_acct 89 -+#define TARGET_NR_capget 90 -+#define TARGET_NR_capset 91 -+#define TARGET_NR_personality 92 -+#define TARGET_NR_exit 93 -+#define TARGET_NR_exit_group 94 -+#define TARGET_NR_waitid 95 -+#define TARGET_NR_set_tid_address 96 -+#define TARGET_NR_unshare 97 -+#define TARGET_NR_futex 98 -+#define TARGET_NR_set_robust_list 99 -+#define TARGET_NR_get_robust_list 100 -+#define TARGET_NR_nanosleep 101 -+#define TARGET_NR_getitimer 102 -+#define TARGET_NR_setitimer 103 -+#define TARGET_NR_kexec_load 104 -+#define TARGET_NR_init_module 105 -+#define TARGET_NR_delete_module 106 -+#define TARGET_NR_timer_create 107 -+#define TARGET_NR_timer_gettime 108 -+#define TARGET_NR_timer_getoverrun 109 -+#define TARGET_NR_timer_settime 110 -+#define TARGET_NR_timer_delete 111 -+#define TARGET_NR_clock_settime 112 -+#define TARGET_NR_clock_gettime 113 -+#define TARGET_NR_clock_getres 114 -+#define TARGET_NR_clock_nanosleep 115 -+#define TARGET_NR_syslog 116 -+#define TARGET_NR_ptrace 117 -+#define TARGET_NR_sched_setparam 118 -+#define TARGET_NR_sched_setscheduler 119 -+#define TARGET_NR_sched_getscheduler 120 -+#define TARGET_NR_sched_getparam 121 -+#define TARGET_NR_sched_setaffinity 122 -+#define TARGET_NR_sched_getaffinity 123 -+#define TARGET_NR_sched_yield 124 -+#define TARGET_NR_sched_get_priority_max 125 -+#define TARGET_NR_sched_get_priority_min 126 -+#define TARGET_NR_sched_rr_get_interval 127 -+#define TARGET_NR_restart_syscall 128 -+#define TARGET_NR_kill 129 -+#define TARGET_NR_tkill 130 -+#define TARGET_NR_tgkill 131 -+#define TARGET_NR_sigaltstack 132 -+#define TARGET_NR_rt_sigsuspend 133 -+#define TARGET_NR_rt_sigaction 134 -+#define TARGET_NR_rt_sigprocmask 135 -+#define TARGET_NR_rt_sigpending 136 -+#define TARGET_NR_rt_sigtimedwait 137 -+#define TARGET_NR_rt_sigqueueinfo 138 -+#define TARGET_NR_rt_sigreturn 139 -+#define TARGET_NR_setpriority 140 -+#define TARGET_NR_getpriority 141 -+#define TARGET_NR_reboot 142 -+#define TARGET_NR_setregid 143 -+#define TARGET_NR_setgid 144 -+#define TARGET_NR_setreuid 145 -+#define TARGET_NR_setuid 146 -+#define TARGET_NR_setresuid 147 -+#define TARGET_NR_getresuid 148 -+#define TARGET_NR_setresgid 149 -+#define TARGET_NR_getresgid 150 -+#define TARGET_NR_setfsuid 151 -+#define TARGET_NR_setfsgid 152 -+#define TARGET_NR_times 153 -+#define TARGET_NR_setpgid 154 -+#define TARGET_NR_getpgid 155 -+#define TARGET_NR_getsid 156 -+#define TARGET_NR_setsid 157 -+#define TARGET_NR_getgroups 158 -+#define TARGET_NR_setgroups 159 -+#define TARGET_NR_uname 160 -+#define TARGET_NR_sethostname 161 -+#define TARGET_NR_setdomainname 162 -+#define TARGET_NR_getrlimit 163 -+#define TARGET_NR_setrlimit 164 -+#define TARGET_NR_getrusage 165 -+#define TARGET_NR_umask 166 -+#define TARGET_NR_prctl 167 -+#define TARGET_NR_getcpu 168 -+#define TARGET_NR_gettimeofday 169 -+#define TARGET_NR_settimeofday 170 -+#define TARGET_NR_adjtimex 171 -+#define TARGET_NR_getpid 172 -+#define TARGET_NR_getppid 173 -+#define TARGET_NR_getuid 174 -+#define TARGET_NR_geteuid 175 -+#define TARGET_NR_getgid 176 -+#define TARGET_NR_getegid 177 -+#define TARGET_NR_gettid 178 -+#define TARGET_NR_sysinfo 179 -+#define TARGET_NR_mq_open 180 -+#define TARGET_NR_mq_unlink 181 -+#define TARGET_NR_mq_timedsend 182 -+#define TARGET_NR_mq_timedreceive 183 -+#define TARGET_NR_mq_notify 184 -+#define TARGET_NR_mq_getsetattr 185 -+#define TARGET_NR_msgget 186 -+#define TARGET_NR_msgctl 187 -+#define TARGET_NR_msgrcv 188 -+#define TARGET_NR_msgsnd 189 -+#define TARGET_NR_semget 190 -+#define TARGET_NR_semctl 191 -+#define TARGET_NR_semtimedop 192 -+#define TARGET_NR_semop 193 -+#define TARGET_NR_shmget 194 -+#define TARGET_NR_shmctl 195 -+#define TARGET_NR_shmat 196 -+#define TARGET_NR_shmdt 197 -+#define TARGET_NR_socket 198 -+#define TARGET_NR_socketpair 199 -+#define TARGET_NR_bind 200 -+#define TARGET_NR_listen 201 -+#define TARGET_NR_accept 202 -+#define TARGET_NR_connect 203 -+#define TARGET_NR_getsockname 204 -+#define TARGET_NR_getpeername 205 -+#define TARGET_NR_sendto 206 -+#define TARGET_NR_recvfrom 207 -+#define TARGET_NR_setsockopt 208 -+#define TARGET_NR_getsockopt 209 -+#define TARGET_NR_shutdown 210 -+#define TARGET_NR_sendmsg 211 -+#define TARGET_NR_recvmsg 212 -+#define TARGET_NR_readahead 213 -+#define TARGET_NR_brk 214 -+#define TARGET_NR_munmap 215 -+#define TARGET_NR_mremap 216 -+#define TARGET_NR_add_key 217 -+#define TARGET_NR_request_key 218 -+#define TARGET_NR_keyctl 219 -+#define TARGET_NR_clone 220 -+#define TARGET_NR_execve 221 -+#define TARGET_NR_mmap 222 -+#define TARGET_NR_fadvise64 223 -+#define TARGET_NR_swapon 224 -+#define TARGET_NR_swapoff 225 -+#define TARGET_NR_mprotect 226 -+#define TARGET_NR_msync 227 -+#define TARGET_NR_mlock 228 -+#define TARGET_NR_munlock 229 -+#define TARGET_NR_mlockall 230 -+#define TARGET_NR_munlockall 231 -+#define TARGET_NR_mincore 232 -+#define TARGET_NR_madvise 233 -+#define TARGET_NR_remap_file_pages 234 -+#define TARGET_NR_mbind 235 -+#define TARGET_NR_get_mempolicy 236 -+#define TARGET_NR_set_mempolicy 237 -+#define TARGET_NR_migrate_pages 238 -+#define TARGET_NR_move_pages 239 -+#define TARGET_NR_rt_tgsigqueueinfo 240 -+#define TARGET_NR_perf_event_open 241 -+#define TARGET_NR_accept4 242 -+#define TARGET_NR_recvmmsg 243 -+#define TARGET_NR_arch_specific_syscall 244 -+#define TARGET_NR_wait4 260 -+#define TARGET_NR_prlimit64 261 -+#define TARGET_NR_fanotify_init 262 -+#define TARGET_NR_fanotify_mark 263 -+#define TARGET_NR_name_to_handle_at 264 -+#define TARGET_NR_open_by_handle_at 265 -+#define TARGET_NR_clock_adjtime 266 -+#define TARGET_NR_syncfs 267 -+#define TARGET_NR_setns 268 -+#define TARGET_NR_sendmmsg 269 -+#define TARGET_NR_process_vm_readv 270 -+#define TARGET_NR_process_vm_writev 271 -+#define TARGET_NR_kcmp 272 -+#define TARGET_NR_finit_module 273 -+#define TARGET_NR_sched_setattr 274 -+#define TARGET_NR_sched_getattr 275 -+#define TARGET_NR_renameat2 276 -+#define TARGET_NR_seccomp 277 -+#define TARGET_NR_getrandom 278 -+#define TARGET_NR_memfd_create 279 -+#define TARGET_NR_bpf 280 -+#define TARGET_NR_execveat 281 -+#define TARGET_NR_userfaultfd 282 -+#define TARGET_NR_membarrier 283 -+#define TARGET_NR_mlock2 284 -+#define TARGET_NR_copy_file_range 285 -+#define TARGET_NR_preadv2 286 -+#define TARGET_NR_pwritev2 287 -+#define TARGET_NR_pkey_mprotect 288 -+#define TARGET_NR_pkey_alloc 289 -+#define TARGET_NR_pkey_free 290 -+#define TARGET_NR_statx 291 -+#define TARGET_NR_io_pgetevents 292 -+#define TARGET_NR_rseq 293 -+#define TARGET_NR_kexec_file_load 294 -+ -+#define TARGET_NR_syscalls (TARGET_NR_kexec_file_load + 1) -+ -+#endif -diff --git a/linux-user/loongarch64/target_cpu.h b/linux-user/loongarch64/target_cpu.h -new file mode 100644 -index 000000000..0f6845737 ---- /dev/null -+++ b/linux-user/loongarch64/target_cpu.h -@@ -0,0 +1,45 @@ -+/* -+ * MIPS specific CPU ABI and functions for linux-user -+ * -+ * Copyright (c) 2004-2005 Jocelyn Mayer -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 . -+ */ -+#ifndef LOONGARCH_TARGET_CPU_H -+#define LOONGARCH_TARGET_CPU_H -+ -+static inline void cpu_clone_regs_child(CPULOONGARCHState *env, target_ulong newsp, -+ unsigned flags) -+{ -+ if (newsp) { -+ env->active_tc.gpr[3] = newsp; -+ } -+ env->active_tc.gpr[7] = 0; -+ env->active_tc.gpr[4] = 0; -+} -+ -+static inline void cpu_clone_regs_parent(CPULOONGARCHState *env, unsigned flags) -+{ -+} -+ -+static inline void cpu_set_tls(CPULOONGARCHState *env, target_ulong newtls) -+{ -+ env->active_tc.gpr[2] = newtls; -+} -+ -+static inline abi_ulong get_sp_from_cpustate(CPULOONGARCHState *state) -+{ -+ return state->active_tc.gpr[3]; -+} -+#endif -diff --git a/linux-user/loongarch64/target_elf.h b/linux-user/loongarch64/target_elf.h -new file mode 100644 -index 000000000..6c153d12c ---- /dev/null -+++ b/linux-user/loongarch64/target_elf.h -@@ -0,0 +1,14 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation, or (at your option) any -+ * later version. See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef LOONGARCH_TARGET_ELF_H -+#define LOONGARCH_TARGET_ELF_H -+static inline const char *cpu_get_model(uint32_t eflags) -+{ -+ return "Loongson-3A5000"; -+} -+#endif -diff --git a/linux-user/loongarch64/target_fcntl.h b/linux-user/loongarch64/target_fcntl.h -new file mode 100644 -index 000000000..a3d7b4606 ---- /dev/null -+++ b/linux-user/loongarch64/target_fcntl.h -@@ -0,0 +1,13 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation, or (at your option) any -+ * later version. See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef LOONGARCH_TARGET_FCNTL_H -+#define LOONGARCH_TARGET_FCNTL_H -+ -+#include "../generic/fcntl.h" -+ -+#endif /* LOONGARCH_TARGET_FCNTL_H */ -diff --git a/linux-user/loongarch64/target_signal.h b/linux-user/loongarch64/target_signal.h -new file mode 100644 -index 000000000..e418c8e8f ---- /dev/null -+++ b/linux-user/loongarch64/target_signal.h -@@ -0,0 +1,23 @@ -+#ifndef LOONGARCH_TARGET_SIGNAL_H -+#define LOONGARCH_TARGET_SIGNAL_H -+ -+/* this struct defines a stack used during syscall handling */ -+ -+typedef struct target_sigaltstack { -+ abi_long ss_sp; -+ abi_int ss_flags; -+ abi_ulong ss_size; -+} target_stack_t; -+ -+/* -+ * sigaltstack controls -+ */ -+#define TARGET_SS_ONSTACK 1 -+#define TARGET_SS_DISABLE 2 -+ -+#define TARGET_MINSIGSTKSZ 2048 -+#define TARGET_SIGSTKSZ 8192 -+ -+#include "../generic/signal.h" -+ -+#endif /* LOONGARCH_TARGET_SIGNAL_H */ -diff --git a/linux-user/loongarch64/target_structs.h b/linux-user/loongarch64/target_structs.h -new file mode 100644 -index 000000000..280acd097 ---- /dev/null -+++ b/linux-user/loongarch64/target_structs.h -@@ -0,0 +1,62 @@ -+/* -+ * LOONGARCH specific structures for linux-user -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * 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 . -+ */ -+#ifndef LOONGARCH_TARGET_STRUCTS_H -+#define LOONGARCH_TARGET_STRUCTS_H -+ -+struct target_ipc_perm { -+ abi_int __key; /* Key. */ -+ abi_uint uid; /* Owner's user ID. */ -+ abi_uint gid; /* Owner's group ID. */ -+ abi_uint cuid; /* Creator's user ID. */ -+ abi_uint cgid; /* Creator's group ID. */ -+ abi_uint mode; /* Read/write permission. */ -+ abi_ushort __seq; /* Sequence number. */ -+ abi_ushort __pad1; -+ abi_ulong __unused1; -+ abi_ulong __unused2; -+}; -+ -+struct target_shmid_ds { -+ struct target_ipc_perm shm_perm; /* operation permission struct */ -+ abi_long shm_segsz; /* size of segment in bytes */ -+ abi_ulong shm_atime; /* time of last shmat() */ -+ abi_ulong shm_dtime; /* time of last shmdt() */ -+ abi_ulong shm_ctime; /* time of last change by shmctl() */ -+ abi_int shm_cpid; /* pid of creator */ -+ abi_int shm_lpid; /* pid of last shmop */ -+ abi_ulong shm_nattch; /* number of current attaches */ -+ abi_ulong __unused1; -+ abi_ulong __unused2; -+}; -+ -+#define TARGET_SEMID64_DS -+ -+/* -+ * The semid64_ds structure for the MIPS architecture. -+ * Note extra padding because this structure is passed back and forth -+ * between kernel and user space. -+ */ -+struct target_semid64_ds { -+ struct target_ipc_perm sem_perm; -+ abi_ulong sem_otime; -+ abi_ulong sem_ctime; -+ abi_ulong sem_nsems; -+ abi_ulong __unused1; -+ abi_ulong __unused2; -+}; -+ -+#endif -diff --git a/linux-user/loongarch64/target_syscall.h b/linux-user/loongarch64/target_syscall.h -new file mode 100644 -index 000000000..cb77f0708 ---- /dev/null -+++ b/linux-user/loongarch64/target_syscall.h -@@ -0,0 +1,44 @@ -+#ifndef LOONGARCH_TARGET_SYSCALL_H -+#define LOONGARCH_TARGET_SYSCALL_H -+ -+/* this struct defines the way the registers are stored on the -+ stack during a system call. */ -+ -+struct target_pt_regs { -+ /* Saved main processor registers. */ -+ target_ulong regs[32]; -+ -+ /* Saved special registers. */ -+ /* Saved special registers. */ -+ target_ulong csr_crmd; -+ target_ulong csr_prmd; -+ target_ulong csr_euen; -+ target_ulong csr_ecfg; -+ target_ulong csr_estat; -+ target_ulong csr_era; -+ target_ulong csr_badvaddr; -+ target_ulong orig_a0; -+ target_ulong __last[0]; -+}; -+ -+#define UNAME_MACHINE "loongarch" -+#define UNAME_MINIMUM_RELEASE "2.6.32" -+ -+#define TARGET_CLONE_BACKWARDS -+#define TARGET_MINSIGSTKSZ 2048 -+#define TARGET_MLOCKALL_MCL_CURRENT 1 -+#define TARGET_MLOCKALL_MCL_FUTURE 2 -+ -+#define TARGET_FORCE_SHMLBA -+ -+static inline abi_ulong target_shmlba(CPULOONGARCHState *env) -+{ -+ return 0x40000; -+} -+ -+#define TARGET_PR_SET_FP_MODE 45 -+#define TARGET_PR_GET_FP_MODE 46 -+#define TARGET_PR_FP_MODE_FR (1 << 0) -+#define TARGET_PR_FP_MODE_FRE (1 << 1) -+ -+#endif /* LOONGARCH_TARGET_SYSCALL_H */ -diff --git a/linux-user/loongarch64/termbits.h b/linux-user/loongarch64/termbits.h -new file mode 100644 -index 000000000..6c613a197 ---- /dev/null -+++ b/linux-user/loongarch64/termbits.h -@@ -0,0 +1,224 @@ -+#ifndef LINUX_USER_LOONGARCH_TERMBITS_H -+#define LINUX_USER_LOONGARCH_TERMBITS_H -+ -+#define TARGET_NCCS 19 -+ -+struct target_termios { -+ unsigned int c_iflag; /* input mode flags */ -+ unsigned int c_oflag; /* output mode flags */ -+ unsigned int c_cflag; /* control mode flags */ -+ unsigned int c_lflag; /* local mode flags */ -+ unsigned char c_line; /* line discipline */ -+ unsigned char c_cc[TARGET_NCCS]; /* control characters */ -+}; -+ -+/* c_iflag bits */ -+#define TARGET_IGNBRK 0000001 -+#define TARGET_BRKINT 0000002 -+#define TARGET_IGNPAR 0000004 -+#define TARGET_PARMRK 0000010 -+#define TARGET_INPCK 0000020 -+#define TARGET_ISTRIP 0000040 -+#define TARGET_INLCR 0000100 -+#define TARGET_IGNCR 0000200 -+#define TARGET_ICRNL 0000400 -+#define TARGET_IUCLC 0001000 -+#define TARGET_IXON 0002000 -+#define TARGET_IXANY 0004000 -+#define TARGET_IXOFF 0010000 -+#define TARGET_IMAXBEL 0020000 -+#define TARGET_IUTF8 0040000 -+ -+/* c_oflag bits */ -+#define TARGET_OPOST 0000001 -+#define TARGET_OLCUC 0000002 -+#define TARGET_ONLCR 0000004 -+#define TARGET_OCRNL 0000010 -+#define TARGET_ONOCR 0000020 -+#define TARGET_ONLRET 0000040 -+#define TARGET_OFILL 0000100 -+#define TARGET_OFDEL 0000200 -+#define TARGET_NLDLY 0000400 -+#define TARGET_NL0 0000000 -+#define TARGET_NL1 0000400 -+#define TARGET_CRDLY 0003000 -+#define TARGET_CR0 0000000 -+#define TARGET_CR1 0001000 -+#define TARGET_CR2 0002000 -+#define TARGET_CR3 0003000 -+#define TARGET_TABDLY 0014000 -+#define TARGET_TAB0 0000000 -+#define TARGET_TAB1 0004000 -+#define TARGET_TAB2 0010000 -+#define TARGET_TAB3 0014000 -+#define TARGET_XTABS 0014000 -+#define TARGET_BSDLY 0020000 -+#define TARGET_BS0 0000000 -+#define TARGET_BS1 0020000 -+#define TARGET_VTDLY 0040000 -+#define TARGET_VT0 0000000 -+#define TARGET_VT1 0040000 -+#define TARGET_FFDLY 0100000 -+#define TARGET_FF0 0000000 -+#define TARGET_FF1 0100000 -+ -+/* c_cflag bit meaning */ -+#define TARGET_CBAUD 0010017 -+#define TARGET_B0 0000000 /* hang up */ -+#define TARGET_B50 0000001 -+#define TARGET_B75 0000002 -+#define TARGET_B110 0000003 -+#define TARGET_B134 0000004 -+#define TARGET_B150 0000005 -+#define TARGET_B200 0000006 -+#define TARGET_B300 0000007 -+#define TARGET_B600 0000010 -+#define TARGET_B1200 0000011 -+#define TARGET_B1800 0000012 -+#define TARGET_B2400 0000013 -+#define TARGET_B4800 0000014 -+#define TARGET_B9600 0000015 -+#define TARGET_B19200 0000016 -+#define TARGET_B38400 0000017 -+#define TARGET_EXTA B19200 -+#define TARGET_EXTB B38400 -+#define TARGET_CSIZE 0000060 -+#define TARGET_CS5 0000000 -+#define TARGET_CS6 0000020 -+#define TARGET_CS7 0000040 -+#define TARGET_CS8 0000060 -+#define TARGET_CSTOPB 0000100 -+#define TARGET_CREAD 0000200 -+#define TARGET_PARENB 0000400 -+#define TARGET_PARODD 0001000 -+#define TARGET_HUPCL 0002000 -+#define TARGET_CLOCAL 0004000 -+#define TARGET_CBAUDEX 0010000 -+#define TARGET_B57600 0010001 -+#define TARGET_B115200 0010002 -+#define TARGET_B230400 0010003 -+#define TARGET_B460800 0010004 -+#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ -+#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ -+#define TARGET_CRTSCTS 020000000000 /* flow control */ -+ -+/* c_lflag bits */ -+#define TARGET_ISIG 0000001 -+#define TARGET_ICANON 0000002 -+#define TARGET_XCASE 0000004 -+#define TARGET_ECHO 0000010 -+#define TARGET_ECHOE 0000020 -+#define TARGET_ECHOK 0000040 -+#define TARGET_ECHONL 0000100 -+#define TARGET_NOFLSH 0000200 -+#define TARGET_TOSTOP 0000400 -+#define TARGET_ECHOCTL 0001000 -+#define TARGET_ECHOPRT 0002000 -+#define TARGET_ECHOKE 0004000 -+#define TARGET_FLUSHO 0010000 -+#define TARGET_PENDIN 0040000 -+#define TARGET_IEXTEN 0100000 -+ -+/* c_cc character offsets */ -+#define TARGET_VINTR 0 -+#define TARGET_VQUIT 1 -+#define TARGET_VERASE 2 -+#define TARGET_VKILL 3 -+#define TARGET_VEOF 4 -+#define TARGET_VTIME 5 -+#define TARGET_VMIN 6 -+#define TARGET_VSWTC 7 -+#define TARGET_VSTART 8 -+#define TARGET_VSTOP 9 -+#define TARGET_VSUSP 10 -+#define TARGET_VEOL 11 -+#define TARGET_VREPRINT 12 -+#define TARGET_VDISCARD 13 -+#define TARGET_VWERASE 14 -+#define TARGET_VLNEXT 15 -+#define TARGET_VEOL2 16 -+ -+/* ioctls */ -+ -+#define TARGET_TCGETS 0x5401 -+#define TARGET_TCSETS 0x5402 -+#define TARGET_TCSETSW 0x5403 -+#define TARGET_TCSETSF 0x5404 -+#define TARGET_TCGETA 0x5405 -+#define TARGET_TCSETA 0x5406 -+#define TARGET_TCSETAW 0x5407 -+#define TARGET_TCSETAF 0x5408 -+#define TARGET_TCSBRK 0x5409 -+#define TARGET_TCXONC 0x540A -+#define TARGET_TCFLSH 0x540B -+ -+#define TARGET_TIOCEXCL 0x540C -+#define TARGET_TIOCNXCL 0x540D -+#define TARGET_TIOCSCTTY 0x540E -+#define TARGET_TIOCGPGRP 0x540F -+#define TARGET_TIOCSPGRP 0x5410 -+#define TARGET_TIOCOUTQ 0x5411 -+#define TARGET_TIOCSTI 0x5412 -+#define TARGET_TIOCGWINSZ 0x5413 -+#define TARGET_TIOCSWINSZ 0x5414 -+#define TARGET_TIOCMGET 0x5415 -+#define TARGET_TIOCMBIS 0x5416 -+#define TARGET_TIOCMBIC 0x5417 -+#define TARGET_TIOCMSET 0x5418 -+#define TARGET_TIOCGSOFTCAR 0x5419 -+#define TARGET_TIOCSSOFTCAR 0x541A -+#define TARGET_FIONREAD 0x541B -+#define TARGET_TIOCINQ TARGET_FIONREAD -+#define TARGET_TIOCLINUX 0x541C -+#define TARGET_TIOCCONS 0x541D -+#define TARGET_TIOCGSERIAL 0x541E -+#define TARGET_TIOCSSERIAL 0x541F -+#define TARGET_TIOCPKT 0x5420 -+#define TARGET_FIONBIO 0x5421 -+#define TARGET_TIOCNOTTY 0x5422 -+#define TARGET_TIOCSETD 0x5423 -+#define TARGET_TIOCGETD 0x5424 -+#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -+#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ -+#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ -+#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ -+#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ -+#define TARGET_TIOCGPTN TARGET_IOR('T', 0x30, unsigned int) -+ /* Get Pty Number (of pty-mux device) */ -+#define TARGET_TIOCSPTLCK TARGET_IOW('T', 0x31, int) -+ /* Lock/unlock Pty */ -+#define TARGET_TIOCGPTPEER TARGET_IO('T', 0x41) -+ /* Safely open the slave */ -+ -+#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ -+#define TARGET_FIOCLEX 0x5451 -+#define TARGET_FIOASYNC 0x5452 -+#define TARGET_TIOCSERCONFIG 0x5453 -+#define TARGET_TIOCSERGWILD 0x5454 -+#define TARGET_TIOCSERSWILD 0x5455 -+#define TARGET_TIOCGLCKTRMIOS 0x5456 -+#define TARGET_TIOCSLCKTRMIOS 0x5457 -+#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ -+#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ -+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ -+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ -+ -+#define TARGET_TIOCMIWAIT 0x545C -+ /* wait for a change on serial input line(s) */ -+#define TARGET_TIOCGICOUNT 0x545D -+ /* read serial port inline interrupt counts */ -+#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -+#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ -+ -+/* Used for packet mode */ -+#define TARGET_TIOCPKT_DATA 0 -+#define TARGET_TIOCPKT_FLUSHREAD 1 -+#define TARGET_TIOCPKT_FLUSHWRITE 2 -+#define TARGET_TIOCPKT_STOP 4 -+#define TARGET_TIOCPKT_START 8 -+#define TARGET_TIOCPKT_NOSTOP 16 -+#define TARGET_TIOCPKT_DOSTOP 32 -+ -+#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -+ -+#endif --- -2.43.5 - diff --git a/0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch b/0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch deleted file mode 100644 index 97cb7cc..0000000 --- a/0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 501e16b4b4cf5a302363c1ae55fb4fb8e68beb8d Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Tue, 24 Aug 2021 17:31:28 +0800 -Subject: [PATCH 5/8] anolis: cpu/i386: populate CPUID 0x8000_001F when CSV is - active - -On Hygon platform, bit 30 of EAX indicates whether -this feature is supported in hardware. - -When CSV is active, CPUID 0x8000_001F provides -information for it. - -Signed-off-by: Xin Jiang -Change-Id: Ifdd2a20f7cb4a079ba918928f012e5f64f7059e6 ---- - target/i386/cpu.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index aa9e636800..970d9bf184 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -27,6 +27,7 @@ - #include "sysemu/hvf.h" - #include "kvm/kvm_i386.h" - #include "sev.h" -+#include "csv.h" - #include "qapi/error.h" - #include "qapi/qapi-visit-machine.h" - #include "qapi/qmp/qerror.h" -@@ -5769,6 +5770,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - if (sev_enabled()) { - *eax = 0x2; - *eax |= sev_es_enabled() ? 0x8 : 0; -+ *eax |= csv_enabled() ? 0x40000000 : 0; /* bit 30 for CSV */ - *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */ - *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */ - } --- -2.17.1 - diff --git a/0006-Add-disas-gdb.patch b/0006-Add-disas-gdb.patch deleted file mode 100644 index 97e9a6d..0000000 --- a/0006-Add-disas-gdb.patch +++ /dev/null @@ -1,3183 +0,0 @@ -From dbf0724c5c9e7928f0007e6a5e0009cabba90457 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:51:12 -0400 -Subject: [PATCH 06/28] Add disas gdb. - -Change-Id: If41c0fc8aa128796e342319c7673fab3ccbf3913 -Signed-off-by: lixianglai ---- - .../devices/loongarch64-softmmu/default.mak | 154 + - configs/targets/loongarch64-softmmu.mak | 4 + - disas/loongarch.c | 2748 +++++++++++++++++ - disas/meson.build | 1 + - gdb-xml/loongarch-base32.xml | 43 + - gdb-xml/loongarch-base64.xml | 43 + - gdb-xml/loongarch-fpu32.xml | 52 + - gdb-xml/loongarch-fpu64.xml | 57 + - 8 files changed, 3102 insertions(+) - create mode 100644 configs/devices/loongarch64-softmmu/default.mak - create mode 100644 configs/targets/loongarch64-softmmu.mak - create mode 100644 disas/loongarch.c - create mode 100644 gdb-xml/loongarch-base32.xml - create mode 100644 gdb-xml/loongarch-base64.xml - create mode 100644 gdb-xml/loongarch-fpu32.xml - create mode 100644 gdb-xml/loongarch-fpu64.xml - -diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak -new file mode 100644 -index 000000000..fcb7e45dd ---- /dev/null -+++ b/configs/devices/loongarch64-softmmu/default.mak -@@ -0,0 +1,154 @@ -+# Default configuration for loongarch-softmmu -+ -+CONFIG_PCI=y -+CONFIG_ACPI_PCI=y -+# For now, CONFIG_IDE_CORE requires ISA, so we enable it here -+CONFIG_ISA_BUS=y -+CONFIG_VIRTIO_PCI=y -+ -+CONFIG_VGA_PCI=y -+CONFIG_ACPI_SMBUS=y -+#CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+CONFIG_VHOST_USER_SCSI=y -+#CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+CONFIG_VHOST_USER_BLK=y -+CONFIG_VIRTIO=y -+CONFIG_VIRTIO_BALLOON=y -+CONFIG_VIRTIO_BLK=y -+CONFIG_VIRTIO_CRYPTO=y -+CONFIG_VIRTIO_GPU=y -+CONFIG_VIRTIO_INPUT=y -+CONFIG_VIRTIO_NET=y -+CONFIG_VIRTIO_RNG=y -+CONFIG_SCSI=y -+CONFIG_VIRTIO_SCSI=y -+CONFIG_VIRTIO_SERIAL=y -+ -+CONFIG_USB_UHCI=y -+CONFIG_USB_OHCI=y -+CONFIG_USB_OHCI_PCI=y -+CONFIG_USB_XHCI=y -+CONFIG_USB_XHCI_NEC=y -+CONFIG_NE2000_PCI=y -+CONFIG_EEPRO100_PCI=y -+CONFIG_PCNET_PCI=y -+CONFIG_PCNET_COMMON=y -+CONFIG_AC97=y -+CONFIG_HDA=y -+CONFIG_ES1370=y -+CONFIG_SCSI=y -+CONFIG_LSI_SCSI_PCI=y -+CONFIG_VMW_PVSCSI_SCSI_PCI=y -+CONFIG_MEGASAS_SCSI_PCI=y -+CONFIG_MPTSAS_SCSI_PCI=y -+CONFIG_RTL8139_PCI=y -+CONFIG_E1000_PCI=y -+CONFIG_IDE_CORE=y -+CONFIG_IDE_QDEV=y -+CONFIG_IDE_PCI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_ICH9=y -+CONFIG_ESP=y -+CONFIG_ESP_PCI=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_SERIAL_PCI=y -+CONFIG_CAN_BUS=y -+CONFIG_CAN_SJA1000=y -+CONFIG_CAN_PCI=y -+CONFIG_USB_UHCI=y -+CONFIG_USB_OHCI=y -+CONFIG_USB_XHCI=y -+CONFIG_USB_XHCI_NEC=y -+CONFIG_NE2000_PCI=y -+CONFIG_EEPRO100_PCI=y -+CONFIG_PCNET_PCI=y -+CONFIG_PCNET_COMMON=y -+CONFIG_AC97=y -+CONFIG_HDA=y -+CONFIG_ES1370=y -+CONFIG_SCSI=y -+CONFIG_LSI_SCSI_PCI=y -+CONFIG_VMW_PVSCSI_SCSI_PCI=y -+CONFIG_MEGASAS_SCSI_PCI=y -+CONFIG_MPTSAS_SCSI_PCI=y -+CONFIG_RTL8139_PCI=y -+CONFIG_E1000_PCI=y -+CONFIG_IDE_CORE=y -+CONFIG_IDE_QDEV=y -+CONFIG_IDE_PCI=y -+CONFIG_AHCI=y -+CONFIG_ESP=y -+CONFIG_ESP_PCI=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_SERIAL_PCI=y -+CONFIG_CAN_BUS=y -+CONFIG_CAN_SJA1000=y -+CONFIG_CAN_PCI=y -+ -+CONFIG_SPICE=y -+CONFIG_QXL=y -+CONFIG_ESP=y -+CONFIG_SCSI=y -+CONFIG_VGA_ISA=y -+CONFIG_VGA_ISA_MM=y -+CONFIG_VGA_CIRRUS=y -+CONFIG_VMWARE_VGA=y -+CONFIG_VIRTIO_VGA=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_PARALLEL=y -+CONFIG_I8254=y -+CONFIG_PCSPK=y -+CONFIG_PCKBD=y -+CONFIG_FDC=y -+CONFIG_ACPI=y -+CONFIG_ACPI_MEMORY_HOTPLUG=y -+CONFIG_ACPI_NVDIMM=y -+CONFIG_ACPI_CPU_HOTPLUG=y -+CONFIG_APM=y -+CONFIG_I8257=y -+CONFIG_PIIX4=y -+CONFIG_IDE_ISA=y -+CONFIG_IDE_PIIX=y -+#CONFIG_NE2000_ISA=y -+CONFIG_MIPSNET=y -+CONFIG_PFLASH_CFI01=y -+CONFIG_I8259=y -+CONFIG_MC146818RTC=y -+CONFIG_ISA_TESTDEV=y -+CONFIG_EMPTY_SLOT=y -+CONFIG_I2C=y -+CONFIG_DIMM=y -+CONFIG_MEM_DEVICE=y -+ -+# Arch Specified CONFIG defines -+CONFIG_IDE_VIA=y -+CONFIG_VT82C686=y -+CONFIG_RC4030=y -+CONFIG_DP8393X=y -+CONFIG_DS1225Y=y -+CONFIG_FITLOADER=y -+CONFIG_SMBIOS=y -+ -+CONFIG_PCIE_PORT=y -+CONFIG_I82801B11=y -+CONFIG_XIO3130=y -+CONFIG_PCI_EXPRESS=y -+CONFIG_MSI_NONBROKEN=y -+CONFIG_IOH3420=y -+CONFIG_SD=y -+CONFIG_SDHCI=y -+CONFIG_VIRTFS=y -+CONFIG_VIRTIO_9P=y -+CONFIG_USB_EHCI=y -+CONFIG_USB_EHCI_PCI=y -+CONFIG_USB_EHCI_SYSBUS=y -+CONFIG_USB_STORAGE_BOT=y -+CONFIG_TPM_EMULATOR=y -+CONFIG_TPM_TIS=y -+CONFIG_PLATFORM_BUS=y -+CONFIG_TPM_TIS_SYSBUS=y -+CONFIG_ACPI_LOONGARCH=y -+CONFIG_LS7A_RTC=y -diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak -new file mode 100644 -index 000000000..dc5ab3966 ---- /dev/null -+++ b/configs/targets/loongarch64-softmmu.mak -@@ -0,0 +1,4 @@ -+TARGET_ARCH=loongarch64 -+TARGET_SUPPORTS_MTTCG=y -+TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml -+ -diff --git a/disas/loongarch.c b/disas/loongarch.c -new file mode 100644 -index 000000000..14dd131e2 ---- /dev/null -+++ b/disas/loongarch.c -@@ -0,0 +1,2748 @@ -+/* -+ * QEMU Loongarch Disassembler -+ * -+ * Copyright (c) 2020-2021. -+ * Author: Song Gao, gaosong@loongson.cn -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program. If not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "disas/dis-asm.h" -+ -+#define INSNLEN 4 -+ -+/* types */ -+ -+typedef uint16_t la_opcode; -+ -+/* enums */ -+ -+typedef enum { -+ la_op_illegal = 0, -+ la_op_gr2scr = 1, -+ la_op_scr2gr = 2, -+ la_op_clo_w = 3, -+ la_op_clz_w = 4, -+ la_op_cto_w = 5, -+ la_op_ctz_w = 6, -+ la_op_clo_d = 7, -+ la_op_clz_d = 8, -+ la_op_cto_d = 9, -+ la_op_ctz_d = 10, -+ la_op_revb_2h = 11, -+ la_op_revb_4h = 12, -+ la_op_revb_2w = 13, -+ la_op_revb_d = 14, -+ la_op_revh_2w = 15, -+ la_op_revh_d = 16, -+ la_op_bitrev_4b = 17, -+ la_op_bitrev_8b = 18, -+ la_op_bitrev_w = 19, -+ la_op_bitrev_d = 20, -+ la_op_ext_w_h = 21, -+ la_op_ext_w_b = 22, -+ la_op_rdtime_d = 23, -+ la_op_cpucfg = 24, -+ la_op_asrtle_d = 25, -+ la_op_asrtgt_d = 26, -+ la_op_alsl_w = 27, -+ la_op_alsl_wu = 28, -+ la_op_bytepick_w = 29, -+ la_op_bytepick_d = 30, -+ la_op_add_w = 31, -+ la_op_add_d = 32, -+ la_op_sub_w = 33, -+ la_op_sub_d = 34, -+ la_op_slt = 35, -+ la_op_sltu = 36, -+ la_op_maskeqz = 37, -+ la_op_masknez = 38, -+ la_op_nor = 39, -+ la_op_and = 40, -+ la_op_or = 41, -+ la_op_xor = 42, -+ la_op_orn = 43, -+ la_op_andn = 44, -+ la_op_sll_w = 45, -+ la_op_srl_w = 46, -+ la_op_sra_w = 47, -+ la_op_sll_d = 48, -+ la_op_srl_d = 49, -+ la_op_sra_d = 50, -+ la_op_rotr_w = 51, -+ la_op_rotr_d = 52, -+ la_op_mul_w = 53, -+ la_op_mulh_w = 54, -+ la_op_mulh_wu = 55, -+ la_op_mul_d = 56, -+ la_op_mulh_d = 57, -+ la_op_mulh_du = 58, -+ la_op_mulw_d_w = 59, -+ la_op_mulw_d_wu = 60, -+ la_op_div_w = 61, -+ la_op_mod_w = 62, -+ la_op_div_wu = 63, -+ la_op_mod_wu = 64, -+ la_op_div_d = 65, -+ la_op_mod_d = 66, -+ la_op_div_du = 67, -+ la_op_mod_du = 68, -+ la_op_crc_w_b_w = 69, -+ la_op_crc_w_h_w = 70, -+ la_op_crc_w_w_w = 71, -+ la_op_crc_w_d_w = 72, -+ la_op_crcc_w_b_w = 73, -+ la_op_crcc_w_h_w = 74, -+ la_op_crcc_w_w_w = 75, -+ la_op_crcc_w_d_w = 76, -+ la_op_break = 77, -+ la_op_dbcl = 78, -+ la_op_syscall = 79, -+ la_op_alsl_d = 80, -+ la_op_slli_w = 81, -+ la_op_slli_d = 82, -+ la_op_srli_w = 83, -+ la_op_srli_d = 84, -+ la_op_srai_w = 85, -+ la_op_srai_d = 86, -+ la_op_rotri_w = 87, -+ la_op_rotri_d = 88, -+ la_op_bstrins_w = 89, -+ la_op_bstrpick_w = 90, -+ la_op_bstrins_d = 91, -+ la_op_bstrpick_d = 92, -+ la_op_fadd_s = 93, -+ la_op_fadd_d = 94, -+ la_op_fsub_s = 95, -+ la_op_fsub_d = 96, -+ la_op_fmul_s = 97, -+ la_op_fmul_d = 98, -+ la_op_fdiv_s = 99, -+ la_op_fdiv_d = 100, -+ la_op_fmax_s = 101, -+ la_op_fmax_d = 102, -+ la_op_fmin_s = 103, -+ la_op_fmin_d = 104, -+ la_op_fmaxa_s = 105, -+ la_op_fmaxa_d = 106, -+ la_op_fmina_s = 107, -+ la_op_fmina_d = 108, -+ la_op_fscaleb_s = 109, -+ la_op_fscaleb_d = 110, -+ la_op_fcopysign_s = 111, -+ la_op_fcopysign_d = 112, -+ la_op_fabs_s = 113, -+ la_op_fabs_d = 114, -+ la_op_fneg_s = 115, -+ la_op_fneg_d = 116, -+ la_op_flogb_s = 117, -+ la_op_flogb_d = 118, -+ la_op_fclass_s = 119, -+ la_op_fclass_d = 120, -+ la_op_fsqrt_s = 121, -+ la_op_fsqrt_d = 122, -+ la_op_frecip_s = 123, -+ la_op_frecip_d = 124, -+ la_op_frsqrt_s = 125, -+ la_op_frsqrt_d = 126, -+ la_op_fmov_s = 127, -+ la_op_fmov_d = 128, -+ la_op_movgr2fr_w = 129, -+ la_op_movgr2fr_d = 130, -+ la_op_movgr2frh_w = 131, -+ la_op_movfr2gr_s = 132, -+ la_op_movfr2gr_d = 133, -+ la_op_movfrh2gr_s = 134, -+ la_op_movgr2fcsr = 135, -+ la_op_movfcsr2gr = 136, -+ la_op_movfr2cf = 137, -+ la_op_movcf2fr = 138, -+ la_op_movgr2cf = 139, -+ la_op_movcf2gr = 140, -+ la_op_fcvt_s_d = 141, -+ la_op_fcvt_d_s = 142, -+ -+ la_op_ftintrm_w_s = 143, -+ la_op_ftintrm_w_d = 144, -+ la_op_ftintrm_l_s = 145, -+ la_op_ftintrm_l_d = 146, -+ la_op_ftintrp_w_s = 147, -+ la_op_ftintrp_w_d = 148, -+ la_op_ftintrp_l_s = 149, -+ la_op_ftintrp_l_d = 150, -+ la_op_ftintrz_w_s = 151, -+ la_op_ftintrz_w_d = 152, -+ la_op_ftintrz_l_s = 153, -+ la_op_ftintrz_l_d = 154, -+ la_op_ftintrne_w_s = 155, -+ la_op_ftintrne_w_d = 156, -+ la_op_ftintrne_l_s = 157, -+ la_op_ftintrne_l_d = 158, -+ la_op_ftint_w_s = 159, -+ la_op_ftint_w_d = 160, -+ la_op_ftint_l_s = 161, -+ la_op_ftint_l_d = 162, -+ la_op_ffint_s_w = 163, -+ la_op_ffint_s_l = 164, -+ la_op_ffint_d_w = 165, -+ la_op_ffint_d_l = 166, -+ la_op_frint_s = 167, -+ la_op_frint_d = 168, -+ -+ la_op_slti = 169, -+ la_op_sltui = 170, -+ la_op_addi_w = 171, -+ la_op_addi_d = 172, -+ la_op_lu52i_d = 173, -+ la_op_addi = 174, -+ la_op_ori = 175, -+ la_op_xori = 176, -+ -+ la_op_csrxchg = 177, -+ la_op_cacop = 178, -+ la_op_lddir = 179, -+ la_op_ldpte = 180, -+ la_op_iocsrrd_b = 181, -+ la_op_iocsrrd_h = 182, -+ la_op_iocsrrd_w = 183, -+ la_op_iocsrrd_d = 184, -+ la_op_iocsrwr_b = 185, -+ la_op_iocsrwr_h = 186, -+ la_op_iocsrwr_w = 187, -+ la_op_iocsrwr_d = 188, -+ la_op_tlbclr = 189, -+ la_op_tlbflush = 190, -+ la_op_tlbsrch = 191, -+ la_op_tlbrd = 192, -+ la_op_tlbwr = 193, -+ la_op_tlbfill = 194, -+ la_op_ertn = 195, -+ la_op_idle = 196, -+ la_op_invtlb = 197, -+ -+ la_op_fmadd_s = 198, -+ la_op_fmadd_d = 199, -+ la_op_fmsub_s = 200, -+ la_op_fmsub_d = 201, -+ la_op_fnmadd_s = 202, -+ la_op_fnmadd_d = 203, -+ la_op_fnmsub_s = 204, -+ la_op_fnmsub_d = 205, -+ la_op_fcmp_cond_s = 206, -+ la_op_fcmp_cond_d = 207, -+ la_op_fsel = 208, -+ la_op_addu16i_d = 209, -+ la_op_lu12i_w = 210, -+ la_op_lu32i_d = 211, -+ la_op_pcaddi = 212, -+ la_op_pcalau12i = 213, -+ la_op_pcaddu12i = 214, -+ la_op_pcaddu18i = 215, -+ -+ la_op_ll_w = 216, -+ la_op_sc_w = 217, -+ la_op_ll_d = 218, -+ la_op_sc_d = 219, -+ la_op_ldptr_w = 220, -+ la_op_stptr_w = 221, -+ la_op_ldptr_d = 222, -+ la_op_stptr_d = 223, -+ la_op_ld_b = 224, -+ la_op_ld_h = 225, -+ la_op_ld_w = 226, -+ la_op_ld_d = 227, -+ la_op_st_b = 228, -+ la_op_st_h = 229, -+ la_op_st_w = 230, -+ la_op_st_d = 231, -+ la_op_ld_bu = 232, -+ la_op_ld_hu = 233, -+ la_op_ld_wu = 234, -+ la_op_preld = 235, -+ la_op_fld_s = 236, -+ la_op_fst_s = 237, -+ la_op_fld_d = 238, -+ la_op_fst_d = 239, -+ la_op_ldl_w = 240, -+ la_op_ldr_w = 241, -+ la_op_ldl_d = 242, -+ la_op_ldr_d = 243, -+ la_op_stl_d = 244, -+ la_op_str_d = 245, -+ la_op_ldx_b = 246, -+ la_op_ldx_h = 247, -+ la_op_ldx_w = 248, -+ la_op_ldx_d = 249, -+ la_op_stx_b = 250, -+ la_op_stx_h = 251, -+ la_op_stx_w = 252, -+ la_op_stx_d = 253, -+ la_op_ldx_bu = 254, -+ la_op_ldx_hu = 255, -+ la_op_ldx_wu = 256, -+ la_op_fldx_s = 257, -+ la_op_fldx_d = 258, -+ la_op_fstx_s = 259, -+ la_op_fstx_d = 260, -+ -+ la_op_amswap_w = 261, -+ la_op_amswap_d = 262, -+ la_op_amadd_w = 263, -+ la_op_amadd_d = 264, -+ la_op_amand_w = 265, -+ la_op_amand_d = 266, -+ la_op_amor_w = 267, -+ la_op_amor_d = 268, -+ la_op_amxor_w = 269, -+ la_op_amxor_d = 270, -+ la_op_ammax_w = 271, -+ la_op_ammax_d = 272, -+ la_op_ammin_w = 273, -+ la_op_ammin_d = 274, -+ la_op_ammax_wu = 275, -+ la_op_ammax_du = 276, -+ la_op_ammin_wu = 277, -+ la_op_ammin_du = 278, -+ la_op_amswap_db_w = 279, -+ la_op_amswap_db_d = 280, -+ la_op_amadd_db_w = 281, -+ la_op_amadd_db_d = 282, -+ la_op_amand_db_w = 283, -+ la_op_amand_db_d = 284, -+ la_op_amor_db_w = 285, -+ la_op_amor_db_d = 286, -+ la_op_amxor_db_w = 287, -+ la_op_amxor_db_d = 288, -+ la_op_ammax_db_w = 289, -+ la_op_ammax_db_d = 290, -+ la_op_ammin_db_w = 291, -+ la_op_ammin_db_d = 292, -+ la_op_ammax_db_wu = 293, -+ la_op_ammax_db_du = 294, -+ la_op_ammin_db_wu = 295, -+ la_op_ammin_db_du = 296, -+ la_op_dbar = 297, -+ la_op_ibar = 298, -+ la_op_fldgt_s = 299, -+ la_op_fldgt_d = 300, -+ la_op_fldle_s = 301, -+ la_op_fldle_d = 302, -+ la_op_fstgt_s = 303, -+ la_op_fstgt_d = 304, -+ ls_op_fstle_s = 305, -+ la_op_fstle_d = 306, -+ la_op_ldgt_b = 307, -+ la_op_ldgt_h = 308, -+ la_op_ldgt_w = 309, -+ la_op_ldgt_d = 310, -+ la_op_ldle_b = 311, -+ la_op_ldle_h = 312, -+ la_op_ldle_w = 313, -+ la_op_ldle_d = 314, -+ la_op_stgt_b = 315, -+ la_op_stgt_h = 316, -+ la_op_stgt_w = 317, -+ la_op_stgt_d = 318, -+ la_op_stle_b = 319, -+ la_op_stle_h = 320, -+ la_op_stle_w = 321, -+ la_op_stle_d = 322, -+ la_op_beqz = 323, -+ la_op_bnez = 324, -+ la_op_bceqz = 325, -+ la_op_bcnez = 326, -+ la_op_jirl = 327, -+ la_op_b = 328, -+ la_op_bl = 329, -+ la_op_beq = 330, -+ la_op_bne = 331, -+ la_op_blt = 332, -+ la_op_bge = 333, -+ la_op_bltu = 334, -+ la_op_bgeu = 335, -+ -+ /* vz insn */ -+ la_op_hvcl = 336, -+ -+} la_op; -+ -+typedef enum { -+ la_codec_illegal, -+ la_codec_empty, -+ la_codec_2r, -+ la_codec_2r_u5, -+ la_codec_2r_u6, -+ la_codec_2r_2bw, -+ la_codec_2r_2bd, -+ la_codec_3r, -+ la_codec_3r_rd0, -+ la_codec_3r_sa2, -+ la_codec_3r_sa3, -+ la_codec_4r, -+ la_codec_r_im20, -+ la_codec_2r_im16, -+ la_codec_2r_im14, -+ la_codec_2r_im12, -+ la_codec_im5_r_im12, -+ la_codec_2r_im8, -+ la_codec_r_sd, -+ la_codec_r_sj, -+ la_codec_r_cd, -+ la_codec_r_cj, -+ la_codec_r_seq, -+ la_codec_code, -+ la_codec_whint, -+ la_codec_invtlb, -+ la_codec_r_ofs21, -+ la_codec_cj_ofs21, -+ la_codec_ofs26, -+ la_codec_cond, -+ la_codec_sel, -+ -+} la_codec; -+ -+#define la_fmt_illegal "nte" -+#define la_fmt_empty "nt" -+#define la_fmt_sd_rj "ntA,1" -+#define la_fmt_rd_sj "nt0,B" -+#define la_fmt_rd_rj "nt0,1" -+#define la_fmt_rj_rk "nt1,2" -+#define la_fmt_rj_seq "nt1,x" -+#define la_fmt_rd_si20 "nt0,i(x)" -+#define la_fmt_rd_rj_ui5 "nt0,1,C" -+#define la_fmt_rd_rj_ui6 "nt0,1.C" -+#define la_fmt_rd_rj_level "nt0,1,x" -+#define la_fmt_rd_rj_msbw_lsbw "nt0,1,C,D" -+#define la_fmt_rd_rj_msbd_lsbd "nt0,1,C,D" -+#define la_fmt_rd_rj_si12 "nt0,1,i(x)" -+#define la_fmt_hint_rj_si12 "ntE,1,i(x)" -+#define la_fmt_rd_rj_csr "nt0,1,x" -+#define la_fmt_rd_rj_si14 "nt0,1,i(x)" -+#define la_fmt_rd_rj_si16 "nt0,1,i(x)" -+#define la_fmt_rd_rj_rk "nt0,1,2" -+#define la_fmt_fd_rj_rk "nt3,1,2" -+#define la_fmt_rd_rj_rk_sa2 "nt0,1,2,D" -+#define la_fmt_rd_rj_rk_sa3 "nt0,1,2,D" -+#define la_fmt_fd_rj "nt3,1" -+#define la_fmt_rd_fj "nt0,4" -+#define la_fmt_fd_fj "nt3,4" -+#define la_fmt_fd_fj_si12 "nt3,4,i(x)" -+#define la_fmt_fcsrd_rj "ntF,1" -+#define la_fmt_rd_fcsrs "nt0,G" -+#define la_fmt_cd_fj "ntH,4" -+#define la_fmt_fd_cj "nt3,I" -+#define la_fmt_fd_fj_fk "nt3,4,5" -+#define la_fmt_code "ntJ" -+#define la_fmt_whint "ntx" -+#define la_fmt_invtlb "ntx,1,2" /* op,rj,rk */ -+#define la_fmt_offs26 "nto(X)p" -+#define la_fmt_rj_offs21 "nt1,o(X)p" -+#define la_fmt_cj_offs21 "ntQ,o(X)p" -+#define la_fmt_rd_rj_offs16 "nt0,1,o(X)" -+#define la_fmt_rj_rd_offs16 "nt1,0,o(X)p" -+#define la_fmt_s_cd_fj_fk "K.stH,4,5" -+#define la_fmt_d_cd_fj_fk "K.dtH,4,5" -+#define la_fmt_fd_fj_fk_fa "nt3,4,5,6" -+#define la_fmt_fd_fj_fk_ca "nt3,4,5,L" -+#define la_fmt_cop_rj_si12 "ntM,1,i(x)" -+ -+/* structures */ -+ -+typedef struct { -+ uint32_t pc; -+ uint32_t insn; -+ int32_t imm; -+ int32_t imm2; -+ uint16_t op; -+ uint16_t code; -+ uint8_t codec; -+ uint8_t r1; -+ uint8_t r2; -+ uint8_t r3; -+ uint8_t r4; -+ uint8_t bit; -+} la_decode; -+ -+typedef struct { -+ const char * const name; -+ const la_codec codec; -+ const char * const format; -+} la_opcode_data; -+ -+/* reg names */ -+ -+const char * const loongarch_r_normal_name[32] = { -+ "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", -+ "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", -+ "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23", -+ "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31", -+}; -+ -+const char * const loongarch_f_normal_name[32] = { -+ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", -+ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", -+ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", -+ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", -+}; -+ -+const char * const loongarch_cr_normal_name[4] = { -+ "$scr0", "$scr1", "$scr2", "$scr3", -+}; -+ -+const char * const loongarch_c_normal_name[8] = { -+ "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", -+}; -+ -+/* instruction data */ -+ -+const la_opcode_data opcode_data[] = { -+ { "illegal", la_codec_illegal, la_fmt_illegal }, -+ { "gr2scr", la_codec_r_sd, la_fmt_sd_rj }, -+ { "scr2gr", la_codec_r_sj, la_fmt_rd_sj }, -+ { "clo.w", la_codec_2r, la_fmt_rd_rj }, -+ { "clz.w", la_codec_2r, la_fmt_rd_rj }, -+ { "cto.w", la_codec_2r, la_fmt_rd_rj }, -+ { "ctz.w", la_codec_2r, la_fmt_rd_rj }, -+ { "clo.d", la_codec_2r, la_fmt_rd_rj }, -+ { "clz.d", la_codec_2r, la_fmt_rd_rj }, -+ { "cto.d", la_codec_2r, la_fmt_rd_rj }, -+ { "ctz_d", la_codec_2r, la_fmt_rd_rj }, -+ { "revb.2h", la_codec_2r, la_fmt_rd_rj }, -+ { "revb.4h", la_codec_2r, la_fmt_rd_rj }, -+ { "revb.2w", la_codec_2r, la_fmt_rd_rj }, -+ { "revb.d", la_codec_2r, la_fmt_rd_rj }, -+ { "revh.2w", la_codec_2r, la_fmt_rd_rj }, -+ { "revh.d", la_codec_2r, la_fmt_rd_rj }, -+ { "bitrev.4b", la_codec_2r, la_fmt_rd_rj }, -+ { "bitrev.8b", la_codec_2r, la_fmt_rd_rj }, -+ { "bitrev.w", la_codec_2r, la_fmt_rd_rj }, -+ { "bitrev.d", la_codec_2r, la_fmt_rd_rj }, -+ { "ext.w.h", la_codec_2r, la_fmt_rd_rj }, -+ { "ext.w.b", la_codec_2r, la_fmt_rd_rj }, -+ { "rdtime.d", la_codec_2r, la_fmt_rd_rj }, -+ { "cpucfg", la_codec_2r, la_fmt_rd_rj }, -+ { "asrtle.d", la_codec_3r_rd0, la_fmt_rj_rk }, -+ { "asrtgt.d", la_codec_3r_rd0, la_fmt_rj_rk }, -+ { "alsl.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, -+ { "alsl.wu", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, -+ { "bytepick.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, -+ { "bytepick.d", la_codec_3r_sa3, la_fmt_rd_rj_rk_sa3 }, -+ { "add.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "add.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sub.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sub.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "slt", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sltu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "maskeqz", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "masknez", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "nor", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "and", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "or", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "xor", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "orn", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "andn", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sll.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "srl.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sra.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sll.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "srl.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sra.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "rotr.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "rotr.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mul.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulh.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulh.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mul.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulh.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulh.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulw.d.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulw.d.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "div.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mod.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "div.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mod.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "div.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mod.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "div.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mod.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crcc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crcc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crcc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crcc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "break", la_codec_code, la_fmt_code }, -+ { "dbcl", la_codec_code, la_fmt_code }, -+ { "syscall", la_codec_code, la_fmt_code }, -+ { "alsl.d", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, -+ { "slli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, -+ { "slli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, -+ { "srli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, -+ { "srli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, -+ { "srai.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, -+ { "srai.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, -+ { "rotri.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, -+ { "rotri.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, -+ { "bstrins.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw }, -+ { "bstrpick.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw }, -+ { "bstrins.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd }, -+ { "bstrpick.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd }, -+ { "fadd.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fadd.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fsub.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fsub.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmul.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmul.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fdiv.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fdiv.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmax.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmax.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmin.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmin.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmaxa.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmaxa.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmina.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmina.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fscaleb.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fscaleb.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fcopysign.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fcopysign.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fabs.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fabs.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fneg.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fneg.d", la_codec_2r, la_fmt_fd_fj }, -+ { "flogb.s", la_codec_2r, la_fmt_fd_fj }, -+ { "flogb.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fclass.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fclass.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fsqrt.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fsqrt.d", la_codec_2r, la_fmt_fd_fj }, -+ { "frecip.s", la_codec_2r, la_fmt_fd_fj }, -+ { "frecip.d", la_codec_2r, la_fmt_fd_fj }, -+ { "frsqrt.s", la_codec_2r, la_fmt_fd_fj }, -+ { "frsqrt.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fmov.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fmov.d", la_codec_2r, la_fmt_fd_fj }, -+ { "movgr2fr.w", la_codec_2r, la_fmt_fd_rj }, -+ { "movgr2fr.d", la_codec_2r, la_fmt_fd_rj }, -+ { "movgr2frh.w", la_codec_2r, la_fmt_fd_rj }, -+ { "movfr2gr.s", la_codec_2r, la_fmt_rd_fj }, -+ { "movfr2gr.d", la_codec_2r, la_fmt_rd_fj }, -+ { "movfrh2gr.s", la_codec_2r, la_fmt_rd_fj }, -+ { "movgr2fcsr", la_codec_2r, la_fmt_fcsrd_rj }, -+ { "movfcsr2gr", la_codec_2r, la_fmt_rd_fcsrs }, -+ { "movfr2cf", la_codec_r_cd, la_fmt_cd_fj }, -+ { "movcf2fr", la_codec_r_cj, la_fmt_fd_cj }, -+ { "movgr2cf", la_codec_r_cd, la_fmt_cd_fj }, -+ { "movcf2gr", la_codec_r_cj, la_fmt_fd_cj }, -+ { "fcvt.s.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fcvt.d.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrm.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrm.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrm.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrm.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrp.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrp.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrp.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrp.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrz.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrz.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrz.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrz.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrne.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrne.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrne.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrne.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftint.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftint.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftint.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftint.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ffint.s.w", la_codec_2r, la_fmt_fd_fj }, -+ { "ffint.s.l", la_codec_2r, la_fmt_fd_fj }, -+ { "ffint.d.w", la_codec_2r, la_fmt_fd_fj }, -+ { "ffint.d.l", la_codec_2r, la_fmt_fd_fj }, -+ { "frint.s", la_codec_2r, la_fmt_fd_fj }, -+ { "frint.d", la_codec_2r, la_fmt_fd_fj }, -+ { "slti", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "sltui", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "addi.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "addi.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "lu52i.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "addi", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ori", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "xori", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "csrxchg", la_codec_2r_im14, la_fmt_rd_rj_csr }, -+ { "cacop", la_codec_im5_r_im12, la_fmt_cop_rj_si12 }, -+ { "lddir", la_codec_2r_im8, la_fmt_rd_rj_level }, -+ { "ldpte", la_codec_r_seq, la_fmt_rj_seq }, -+ { "iocsrrd.b", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrrd.h", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrrd.w", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrrd.d", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrwr.b", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrwr.h", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrwr.w", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrwr.d", la_codec_2r, la_fmt_rd_rj }, -+ { "tlbclr", la_codec_empty, la_fmt_empty }, -+ { "tlbflush", la_codec_empty, la_fmt_empty }, -+ { "tlbsrch", la_codec_empty, la_fmt_empty }, -+ { "tlbrd", la_codec_empty, la_fmt_empty }, -+ { "tlbwr", la_codec_empty, la_fmt_empty }, -+ { "tlbfill", la_codec_empty, la_fmt_empty }, -+ { "ertn", la_codec_empty, la_fmt_empty }, -+ { "idle", la_codec_whint, la_fmt_whint }, -+ { "invtlb", la_codec_invtlb, la_fmt_invtlb }, -+ { "fmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fnmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fnmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fnmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fnmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fcmp.cond.s", la_codec_cond, la_fmt_s_cd_fj_fk }, -+ { "fcmp.cond.d", la_codec_cond, la_fmt_d_cd_fj_fk }, -+ { "fsel", la_codec_sel, la_fmt_fd_fj_fk_ca }, -+ { "addu16i.d", la_codec_2r_im16, la_fmt_rd_rj_si16 }, -+ { "lu12i.w", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "lu32i.d", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "pcaddi", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "pcalau12i", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "pcaddu12i", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "pcaddu18i", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "ll.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "sc.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "ll.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "sc.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "ldptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "stptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "ldptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "stptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "ld.b", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.h", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "st.b", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "st.h", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "st.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "st.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.bu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.hu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.wu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "preld", la_codec_2r_im12, la_fmt_hint_rj_si12 }, -+ { "fld.s", la_codec_2r_im12, la_fmt_fd_fj_si12 }, -+ { "fst.s", la_codec_2r_im12, la_fmt_fd_fj_si12 }, -+ { "fld.d", la_codec_2r_im12, la_fmt_fd_fj_si12 }, -+ { "fst.d", la_codec_2r_im12, la_fmt_fd_fj_si12 }, -+ { "ldl.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ldr.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ldl.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ldr.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "stl.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "str.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ldx.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stx.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stx.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stx.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stx.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.bu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.hu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "fldx.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fldx.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstx.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstx.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "amswap.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amswap.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amadd.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amadd.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amand.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amand.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amor.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amor.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amxor.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amxor.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amswap.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amswap.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amadd.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amadd.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amand.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amand.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amor.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amor.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amxor.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amxor.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.db.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.db.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.db.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.db.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "dbar", la_codec_whint, la_fmt_whint }, -+ { "ibar", la_codec_whint, la_fmt_whint }, -+ { "fldgt.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fldgt.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fldle.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fldle.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstgt.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstgt.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstle.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstle.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "ldgt.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldgt.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldgt.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldgt.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldle.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldle.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldle.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldle.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stgt.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stgt.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stgt.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stgt.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stle.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stle.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stle.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stle.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "beqz", la_codec_r_ofs21, la_fmt_rj_offs21 }, -+ { "bnez", la_codec_r_ofs21, la_fmt_rj_offs21 }, -+ { "bceqz", la_codec_cj_ofs21, la_fmt_cj_offs21 }, -+ { "bcnez", la_codec_cj_ofs21, la_fmt_cj_offs21 }, -+ { "jirl", la_codec_2r_im16, la_fmt_rd_rj_offs16 }, -+ { "b", la_codec_ofs26, la_fmt_offs26 }, -+ { "bl", la_codec_ofs26, la_fmt_offs26 }, -+ { "beq", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "bne", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "blt", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "bge", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "bltu", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "bgeu", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ -+ /* vz insn */ -+ { "hvcl", la_codec_code, la_fmt_code }, -+ -+}; -+ -+ -+/* decode opcode */ -+ -+static void decode_insn_opcode(la_decode *dec) -+{ -+ uint32_t insn = dec->insn; -+ uint16_t op = la_op_illegal; -+ switch ((insn >> 26) & 0x3f) { -+ case 0x0: -+ switch ((insn >> 22) & 0xf) { -+ case 0x0: -+ switch ((insn >> 18) & 0xf) { -+ case 0x0: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x2: -+ switch ((insn >> 2) & 0x7) { -+ case 0x0: -+ op = la_op_gr2scr; -+ break; -+ } -+ break; -+ case 0x3: -+ switch ((insn >> 7) & 0x7) { -+ case 0x0: -+ op = la_op_scr2gr; -+ break; -+ } -+ break; -+ case 0x4: -+ op = la_op_clo_w; -+ break; -+ case 0x5: -+ op = la_op_clz_w; -+ break; -+ case 0x6: -+ op = la_op_cto_w; -+ break; -+ case 0x7: -+ op = la_op_ctz_w; -+ break; -+ case 0x8: -+ op = la_op_clo_d; -+ break; -+ case 0x9: -+ op = la_op_clz_d; -+ break; -+ case 0xa: -+ op = la_op_cto_d; -+ break; -+ case 0xb: -+ op = la_op_ctz_d; -+ break; -+ case 0xc: -+ op = la_op_revb_2h; -+ break; -+ case 0xd: -+ op = la_op_revb_4h; -+ break; -+ case 0xe: -+ op = la_op_revb_2w; -+ break; -+ case 0xf: -+ op = la_op_revb_d; -+ break; -+ case 0x10: -+ op = la_op_revh_2w; -+ break; -+ case 0x11: -+ op = la_op_revh_d; -+ break; -+ case 0x12: -+ op = la_op_bitrev_4b; -+ break; -+ case 0x13: -+ op = la_op_bitrev_8b; -+ break; -+ case 0x14: -+ op = la_op_bitrev_w; -+ break; -+ case 0x15: -+ op = la_op_bitrev_d; -+ break; -+ case 0x16: -+ op = la_op_ext_w_h; -+ break; -+ case 0x17: -+ op = la_op_ext_w_b; -+ break; -+ case 0x1a: -+ op = la_op_rdtime_d; -+ break; -+ case 0x1b: -+ op = la_op_cpucfg; -+ break; -+ } -+ break; -+ case 0x2: -+ switch (insn & 0x0000001f) { -+ case 0x00000000: -+ op = la_op_asrtle_d; -+ break; -+ } -+ break; -+ case 0x3: -+ switch (insn & 0x0000001f) { -+ case 0x00000000: -+ op = la_op_asrtgt_d; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x1: -+ switch ((insn >> 17) & 0x1) { -+ case 0x0: -+ op = la_op_alsl_w; -+ break; -+ case 0x1: -+ op = la_op_alsl_wu; -+ break; -+ } -+ break; -+ case 0x2: -+ switch ((insn >> 17) & 0x1) { -+ case 0x0: -+ op = la_op_bytepick_w; -+ break; -+ } -+ break; -+ case 0x3: -+ op = la_op_bytepick_d; -+ break; -+ case 0x4: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_add_w; -+ break; -+ case 0x1: -+ op = la_op_add_d; -+ break; -+ case 0x2: -+ op = la_op_sub_w; -+ break; -+ case 0x3: -+ op = la_op_sub_d; -+ break; -+ case 0x4: -+ op = la_op_slt; -+ break; -+ case 0x5: -+ op = la_op_sltu; -+ break; -+ case 0x6: -+ op = la_op_maskeqz; -+ break; -+ case 0x7: -+ op = la_op_masknez; -+ break; -+ } -+ break; -+ case 0x5: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_nor; -+ break; -+ case 0x1: -+ op = la_op_and; -+ break; -+ case 0x2: -+ op = la_op_or; -+ break; -+ case 0x3: -+ op = la_op_xor; -+ break; -+ case 0x4: -+ op = la_op_orn; -+ break; -+ case 0x5: -+ op = la_op_andn; -+ break; -+ case 0x6: -+ op = la_op_sll_w; -+ break; -+ case 0x7: -+ op = la_op_srl_w; -+ break; -+ } -+ break; -+ case 0x6: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_sra_w; -+ break; -+ case 0x1: -+ op = la_op_sll_d; -+ break; -+ case 0x2: -+ op = la_op_srl_d; -+ break; -+ case 0x3: -+ op = la_op_sra_d; -+ break; -+ case 0x6: -+ op = la_op_rotr_w; -+ break; -+ case 0x7: -+ op = la_op_rotr_d; -+ break; -+ } -+ break; -+ case 0x7: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_mul_w; -+ break; -+ case 0x1: -+ op = la_op_mulh_w; -+ break; -+ case 0x2: -+ op = la_op_mulh_wu; -+ break; -+ case 0x3: -+ op = la_op_mul_d; -+ break; -+ case 0x4: -+ op = la_op_mulh_d; -+ break; -+ case 0x5: -+ op = la_op_mulh_du; -+ break; -+ case 0x6: -+ op = la_op_mulw_d_w; -+ break; -+ case 0x7: -+ op = la_op_mulw_d_wu; -+ break; -+ } -+ break; -+ case 0x8: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_div_w; -+ break; -+ case 0x1: -+ op = la_op_mod_w; -+ break; -+ case 0x2: -+ op = la_op_div_wu; -+ break; -+ case 0x3: -+ op = la_op_mod_wu; -+ break; -+ case 0x4: -+ op = la_op_div_d; -+ break; -+ case 0x5: -+ op = la_op_mod_d; -+ break; -+ case 0x6: -+ op = la_op_div_du; -+ break; -+ case 0x7: -+ op = la_op_mod_du; -+ break; -+ } -+ break; -+ case 0x9: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_crc_w_b_w; -+ break; -+ case 0x1: -+ op = la_op_crc_w_h_w; -+ break; -+ case 0x2: -+ op = la_op_crc_w_w_w; -+ break; -+ case 0x3: -+ op = la_op_crc_w_d_w; -+ break; -+ case 0x4: -+ op = la_op_crcc_w_b_w; -+ break; -+ case 0x5: -+ op = la_op_crcc_w_h_w; -+ break; -+ case 0x6: -+ op = la_op_crcc_w_w_w; -+ break; -+ case 0x7: -+ op = la_op_crcc_w_d_w; -+ break; -+ } -+ break; -+ case 0xa: -+ switch ((insn >> 15) & 0x7) { -+ case 0x4: -+ op = la_op_break; -+ break; -+ case 0x5: -+ op = la_op_dbcl; -+ break; -+ case 0x6: -+ op = la_op_syscall; -+ break; -+ case 0x7: -+ op = la_op_hvcl; -+ break; -+ } -+ break; -+ case 0xb: -+ switch ((insn >> 17) & 0x1) { -+ case 0x0: -+ op = la_op_alsl_d; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x1: -+ switch ((insn >> 21) & 0x1) { -+ case 0x0: -+ switch ((insn >> 16) & 0x1f) { -+ case 0x0: -+ switch ((insn >> 15) & 0x1) { -+ case 0x1: -+ op = la_op_slli_w; -+ break; -+ } -+ break; -+ case 0x1: -+ op = la_op_slli_d; -+ break; -+ case 0x4: -+ switch ((insn >> 15) & 0x1) { -+ case 0x1: -+ op = la_op_srli_w; -+ break; -+ } -+ break; -+ case 0x5: -+ op = la_op_srli_d; -+ break; -+ case 0x8: -+ switch ((insn >> 15) & 0x1) { -+ case 0x1: -+ op = la_op_srai_w; -+ break; -+ } -+ break; -+ case 0x9: -+ op = la_op_srai_d; -+ break; -+ case 0xc: -+ switch ((insn >> 15) & 0x1) { -+ case 0x1: -+ op = la_op_rotri_w; -+ break; -+ } -+ break; -+ case 0xd: -+ op = la_op_rotri_d; -+ break; -+ } -+ break; -+ case 0x1: -+ switch ((insn >> 15) & 0x1) { -+ case 0x0: -+ op = la_op_bstrins_w; -+ break; -+ case 0x1: -+ op = la_op_bstrpick_w; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x2: -+ op = la_op_bstrins_d; -+ break; -+ case 0x3: -+ op = la_op_bstrpick_d; -+ break; -+ case 0x4: -+ switch ((insn >> 15) & 0x7f) { -+ case 0x1: -+ op = la_op_fadd_s; -+ break; -+ case 0x2: -+ op = la_op_fadd_d; -+ break; -+ case 0x5: -+ op = la_op_fsub_s; -+ break; -+ case 0x6: -+ op = la_op_fsub_d; -+ break; -+ case 0x9: -+ op = la_op_fmul_s; -+ break; -+ case 0xa: -+ op = la_op_fmul_d; -+ break; -+ case 0xd: -+ op = la_op_fdiv_s; -+ break; -+ case 0xe: -+ op = la_op_fdiv_d; -+ break; -+ case 0x11: -+ op = la_op_fmax_s; -+ break; -+ case 0x12: -+ op = la_op_fmax_d; -+ break; -+ case 0x15: -+ op = la_op_fmin_s; -+ break; -+ case 0x16: -+ op = la_op_fmin_d; -+ break; -+ case 0x19: -+ op = la_op_fmaxa_s; -+ break; -+ case 0x1a: -+ op = la_op_fmaxa_d; -+ break; -+ case 0x1d: -+ op = la_op_fmina_s; -+ break; -+ case 0x1e: -+ op = la_op_fmina_d; -+ break; -+ case 0x21: -+ op = la_op_fscaleb_s; -+ break; -+ case 0x22: -+ op = la_op_fscaleb_d; -+ break; -+ case 0x25: -+ op = la_op_fcopysign_s; -+ break; -+ case 0x26: -+ op = la_op_fcopysign_d; -+ break; -+ case 0x28: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x1: -+ op = la_op_fabs_s; -+ break; -+ case 0x2: -+ op = la_op_fabs_d; -+ break; -+ case 0x5: -+ op = la_op_fneg_s; -+ break; -+ case 0x6: -+ op = la_op_fneg_d; -+ break; -+ case 0x9: -+ op = la_op_flogb_s; -+ break; -+ case 0xa: -+ op = la_op_flogb_d; -+ break; -+ case 0xd: -+ op = la_op_fclass_s; -+ break; -+ case 0xe: -+ op = la_op_fclass_d; -+ break; -+ case 0x11: -+ op = la_op_fsqrt_s; -+ break; -+ case 0x12: -+ op = la_op_fsqrt_d; -+ break; -+ case 0x15: -+ op = la_op_frecip_s; -+ break; -+ case 0x16: -+ op = la_op_frecip_d; -+ break; -+ case 0x19: -+ op = la_op_frsqrt_s; -+ break; -+ case 0x1a: -+ op = la_op_frsqrt_d; -+ break; -+ } -+ break; -+ case 0x29: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x5: -+ op = la_op_fmov_s; -+ break; -+ case 0x6: -+ op = la_op_fmov_d; -+ break; -+ case 0x9: -+ op = la_op_movgr2fr_w; -+ break; -+ case 0xa: -+ op = la_op_movgr2fr_d; -+ break; -+ case 0xb: -+ op = la_op_movgr2frh_w; -+ break; -+ case 0xd: -+ op = la_op_movfr2gr_s; -+ break; -+ case 0xe: -+ op = la_op_movfr2gr_d; -+ break; -+ case 0xf: -+ op = la_op_movfrh2gr_s; -+ break; -+ case 0x10: -+ op = la_op_movgr2fcsr; -+ break; -+ case 0x12: -+ op = la_op_movfcsr2gr; -+ break; -+ case 0x14: -+ switch ((insn >> 3) & 0x3) { -+ case 0x0: -+ op = la_op_movfr2cf; -+ break; -+ } -+ break; -+ case 0x15: -+ switch ((insn >> 8) & 0x3) { -+ case 0x0: -+ op = la_op_movcf2fr; -+ break; -+ } -+ break; -+ case 0x16: -+ switch ((insn >> 3) & 0x3) { -+ case 0x0: -+ op = la_op_movgr2cf; -+ break; -+ } -+ break; -+ case 0x17: -+ switch ((insn >> 8) & 0x3) { -+ case 0x0: -+ op = la_op_movcf2gr; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x32: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x6: -+ op = la_op_fcvt_s_d; -+ break; -+ case 0x9: -+ op = la_op_fcvt_d_s; -+ break; -+ } -+ break; -+ case 0x34: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x1: -+ op = la_op_ftintrm_w_s; -+ break; -+ case 0x2: -+ op = la_op_ftintrm_w_d; -+ break; -+ case 0x9: -+ op = la_op_ftintrm_l_s; -+ break; -+ case 0xa: -+ op = la_op_ftintrm_l_d; -+ break; -+ case 0x11: -+ op = la_op_ftintrp_w_s; -+ break; -+ case 0x12: -+ op = la_op_ftintrp_w_d; -+ break; -+ case 0x19: -+ op = la_op_ftintrp_l_s; -+ break; -+ case 0x1a: -+ op = la_op_ftintrp_l_d; -+ break; -+ } -+ break; -+ case 0x35: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x1: -+ op = la_op_ftintrz_w_s; -+ break; -+ case 0x2: -+ op = la_op_ftintrz_w_d; -+ break; -+ case 0x9: -+ op = la_op_ftintrz_l_s; -+ break; -+ case 0xa: -+ op = la_op_ftintrz_l_d; -+ break; -+ case 0x11: -+ op = la_op_ftintrne_w_s; -+ break; -+ case 0x12: -+ op = la_op_ftintrne_w_d; -+ break; -+ case 0x19: -+ op = la_op_ftintrne_l_s; -+ break; -+ case 0x1a: -+ op = la_op_ftintrne_l_d; -+ break; -+ } -+ break; -+ case 0x36: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x1: -+ op = la_op_ftint_w_s; -+ break; -+ case 0x2: -+ op = la_op_ftint_w_d; -+ break; -+ case 0x9: -+ op = la_op_ftint_l_s; -+ break; -+ case 0xa: -+ op = la_op_ftint_l_d; -+ break; -+ } -+ break; -+ case 0x3a: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x4: -+ op = la_op_ffint_s_w; -+ break; -+ case 0x6: -+ op = la_op_ffint_s_l; -+ break; -+ case 0x8: -+ op = la_op_ffint_d_w; -+ break; -+ case 0xa: -+ op = la_op_ffint_d_l; -+ break; -+ } -+ break; -+ case 0x3c: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x11: -+ op = la_op_frint_s; -+ break; -+ case 0x12: -+ op = la_op_frint_d; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x8: -+ op = la_op_slti; -+ break; -+ case 0x9: -+ op = la_op_sltui; -+ break; -+ case 0xa: -+ op = la_op_addi_w; -+ break; -+ case 0xb: -+ op = la_op_addi_d; -+ break; -+ case 0xc: -+ op = la_op_lu52i_d; -+ break; -+ case 0xd: -+ op = la_op_addi; -+ break; -+ case 0xe: -+ op = la_op_ori; -+ break; -+ case 0xf: -+ op = la_op_xori; -+ break; -+ } -+ break; -+ case 0x1: -+ switch ((insn >> 24) & 0x3) { -+ case 0x0: -+ op = la_op_csrxchg; -+ break; -+ case 0x2: -+ switch ((insn >> 22) & 0x3) { -+ case 0x0: -+ op = la_op_cacop; -+ break; -+ case 0x1: -+ switch ((insn >> 18) & 0xf) { -+ case 0x0: -+ op = la_op_lddir; -+ break; -+ case 0x1: -+ switch (insn & 0x0000001f) { -+ case 0x00000000: -+ op = la_op_ldpte; -+ break; -+ } -+ break; -+ case 0x2: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x0: -+ op = la_op_iocsrrd_b; -+ break; -+ case 0x1: -+ op = la_op_iocsrrd_h; -+ break; -+ case 0x2: -+ op = la_op_iocsrrd_w; -+ break; -+ case 0x3: -+ op = la_op_iocsrrd_d; -+ break; -+ case 0x4: -+ op = la_op_iocsrwr_b; -+ break; -+ case 0x5: -+ op = la_op_iocsrwr_h; -+ break; -+ case 0x6: -+ op = la_op_iocsrwr_w; -+ break; -+ case 0x7: -+ op = la_op_iocsrwr_d; -+ break; -+ case 0x8: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbclr; -+ break; -+ } -+ break; -+ case 0x9: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbflush; -+ break; -+ } -+ break; -+ case 0xa: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbsrch; -+ break; -+ } -+ break; -+ case 0xb: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbrd; -+ break; -+ } -+ break; -+ case 0xc: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbwr; -+ break; -+ } -+ break; -+ case 0xd: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbfill; -+ break; -+ } -+ break; -+ case 0xe: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_ertn; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x1: -+ op = la_op_idle; -+ break; -+ case 0x3: -+ op = la_op_invtlb; -+ break; -+ } -+ break; -+ } -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x2: -+ switch ((insn >> 20) & 0x3f) { -+ case 0x1: -+ op = la_op_fmadd_s; -+ break; -+ case 0x2: -+ op = la_op_fmadd_d; -+ break; -+ case 0x5: -+ op = la_op_fmsub_s; -+ break; -+ case 0x6: -+ op = la_op_fmsub_d; -+ break; -+ case 0x9: -+ op = la_op_fnmadd_s; -+ break; -+ case 0xa: -+ op = la_op_fnmadd_d; -+ break; -+ case 0xd: -+ op = la_op_fnmsub_s; -+ break; -+ case 0xe: -+ op = la_op_fnmsub_d; -+ break; -+ } -+ break; -+ case 0x3: -+ switch ((insn >> 20) & 0x3f) { -+ case 0x1: -+ switch ((insn >> 3) & 0x3) { -+ case 0x0: -+ op = la_op_fcmp_cond_s; -+ break; -+ } -+ break; -+ case 0x2: -+ switch ((insn >> 3) & 0x3) { -+ case 0x0: -+ op = la_op_fcmp_cond_d; -+ break; -+ } -+ break; -+ case 0x10: -+ switch ((insn >> 18) & 0x3) { -+ case 0x0: -+ op = la_op_fsel; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x4: -+ op = la_op_addu16i_d; -+ break; -+ case 0x5: -+ switch ((insn >> 25) & 0x1) { -+ case 0x0: -+ op = la_op_lu12i_w; -+ break; -+ case 0x1: -+ op = la_op_lu32i_d; -+ break; -+ } -+ break; -+ case 0x6: -+ switch ((insn >> 25) & 0x1) { -+ case 0x0: -+ op = la_op_pcaddi; -+ break; -+ case 0x1: -+ op = la_op_pcalau12i; -+ break; -+ } -+ break; -+ case 0x7: -+ switch ((insn >> 25) & 0x1) { -+ case 0x0: -+ op = la_op_pcaddu12i; -+ break; -+ case 0x1: -+ op = la_op_pcaddu18i; -+ break; -+ } -+ break; -+ case 0x8: -+ switch ((insn >> 24) & 0x3) { -+ case 0x0: -+ op = la_op_ll_w; -+ break; -+ case 0x1: -+ op = la_op_sc_w; -+ break; -+ case 0x2: -+ op = la_op_ll_d; -+ break; -+ case 0x3: -+ op = la_op_sc_d; -+ break; -+ } -+ break; -+ case 0x9: -+ switch ((insn >> 24) & 0x3) { -+ case 0x0: -+ op = la_op_ldptr_w; -+ break; -+ case 0x1: -+ op = la_op_stptr_w; -+ break; -+ case 0x2: -+ op = la_op_ldptr_d; -+ break; -+ case 0x3: -+ op = la_op_stptr_d; -+ break; -+ } -+ break; -+ case 0xa: -+ switch ((insn >> 22) & 0xf) { -+ case 0x0: -+ op = la_op_ld_b; -+ break; -+ case 0x1: -+ op = la_op_ld_h; -+ break; -+ case 0x2: -+ op = la_op_ld_w; -+ break; -+ case 0x3: -+ op = la_op_ld_d; -+ break; -+ case 0x4: -+ op = la_op_st_b; -+ break; -+ case 0x5: -+ op = la_op_st_h; -+ break; -+ case 0x6: -+ op = la_op_st_w; -+ break; -+ case 0x7: -+ op = la_op_st_d; -+ break; -+ case 0x8: -+ op = la_op_ld_bu; -+ break; -+ case 0x9: -+ op = la_op_ld_hu; -+ break; -+ case 0xa: -+ op = la_op_ld_wu; -+ break; -+ case 0xb: -+ op = la_op_preld; -+ break; -+ case 0xc: -+ op = la_op_fld_s; -+ break; -+ case 0xd: -+ op = la_op_fst_s; -+ break; -+ case 0xe: -+ op = la_op_fld_d; -+ break; -+ case 0xf: -+ op = la_op_fst_d; -+ break; -+ } -+ break; -+ case 0xb: -+ switch ((insn >> 22) & 0xf) { -+ case 0x8: -+ op = la_op_ldl_w; -+ break; -+ case 0x9: -+ op = la_op_ldr_w; -+ break; -+ case 0xa: -+ op = la_op_ldl_d; -+ break; -+ case 0xb: -+ op = la_op_ldr_d; -+ break; -+ case 0xe: -+ op = la_op_stl_d; -+ break; -+ case 0xf: -+ op = la_op_str_d; -+ break; -+ } -+ break; -+ case 0xe: -+ switch ((insn >> 15) & 0x7ff) { -+ case 0x0: -+ op = la_op_ldx_b; -+ break; -+ case 0x8: -+ op = la_op_ldx_h; -+ break; -+ case 0x10: -+ op = la_op_ldx_w; -+ break; -+ case 0x18: -+ op = la_op_ldx_d; -+ break; -+ case 0x20: -+ op = la_op_stx_b; -+ break; -+ case 0x28: -+ op = la_op_stx_h; -+ break; -+ case 0x30: -+ op = la_op_stx_w; -+ break; -+ case 0x38: -+ op = la_op_stx_d; -+ break; -+ case 0x40: -+ op = la_op_ldx_bu; -+ break; -+ case 0x48: -+ op = la_op_ldx_hu; -+ break; -+ case 0x50: -+ op = la_op_ldx_wu; -+ break; -+ case 0x60: -+ op = la_op_fldx_s; -+ break; -+ case 0x68: -+ op = la_op_fldx_d; -+ break; -+ case 0x70: -+ op = la_op_fstx_s; -+ break; -+ case 0x78: -+ op = la_op_fstx_d; -+ break; -+ case 0xc0: -+ op = la_op_amswap_w; -+ break; -+ case 0xc1: -+ op = la_op_amswap_d; -+ break; -+ case 0xc2: -+ op = la_op_amadd_w; -+ break; -+ case 0xc3: -+ op = la_op_amadd_d; -+ break; -+ case 0xc4: -+ op = la_op_amand_w; -+ break; -+ case 0xc5: -+ op = la_op_amand_d; -+ break; -+ case 0xc6: -+ op = la_op_amor_w; -+ break; -+ case 0xc7: -+ op = la_op_amor_d; -+ break; -+ case 0xc8: -+ op = la_op_amxor_w; -+ break; -+ case 0xc9: -+ op = la_op_amxor_d; -+ break; -+ case 0xca: -+ op = la_op_ammax_w; -+ break; -+ case 0xcb: -+ op = la_op_ammax_d; -+ break; -+ case 0xcc: -+ op = la_op_ammin_w; -+ break; -+ case 0xcd: -+ op = la_op_ammin_d; -+ break; -+ case 0xce: -+ op = la_op_ammax_wu; -+ break; -+ case 0xcf: -+ op = la_op_ammax_du; -+ break; -+ case 0xd0: -+ op = la_op_ammin_wu; -+ break; -+ case 0xd1: -+ op = la_op_ammin_du; -+ break; -+ case 0xd2: -+ op = la_op_amswap_db_w; -+ break; -+ case 0xd3: -+ op = la_op_amswap_db_d; -+ break; -+ case 0xd4: -+ op = la_op_amadd_db_w; -+ break; -+ case 0xd5: -+ op = la_op_amadd_db_d; -+ break; -+ case 0xd6: -+ op = la_op_amand_db_w; -+ break; -+ case 0xd7: -+ op = la_op_amand_db_d; -+ break; -+ case 0xd8: -+ op = la_op_amor_db_w; -+ break; -+ case 0xd9: -+ op = la_op_amor_db_d; -+ break; -+ case 0xda: -+ op = la_op_amxor_db_w; -+ break; -+ case 0xdb: -+ op = la_op_amxor_db_d; -+ break; -+ case 0xdc: -+ op = la_op_ammax_db_w; -+ break; -+ case 0xdd: -+ op = la_op_ammax_db_d; -+ break; -+ case 0xde: -+ op = la_op_ammin_db_w; -+ break; -+ case 0xdf: -+ op = la_op_ammin_db_d; -+ break; -+ case 0xe0: -+ op = la_op_ammax_db_wu; -+ break; -+ case 0xe1: -+ op = la_op_ammax_db_du; -+ break; -+ case 0xe2: -+ op = la_op_ammin_db_wu; -+ break; -+ case 0xe3: -+ op = la_op_ammin_db_du; -+ break; -+ case 0xe4: -+ op = la_op_dbar; -+ break; -+ case 0xe5: -+ op = la_op_ibar; -+ break; -+ case 0xe8: -+ op = la_op_fldgt_s; -+ break; -+ case 0xe9: -+ op = la_op_fldgt_d; -+ break; -+ case 0xea: -+ op = la_op_fldle_s; -+ break; -+ case 0xeb: -+ op = la_op_fldle_d; -+ break; -+ case 0xec: -+ op = la_op_fstgt_s; -+ break; -+ case 0xed: -+ op = la_op_fstgt_d; -+ break; -+ case 0xee: -+ op = ls_op_fstle_s; -+ break; -+ case 0xef: -+ op = la_op_fstle_d; -+ break; -+ case 0xf0: -+ op = la_op_ldgt_b; -+ break; -+ case 0xf1: -+ op = la_op_ldgt_h; -+ break; -+ case 0xf2: -+ op = la_op_ldgt_w; -+ break; -+ case 0xf3: -+ op = la_op_ldgt_d; -+ break; -+ case 0xf4: -+ op = la_op_ldle_b; -+ break; -+ case 0xf5: -+ op = la_op_ldle_h; -+ break; -+ case 0xf6: -+ op = la_op_ldle_w; -+ break; -+ case 0xf7: -+ op = la_op_ldle_d; -+ break; -+ case 0xf8: -+ op = la_op_stgt_b; -+ break; -+ case 0xf9: -+ op = la_op_stgt_h; -+ break; -+ case 0xfa: -+ op = la_op_stgt_w; -+ break; -+ case 0xfb: -+ op = la_op_stgt_d; -+ break; -+ case 0xfc: -+ op = la_op_stle_b; -+ break; -+ case 0xfd: -+ op = la_op_stle_h; -+ break; -+ case 0xfe: -+ op = la_op_stle_w; -+ break; -+ case 0xff: -+ op = la_op_stle_d; -+ break; -+ } -+ break; -+ case 0x10: -+ op = la_op_beqz; -+ break; -+ case 0x11: -+ op = la_op_bnez; -+ break; -+ case 0x12: -+ switch ((insn >> 8) & 0x3) { -+ case 0x0: -+ op = la_op_bceqz; -+ break; -+ case 0x1: -+ op = la_op_bcnez; -+ break; -+ } -+ break; -+ case 0x13: -+ op = la_op_jirl; -+ break; -+ case 0x14: -+ op = la_op_b; -+ break; -+ case 0x15: -+ op = la_op_bl; -+ break; -+ case 0x16: -+ op = la_op_beq; -+ break; -+ case 0x17: -+ op = la_op_bne; -+ break; -+ case 0x18: -+ op = la_op_blt; -+ break; -+ case 0x19: -+ op = la_op_bge; -+ break; -+ case 0x1a: -+ op = la_op_bltu; -+ break; -+ case 0x1b: -+ op = la_op_bgeu; -+ break; -+ default: -+ op = la_op_illegal; -+ break; -+ } -+ dec->op = op; -+} -+ -+/* operand extractors */ -+ -+#define IM_5 5 -+#define IM_8 8 -+#define IM_12 12 -+#define IM_14 14 -+#define IM_15 15 -+#define IM_16 16 -+#define IM_20 20 -+#define IM_21 21 -+#define IM_26 26 -+ -+static uint32_t operand_r1(uint32_t insn) -+{ -+ return insn & 0x1f; -+} -+ -+static uint32_t operand_r2(uint32_t insn) -+{ -+ return (insn >> 5) & 0x1f; -+} -+ -+static uint32_t operand_r3(uint32_t insn) -+{ -+ return (insn >> 10) & 0x1f; -+} -+ -+static uint32_t operand_r4(uint32_t insn) -+{ -+ return (insn >> 15) & 0x1f; -+} -+ -+static uint32_t operand_u6(uint32_t insn) -+{ -+ return (insn >> 10) & 0x3f; -+} -+ -+static uint32_t operand_bw1(uint32_t insn) -+{ -+ return (insn >> 10) & 0x1f; -+} -+ -+static uint32_t operand_bw2(uint32_t insn) -+{ -+ return (insn >> 16) & 0x1f; -+} -+ -+static uint32_t operand_bd1(uint32_t insn) -+{ -+ return (insn >> 10) & 0x3f; -+} -+ -+static uint32_t operand_bd2(uint32_t insn) -+{ -+ return (insn >> 16) & 0x3f; -+} -+ -+static uint32_t operand_sa2(uint32_t insn) -+{ -+ return (insn >> 15) & 0x3; -+} -+ -+static uint32_t operand_sa3(uint32_t insn) -+{ -+ return (insn >> 15) & 0x3; -+} -+ -+static int32_t operand_im20(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 5) & 0xfffff); -+ return imm > (1 << 19) ? imm - (1 << 20) : imm; -+} -+ -+static int32_t operand_im16(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 10) & 0xffff); -+ return imm > (1 << 15) ? imm - (1 << 16) : imm; -+} -+ -+static int32_t operand_im14(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 10) & 0x3fff); -+ return imm > (1 << 13) ? imm - (1 << 14) : imm; -+} -+ -+static int32_t operand_im12(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 10) & 0xfff); -+ return imm > (1 << 11) ? imm - (1 << 12) : imm; -+} -+ -+static int32_t operand_im8(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 10) & 0xff); -+ return imm > (1 << 7) ? imm - (1 << 8) : imm; -+} -+ -+static uint32_t operand_sd(uint32_t insn) -+{ -+ return insn & 0x3; -+} -+ -+static uint32_t operand_sj(uint32_t insn) -+{ -+ return (insn >> 5) & 0x3; -+} -+ -+static uint32_t operand_cd(uint32_t insn) -+{ -+ return insn & 0x7; -+} -+ -+static uint32_t operand_cj(uint32_t insn) -+{ -+ return (insn >> 5) & 0x7; -+} -+ -+static uint32_t operand_code(uint32_t insn) -+{ -+ return insn & 0x7fff; -+} -+ -+static int32_t operand_whint(uint32_t insn) -+{ -+ int32_t imm = (int32_t)(insn & 0x7fff); -+ return imm > (1 << 14) ? imm - (1 << 15) : imm; -+} -+ -+static int32_t operand_invop(uint32_t insn) -+{ -+ int32_t imm = (int32_t)(insn & 0x1f); -+ return imm > (1 << 4) ? imm - (1 << 5) : imm; -+} -+ -+static int32_t operand_ofs21(uint32_t insn) -+{ -+ int32_t imm = (((int32_t)insn & 0x1f) << 16) | -+ ((insn >> 10) & 0xffff); -+ return imm > (1 << 20) ? imm - (1 << 21) : imm; -+} -+ -+static int32_t operand_ofs26(uint32_t insn) -+{ -+ int32_t imm = (((int32_t)insn & 0x3ff) << 16) | -+ ((insn >> 10) & 0xffff); -+ return imm > (1 << 25) ? imm - (1 << 26) : imm; -+} -+ -+static uint32_t operand_fcond(uint32_t insn) -+{ -+ return (insn >> 15) & 0x1f; -+} -+ -+static uint32_t operand_sel(uint32_t insn) -+{ -+ return (insn >> 15) & 0x7; -+} -+ -+/* decode operands */ -+ -+static void decode_insn_operands(la_decode *dec) -+{ -+ uint32_t insn = dec->insn; -+ dec->codec = opcode_data[dec->op].codec; -+ switch (dec->codec) { -+ case la_codec_illegal: -+ case la_codec_empty: -+ break; -+ case la_codec_2r: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ break; -+ case la_codec_2r_u5: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ break; -+ case la_codec_2r_u6: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_u6(insn); -+ break; -+ case la_codec_2r_2bw: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_bw1(insn); -+ dec->r4 = operand_bw2(insn); -+ break; -+ case la_codec_2r_2bd: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_bd1(insn); -+ dec->r4 = operand_bd2(insn); -+ break; -+ case la_codec_3r: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ break; -+ case la_codec_3r_rd0: -+ dec->r1 = 0; -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ break; -+ case la_codec_3r_sa2: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_sa2(insn); -+ break; -+ case la_codec_3r_sa3: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_sa3(insn); -+ break; -+ case la_codec_4r: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_r4(insn); -+ break; -+ case la_codec_r_im20: -+ dec->r1 = operand_r1(insn); -+ dec->imm = operand_im20(insn); -+ dec->bit = IM_20; -+ break; -+ case la_codec_2r_im16: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im16(insn); -+ dec->bit = IM_16; -+ break; -+ case la_codec_2r_im14: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im14(insn); -+ dec->bit = IM_14; -+ break; -+ case la_codec_im5_r_im12: -+ dec->imm2 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im12(insn); -+ dec->bit = IM_12; -+ break; -+ case la_codec_2r_im12: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im12(insn); -+ dec->bit = IM_12; -+ break; -+ case la_codec_2r_im8: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im8(insn); -+ dec->bit = IM_8; -+ break; -+ case la_codec_r_sd: -+ dec->r1 = operand_sd(insn); -+ dec->r2 = operand_r2(insn); -+ break; -+ case la_codec_r_sj: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_sj(insn); -+ break; -+ case la_codec_r_cd: -+ dec->r1 = operand_cd(insn); -+ dec->r2 = operand_r2(insn); -+ break; -+ case la_codec_r_cj: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_cj(insn); -+ break; -+ case la_codec_r_seq: -+ dec->r1 = 0; -+ dec->r2 = operand_r1(insn); -+ dec->imm = operand_im8(insn); -+ dec->bit = IM_8; -+ break; -+ case la_codec_code: -+ dec->code = operand_code(insn); -+ break; -+ case la_codec_whint: -+ dec->imm = operand_whint(insn); -+ dec->bit = IM_15; -+ break; -+ case la_codec_invtlb: -+ dec->imm = operand_invop(insn); -+ dec->bit = IM_5; -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ break; -+ case la_codec_r_ofs21: -+ dec->imm = operand_ofs21(insn); -+ dec->bit = IM_21; -+ dec->r2 = operand_r2(insn); -+ break; -+ case la_codec_cj_ofs21: -+ dec->imm = operand_ofs21(insn); -+ dec->bit = IM_21; -+ dec->r2 = operand_cj(insn); -+ break; -+ case la_codec_ofs26: -+ dec->imm = operand_ofs26(insn); -+ dec->bit = IM_26; -+ break; -+ case la_codec_cond: -+ dec->r1 = operand_cd(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_fcond(insn); -+ break; -+ case la_codec_sel: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_sel(insn); -+ break; -+ } -+} -+ -+/* format instruction */ -+ -+static void append(char *s1, const char *s2, size_t n) -+{ -+ size_t l1 = strlen(s1); -+ if (n - l1 - 1 > 0) { -+ strncat(s1, s2, n - l1); -+ } -+} -+ -+static void format_insn(char *buf, size_t buflen, size_t tab, la_decode *dec) -+{ -+ char tmp[16]; -+ const char *fmt; -+ -+ fmt = opcode_data[dec->op].format; -+ while (*fmt) { -+ switch (*fmt) { -+ case 'n': /* name */ -+ append(buf, opcode_data[dec->op].name, buflen); -+ break; -+ case 's': -+ append(buf, "s", buflen); -+ break; -+ case 'd': -+ append(buf, "d", buflen); -+ break; -+ case 'e': /* illegal */ -+ snprintf(tmp, sizeof(tmp), "%x", dec->insn); -+ append(buf, tmp, buflen); -+ break; -+ case 't': -+ while (strlen(buf) < tab) { -+ append(buf, " ", buflen); -+ } -+ break; -+ case '(': -+ append(buf, "(", buflen); -+ break; -+ case ',': -+ append(buf, ",", buflen); -+ break; -+ case '.': -+ append(buf, ".", buflen); -+ break; -+ case ')': -+ append(buf, ")", buflen); -+ break; -+ case '0': /* rd */ -+ append(buf, loongarch_r_normal_name[dec->r1], buflen); -+ break; -+ case '1': /* rj */ -+ append(buf, loongarch_r_normal_name[dec->r2], buflen); -+ break; -+ case '2': /* rk */ -+ append(buf, loongarch_r_normal_name[dec->r3], buflen); -+ break; -+ case '3': /* fd */ -+ append(buf, loongarch_f_normal_name[dec->r1], buflen); -+ break; -+ case '4': /* fj */ -+ append(buf, loongarch_f_normal_name[dec->r2], buflen); -+ break; -+ case '5': /* fk */ -+ append(buf, loongarch_f_normal_name[dec->r3], buflen); -+ break; -+ case '6': /* fa */ -+ append(buf, loongarch_f_normal_name[dec->r4], buflen); -+ break; -+ case 'A': /* sd */ -+ append(buf, loongarch_cr_normal_name[dec->r1], buflen); -+ break; -+ case 'B': /* sj */ -+ append(buf, loongarch_cr_normal_name[dec->r2], buflen); -+ break; -+ case 'C': /* r3 */ -+ snprintf(tmp, sizeof(tmp), "%x", dec->r3); -+ append(buf, tmp, buflen); -+ break; -+ case 'D': /* r4 */ -+ snprintf(tmp, sizeof(tmp), "%x", dec->r4); -+ append(buf, tmp, buflen); -+ break; -+ case 'E': /* r1 */ -+ snprintf(tmp, sizeof(tmp), "%x", dec->r1); -+ append(buf, tmp, buflen); -+ break; -+ case 'F': /* fcsrd */ -+ append(buf, loongarch_r_normal_name[dec->r1], buflen); -+ break; -+ case 'G': /* fcsrs */ -+ append(buf, loongarch_r_normal_name[dec->r2], buflen); -+ break; -+ case 'H': /* cd */ -+ append(buf, loongarch_c_normal_name[dec->r1], buflen); -+ break; -+ case 'I': /* cj */ -+ append(buf, loongarch_c_normal_name[dec->r2], buflen); -+ break; -+ case 'J': /* code */ -+ snprintf(tmp, sizeof(tmp), "0x%x", dec->code); -+ append(buf, tmp, buflen); -+ break; -+ case 'K': /* cond */ -+ switch (dec->r4) { -+ case 0x0: -+ append(buf, "caf", buflen); -+ break; -+ case 0x1: -+ append(buf, "saf", buflen); -+ break; -+ case 0x2: -+ append(buf, "clt", buflen); -+ break; -+ case 0x3: -+ append(buf, "slt", buflen); -+ break; -+ case 0x4: -+ append(buf, "ceq", buflen); -+ break; -+ case 0x5: -+ append(buf, "seq", buflen); -+ break; -+ case 0x6: -+ append(buf, "cle", buflen); -+ break; -+ case 0x7: -+ append(buf, "sle", buflen); -+ break; -+ case 0x8: -+ append(buf, "cun", buflen); -+ break; -+ case 0x9: -+ append(buf, "sun", buflen); -+ break; -+ case 0xA: -+ append(buf, "cult", buflen); -+ break; -+ case 0xB: -+ append(buf, "sult", buflen); -+ break; -+ case 0xC: -+ append(buf, "cueq", buflen); -+ break; -+ case 0xD: -+ append(buf, "sueq", buflen); -+ break; -+ case 0xE: -+ append(buf, "cule", buflen); -+ break; -+ case 0xF: -+ append(buf, "sule", buflen); -+ break; -+ case 0x10: -+ append(buf, "cne", buflen); -+ break; -+ case 0x11: -+ append(buf, "sne", buflen); -+ break; -+ case 0x14: -+ append(buf, "cor", buflen); -+ break; -+ case 0x15: -+ append(buf, "sor", buflen); -+ break; -+ case 0x18: -+ append(buf, "cune", buflen); -+ break; -+ case 0x19: -+ append(buf, "sune", buflen); -+ break; -+ } -+ break; -+ case 'L': /* ca */ -+ append(buf, loongarch_c_normal_name[dec->r4], buflen); -+ break; -+ case 'M': /* cop */ -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm2) & 0x1f); -+ append(buf, tmp, buflen); -+ break; -+ case 'i': /* sixx d */ -+ snprintf(tmp, sizeof(tmp), "%d", dec->imm); -+ append(buf, tmp, buflen); -+ break; -+ case 'o': /* offset */ -+ snprintf(tmp, sizeof(tmp), "%d", (dec->imm) << 2); -+ append(buf, tmp, buflen); -+ break; -+ case 'x': /* sixx x */ -+ switch (dec->bit) { -+ case IM_5: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x1f); -+ append(buf, tmp, buflen); -+ break; -+ case IM_8: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_12: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_14: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x3fff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_15: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x7fff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_16: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xffff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_20: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfffff); -+ append(buf, tmp, buflen); -+ break; -+ default: -+ snprintf(tmp, sizeof(tmp), "0x%x", dec->imm); -+ append(buf, tmp, buflen); -+ break; -+ } -+ break; -+ case 'X': /* offset x*/ -+ switch (dec->bit) { -+ case IM_16: -+ snprintf(tmp, sizeof(tmp), "0x%x", -+ ((dec->imm) << 2) & 0xffff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_21: -+ snprintf(tmp, sizeof(tmp), "0x%x", -+ ((dec->imm) << 2) & 0x1fffff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_26: -+ snprintf(tmp, sizeof(tmp), "0x%x", -+ ((dec->imm) << 2) & 0x3ffffff); -+ append(buf, tmp, buflen); -+ break; -+ default: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) << 2); -+ append(buf, tmp, buflen); -+ break; -+ } -+ break; -+ case 'p': /* pc */ -+ snprintf(tmp, sizeof(tmp), " # 0x%"PRIx32"", -+ dec->pc + ((dec->imm) << 2)); -+ append(buf, tmp, buflen); -+ break; -+ default: -+ break; -+ } -+ fmt++; -+ } -+} -+ -+ -+/* disassemble instruction */ -+ -+static void -+disasm_insn(char *buf, size_t buflen, bfd_vma pc, unsigned long int insn) -+{ -+ la_decode dec = { 0 }; -+ dec.pc = pc; -+ dec.insn = insn; -+ decode_insn_opcode(&dec); -+ decode_insn_operands(&dec); -+ format_insn(buf, buflen, 16, &dec); -+} -+ -+int -+print_insn_loongarch(bfd_vma memaddr, struct disassemble_info *info) -+{ -+ char buf[128] = { 0 }; -+ bfd_byte buffer[INSNLEN]; -+ unsigned long insn; -+ int status; -+ -+ status = (*info->read_memory_func)(memaddr, buffer, INSNLEN, info); -+ if (status == 0) { -+ insn = (uint32_t) bfd_getl32(buffer); -+ (*info->fprintf_func)(info->stream, "%08" PRIx64 " ", insn); -+ } else { -+ (*info->memory_error_func)(status, memaddr, info); -+ return -1; -+ } -+ disasm_insn(buf, sizeof(buf), memaddr, insn); -+ (*info->fprintf_func)(info->stream, "\t%s", buf); -+ return INSNLEN; -+} -diff --git a/disas/meson.build b/disas/meson.build -index 449f99e1d..06a69d9d7 100644 ---- a/disas/meson.build -+++ b/disas/meson.build -@@ -12,6 +12,7 @@ common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c')) - common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) - common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) - common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) -+common_ss.add(when: 'CONFIG_LOONGARCH_DIS', if_true: files('loongarch.c')) - common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.cpp')) - common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c')) - common_ss.add(when: 'CONFIG_PPC_DIS', if_true: files('ppc.c')) -diff --git a/gdb-xml/loongarch-base32.xml b/gdb-xml/loongarch-base32.xml -new file mode 100644 -index 000000000..04891e023 ---- /dev/null -+++ b/gdb-xml/loongarch-base32.xml -@@ -0,0 +1,43 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/gdb-xml/loongarch-base64.xml b/gdb-xml/loongarch-base64.xml -new file mode 100644 -index 000000000..6308fb6ec ---- /dev/null -+++ b/gdb-xml/loongarch-base64.xml -@@ -0,0 +1,43 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/gdb-xml/loongarch-fpu32.xml b/gdb-xml/loongarch-fpu32.xml -new file mode 100644 -index 000000000..a5b4d80e6 ---- /dev/null -+++ b/gdb-xml/loongarch-fpu32.xml -@@ -0,0 +1,52 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/gdb-xml/loongarch-fpu64.xml b/gdb-xml/loongarch-fpu64.xml -new file mode 100644 -index 000000000..74ab55a01 ---- /dev/null -+++ b/gdb-xml/loongarch-fpu64.xml -@@ -0,0 +1,57 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ --- -2.43.5 - diff --git a/0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch b/0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch deleted file mode 100644 index af4851e..0000000 --- a/0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch +++ /dev/null @@ -1,35 +0,0 @@ -From e25884e4e0ee839b591836ae33681ac9a52883ce Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Wed, 25 Aug 2021 12:36:00 +0800 -Subject: [PATCH 6/8] anolis: csv/i386: CSV guest do not need - register/unregister guest secure memory - -CSV guest memory is allocated by firmware in secure processor -from dedicated memory reserved upon system boot up, -consequently it is not necessary to add notifier to pin/unpin memory. - -Signed-off-by: Xin Jiang -Change-Id: I10d5b5ee8dbc3a1bf9ed1935c006c61a094f1e8d ---- - target/i386/sev.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 73a794ef74..36669bbdf4 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -973,7 +973,10 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - goto err; - } - -- ram_block_notifier_add(&sev_ram_notifier); -+ /* CSV guest needs no notifier to reg/unreg memory */ -+ if (!csv_enabled()) { -+ ram_block_notifier_add(&sev_ram_notifier); -+ } - qemu_add_machine_init_done_notifier(&sev_machine_done_notify); - qemu_add_vm_change_state_handler(sev_vm_state_change, sev); - --- -2.17.1 - diff --git a/0007-Modify-kvm-cpu-vga-qapi.patch b/0007-Modify-kvm-cpu-vga-qapi.patch deleted file mode 100644 index 7c09b0a..0000000 --- a/0007-Modify-kvm-cpu-vga-qapi.patch +++ /dev/null @@ -1,477 +0,0 @@ -From 42c6c2a89fa44100141cd2b7e178f965d1b8f80f Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Sat, 20 Aug 2022 02:18:41 -0400 -Subject: [PATCH 07/28] Modify kvm cpu vga qapi. - -Change-Id: I7923af804bdbe6d44d3f521df1859aa081afceba -Signed-off-by: lixianglai -Signed-off-by: Mao Bibo ---- - hw/acpi/cpu.c | 11 ++++++ - hw/loongarch/iocsr.c | 2 ++ - hw/loongarch/larch_3a.c | 18 +++++----- - hw/meson.build | 1 + - include/disas/dis-asm.h | 1 + - include/elf.h | 2 ++ - include/hw/loongarch/larch.h | 1 - - include/qemu/osdep.h | 3 ++ - include/sysemu/arch_init.h | 1 + - linux-headers/linux/kvm.h | 23 +++++++++++++ - linux-user/elfload.c | 67 ++++++++++++++++++++++++++++++++++++ - linux-user/meson.build | 1 + - linux-user/qemu.h | 2 +- - linux-user/syscall.c | 3 ++ - linux-user/syscall_defs.h | 9 ++--- - meson.build | 1 + - pc-bios/meson.build | 1 + - qapi/machine-target.json | 6 ++-- - qapi/machine.json | 2 +- - qapi/misc-target.json | 1 + - 20 files changed, 138 insertions(+), 18 deletions(-) - -diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c -index b20903ea3..cd73fab65 100644 ---- a/hw/acpi/cpu.c -+++ b/hw/acpi/cpu.c -@@ -371,14 +371,25 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, - aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0)); - - crs = aml_resource_template(); -+#ifdef __loongarch__ -+ aml_append(crs, aml_memory32_fixed(io_base, -+ ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE)); -+#else - aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, - ACPI_CPU_HOTPLUG_REG_LEN)); -+#endif - aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs)); - - /* declare CPU hotplug MMIO region with related access fields */ -+#ifdef __loongarch__ -+ aml_append(cpu_ctrl_dev, -+ aml_operation_region("PRST", AML_SYSTEM_MEMORY, aml_int(io_base), -+ ACPI_CPU_HOTPLUG_REG_LEN)); -+#else - aml_append(cpu_ctrl_dev, - aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base), - ACPI_CPU_HOTPLUG_REG_LEN)); -+#endif - - field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, - AML_WRITE_AS_ZEROS); -diff --git a/hw/loongarch/iocsr.c b/hw/loongarch/iocsr.c -index 14521c2d5..60daafd6e 100644 ---- a/hw/loongarch/iocsr.c -+++ b/hw/loongarch/iocsr.c -@@ -59,6 +59,7 @@ enum { - IOCSR_MAX - }; - -+#ifdef CONFIG_KVM - static uint32_t iocsr_array[IOCSR_MAX] = { - [IOCSR_FEATURES] = LOONGARCH_IOCSR_FEATURES, - [IOCSR_VENDOR] = LOONGARCH_IOCSR_VENDOR, -@@ -66,6 +67,7 @@ static uint32_t iocsr_array[IOCSR_MAX] = { - [IOCSR_NODECNT] = LOONGARCH_IOCSR_NODECNT, - [IOCSR_MISC_FUNC] = LOONGARCH_IOCSR_MISC_FUNC, - }; -+#endif - - - #define TYPE_IOCSR "iocsr" -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 3db269274..3194a822c 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -846,7 +846,7 @@ static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg, - if (0 < initrd_size) { - if (initrd_size > highram_size) { - error_report("initrd size is too big, should below %ld MB", -- highram_size / S_1MiB); -+ highram_size / MiB); - /*prevent write io memory address space*/ - exit(1); - } -@@ -1033,7 +1033,9 @@ static void *ls3a_intctl_init(MachineState *machine, CPULOONGARCHState *env[]) - SysBusDevice *busdev; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *iomem = NULL; -+#ifdef CONFIG_KVM - int i; -+#endif - - s = g_malloc0(sizeof(ls3a_intctlstate)); - -@@ -1214,8 +1216,6 @@ static void loongarch_build_smbios(LoongarchMachineState *lsms) - product = "Loongarch-3A5K-7A1000-TCG"; - } - -- host_cpufreq = get_host_cpu_freq(); -- - smbios_set_defaults("Loongson", product, lsmc->cpu_name, false, - true, NULL, NULL, SMBIOS_ENTRY_POINT_30); - -@@ -1672,15 +1672,15 @@ static void ls3a5k_init(MachineState *args) - - offset += lowram_size; - if (nb_numa_nodes > 0) { -- highram_size = numa_info[0].node_mem - S_256MiB; -- if (numa_info[0].node_mem > S_1GiB) { -- memmap_size = numa_info[0].node_mem - S_1GiB; -+ highram_size = numa_info[0].node_mem - 256 * MiB; -+ if (numa_info[0].node_mem > GiB) { -+ memmap_size = numa_info[0].node_mem - GiB; - la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); - } - } else { -- highram_size = ram_size - S_256MiB; -- if (ram_size > S_1GiB) { -- memmap_size = ram_size - S_1GiB; -+ highram_size = ram_size - 256 * MiB; -+ if (ram_size > GiB) { -+ memmap_size = ram_size - GiB; - la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); - } - } -diff --git a/hw/meson.build b/hw/meson.build -index b3366c888..f224f8ad2 100644 ---- a/hw/meson.build -+++ b/hw/meson.build -@@ -17,6 +17,7 @@ subdir('intc') - subdir('ipack') - subdir('ipmi') - subdir('isa') -+subdir('loongarch') - subdir('mem') - subdir('misc') - subdir('net') -diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h -index 08e1beec8..95b93f100 100644 ---- a/include/disas/dis-asm.h -+++ b/include/disas/dis-asm.h -@@ -461,6 +461,7 @@ int print_insn_riscv32 (bfd_vma, disassemble_info*); - int print_insn_riscv64 (bfd_vma, disassemble_info*); - int print_insn_rx(bfd_vma, disassemble_info *); - int print_insn_hexagon(bfd_vma, disassemble_info *); -+int print_insn_loongarch (bfd_vma, disassemble_info*); - - #ifdef CONFIG_CAPSTONE - bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size); -diff --git a/include/elf.h b/include/elf.h -index 4edab8e5a..c614bfb12 100644 ---- a/include/elf.h -+++ b/include/elf.h -@@ -182,6 +182,8 @@ typedef struct mips_elf_abiflags_v0 { - - #define EM_NANOMIPS 249 /* Wave Computing nanoMIPS */ - -+#define EM_LOONGARCH 258 /* Loongarch */ -+ - /* - * This is an interim value that we will use until the committee comes - * up with a final number. -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -index 0886ed52a..62e2830e2 100644 ---- a/include/hw/loongarch/larch.h -+++ b/include/hw/loongarch/larch.h -@@ -159,5 +159,4 @@ bool loongarch_is_acpi_enabled(LoongarchMachineState *vms); - void ls7a_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, bool force_enabled); - void slave_cpu_reset(void *opaque); --extern uint64_t host_cpufreq; - #endif -diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h -index 60718fc34..903475bb2 100644 ---- a/include/qemu/osdep.h -+++ b/include/qemu/osdep.h -@@ -533,6 +533,9 @@ static inline void qemu_cleanup_generic_vfree(void *p) - Valgrind does not support alignments larger than 1 MiB, - therefore we need special code which handles running on Valgrind. */ - # define QEMU_VMALLOC_ALIGN (512 * 4096) -+#elif defined(__linux__) && defined(__loongarch__) -+ /* Use 32 MiB alignment so transparent hugepages can be used by KVM. */ -+# define QEMU_VMALLOC_ALIGN (qemu_real_host_page_size * qemu_real_host_page_size / 8) - #elif defined(__linux__) && defined(__s390x__) - /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */ - # define QEMU_VMALLOC_ALIGN (256 * 4096) -diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h -index 70c579560..62d1a4b92 100644 ---- a/include/sysemu/arch_init.h -+++ b/include/sysemu/arch_init.h -@@ -24,6 +24,7 @@ enum { - QEMU_ARCH_RX = (1 << 20), - QEMU_ARCH_AVR = (1 << 21), - QEMU_ARCH_HEXAGON = (1 << 22), -+ QEMU_ARCH_LOONGARCH64 = (1 << 23), - }; - - extern const uint32_t arch_type; -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index c65930288..0e50d3749 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -2115,6 +2115,29 @@ struct kvm_stats_desc { - char name[]; - }; - -+#ifdef __loongarch__ -+struct kvm_loongarch_vcpu_state { -+ __u8 online_vcpus; -+ __u8 is_migrate; -+ __u32 cpu_freq; -+ __u32 count_ctl; -+ __u64 pending_exceptions; -+ __u64 pending_exceptions_clr; -+ __u64 core_ext_ioisr[4]; -+}; -+ -+#define KVM_CAP_LOONGARCH_FPU 165 -+#define KVM_CAP_LOONGARCH_LSX 166 -+#define KVM_CAP_LOONGARCH_VZ 167 -+#define KVM_REG_LOONGARCH 0x8000000000000000ULL -+#define KVM_LARCH_GET_VCPU_STATE _IOR(KVMIO, 0xc0, struct kvm_loongarch_vcpu_state) -+#define KVM_LARCH_SET_VCPU_STATE _IOW(KVMIO, 0xc1, struct kvm_loongarch_vcpu_state) -+#define KVM_LARCH_GET_CPUCFG _IOR(KVMIO, 0xc2, struct kvm_cpucfg) -+#define KVM_LOONGARCH_GET_IOCSR _IOR(KVMIO, 0xc3, struct kvm_iocsr_entry) -+#define KVM_LOONGARCH_SET_IOCSR _IOW(KVMIO, 0xc4, struct kvm_iocsr_entry) -+#define KVM_LARCH_SET_CPUCFG _IOR(KVMIO, 0xc5, struct kvm_cpucfg) -+#endif -+ - #define KVM_GET_STATS_FD _IO(KVMIO, 0xce) - - /* Available with KVM_CAP_XSAVE2 */ -diff --git a/linux-user/elfload.c b/linux-user/elfload.c -index 767f54c76..9fb632780 100644 ---- a/linux-user/elfload.c -+++ b/linux-user/elfload.c -@@ -1041,6 +1041,73 @@ static uint32_t get_elf_hwcap(void) - - #endif /* TARGET_MIPS */ - -+#ifdef TARGET_LOONGARCH64 -+ -+#define ELF_START_MMAP 0x80000000 -+ -+#define ELF_CLASS ELFCLASS64 -+#define ELF_ARCH EM_LOONGARCH -+ -+#define elf_check_arch(x) ((x) == EM_LOONGARCH) -+ -+static inline void init_thread(struct target_pt_regs *regs, -+ struct image_info *infop) -+{ -+ regs->csr_crmd = 2 << 3; -+ regs->csr_era = infop->entry; -+ regs->regs[3] = infop->start_stack; -+} -+ -+/* See linux kernel: arch/mips/include/asm/elf.h. */ -+#define ELF_NREG 45 -+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; -+ -+/* See linux kernel: arch/loongarch/include/uapi/asm/reg.h */ -+enum { -+ TARGET_EF_R0 = 0, -+ TARGET_EF_R26 = TARGET_EF_R0 + 26, -+ TARGET_EF_R27 = TARGET_EF_R0 + 27, -+ TARGET_EF_CSR_ERA = TARGET_EF_R0 + 32, -+ TARGET_EF_CSR_BADV = TARGET_EF_R0 + 33, -+ TARGET_EF_CSR_CRMD = TARGET_EF_R0 + 34, -+ TARGET_EF_CSR_ESTAT = TARGET_EF_R0 + 38 -+}; -+ -+/* See linux kernel: arch/loongarch/kernel/process.c:elf_dump_regs. */ -+static void elf_core_copy_regs(target_elf_gregset_t *regs, -+ const CPULOONGARCHState *env) -+{ -+ int i; -+ -+ for (i = 0; i < TARGET_EF_R0; i++) { -+ (*regs)[i] = 0; -+ } -+ (*regs)[TARGET_EF_R0] = 0; -+ -+ for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) { -+ (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]); -+ } -+ -+ (*regs)[TARGET_EF_R26] = 0; -+ (*regs)[TARGET_EF_R27] = 0; -+ (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->active_tc.PC); -+ (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV); -+ (*regs)[TARGET_EF_CSR_CRMD] = tswapreg(env->CSR_CRMD); -+ (*regs)[TARGET_EF_CSR_ESTAT] = tswapreg(env->CSR_ESTAT); -+} -+ -+#define USE_ELF_CORE_DUMP -+#define ELF_EXEC_PAGESIZE 4096 -+ -+#define ELF_HWCAP get_elf_hwcap() -+ -+static uint32_t get_elf_hwcap(void) -+{ -+ return 0; -+} -+ -+#endif /* TARGET_LOONGARCH64 */ -+ - #ifdef TARGET_MICROBLAZE - - #define ELF_START_MMAP 0x80000000 -diff --git a/linux-user/meson.build b/linux-user/meson.build -index bf62c13e3..195f9e83a 100644 ---- a/linux-user/meson.build -+++ b/linux-user/meson.build -@@ -39,3 +39,4 @@ subdir('sh4') - subdir('sparc') - subdir('x86_64') - subdir('xtensa') -+subdir('loongarch64') -diff --git a/linux-user/qemu.h b/linux-user/qemu.h -index 5c713fa8a..66ddb25d1 100644 ---- a/linux-user/qemu.h -+++ b/linux-user/qemu.h -@@ -61,7 +61,7 @@ struct image_info { - /* For target-specific processing of NT_GNU_PROPERTY_TYPE_0. */ - uint32_t note_flags; - --#ifdef TARGET_MIPS -+#if defined(TARGET_MIPS) || defined(TARGET_LOONGARCH64) - int fp_abi; - int interp_fp_abi; - #endif -diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index f1cfcc810..729131ecd 100644 ---- a/linux-user/syscall.c -+++ b/linux-user/syscall.c -@@ -1614,6 +1614,9 @@ static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, - #elif defined(TARGET_MIPS) - ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1]; - return host_pipe[0]; -+#elif defined(TARGET_LOONGARCH64) -+ ((CPULOONGARCHState *)cpu_env)->active_tc.gpr[5] = host_pipe[1]; -+ return host_pipe[0]; - #elif defined(TARGET_SH4) - ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; - return host_pipe[0]; -diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h -index 0b1397593..7e2915d53 100644 ---- a/linux-user/syscall_defs.h -+++ b/linux-user/syscall_defs.h -@@ -74,7 +74,7 @@ - || defined(TARGET_M68K) || defined(TARGET_CRIS) \ - || defined(TARGET_S390X) || defined(TARGET_OPENRISC) \ - || defined(TARGET_NIOS2) || defined(TARGET_RISCV) \ -- || defined(TARGET_XTENSA) -+ || defined(TARGET_XTENSA) || defined(TARGET_LOONGARCH64) - - #define TARGET_IOC_SIZEBITS 14 - #define TARGET_IOC_DIRBITS 2 -@@ -450,7 +450,7 @@ struct target_dirent64 { - #define TARGET_SIG_IGN ((abi_long)1) /* ignore signal */ - #define TARGET_SIG_ERR ((abi_long)-1) /* error return from signal */ - --#ifdef TARGET_MIPS -+#if defined(TARGET_MIPS) || defined(TARGET_LOONGARCH64) - #define TARGET_NSIG 128 - #else - #define TARGET_NSIG 64 -@@ -2133,7 +2133,7 @@ struct target_stat64 { - abi_ulong __unused5; - }; - --#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || defined(TARGET_RISCV) -+#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || defined(TARGET_RISCV) || defined(TARGET_LOONGARCH64) - - /* These are the asm-generic versions of the stat and stat64 structures */ - -@@ -2161,7 +2161,7 @@ struct target_stat { - unsigned int __unused5; - }; - --#if !defined(TARGET_RISCV64) -+#if !(defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64)) - #define TARGET_HAS_STRUCT_STAT64 - struct target_stat64 { - uint64_t st_dev; -@@ -2331,6 +2331,7 @@ struct target_statfs64 { - }; - #elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \ - defined(TARGET_SPARC64) || defined(TARGET_AARCH64) || \ -+ defined(TARGET_LOONGARCH64) || \ - defined(TARGET_RISCV)) && !defined(TARGET_ABI32) - struct target_statfs { - abi_long f_type; -diff --git a/meson.build b/meson.build -index 5f6ba86db..fc2dc58f3 100644 ---- a/meson.build -+++ b/meson.build -@@ -1814,6 +1814,7 @@ disassemblers = { - 'sh4' : ['CONFIG_SH4_DIS'], - 'sparc' : ['CONFIG_SPARC_DIS'], - 'xtensa' : ['CONFIG_XTENSA_DIS'], -+ 'loongarch64' : ['CONFIG_LOONGARCH_DIS'], - } - if link_language == 'cpp' - disassemblers += { -diff --git a/pc-bios/meson.build b/pc-bios/meson.build -index b40ff3f2b..a09ca4d03 100644 ---- a/pc-bios/meson.build -+++ b/pc-bios/meson.build -@@ -83,6 +83,7 @@ blobs = files( - 'opensbi-riscv32-generic-fw_dynamic.elf', - 'opensbi-riscv64-generic-fw_dynamic.elf', - 'npcm7xx_bootrom.bin', -+ 'loongarch_bios.bin', - ) - - if get_option('install_blobs') -diff --git a/qapi/machine-target.json b/qapi/machine-target.json -index f5ec4bc17..682dc86b4 100644 ---- a/qapi/machine-target.json -+++ b/qapi/machine-target.json -@@ -324,7 +324,8 @@ - 'TARGET_ARM', - 'TARGET_I386', - 'TARGET_S390X', -- 'TARGET_MIPS' ] } } -+ 'TARGET_MIPS', -+ 'TARGET_LOONGARCH64' ] } } - - ## - # @query-cpu-definitions: -@@ -340,4 +341,5 @@ - 'TARGET_ARM', - 'TARGET_I386', - 'TARGET_S390X', -- 'TARGET_MIPS' ] } } -+ 'TARGET_MIPS', -+ 'TARGET_LOONGARCH64' ] } } -diff --git a/qapi/machine.json b/qapi/machine.json -index a9f33d0f2..cd47b8d6b 100644 ---- a/qapi/machine.json -+++ b/qapi/machine.json -@@ -34,7 +34,7 @@ - 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', - 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', - 'sh4eb', 'sparc', 'sparc64', 'tricore', -- 'x86_64', 'xtensa', 'xtensaeb' ] } -+ 'x86_64', 'xtensa', 'xtensaeb', 'loongarch64' ] } - - ## - # @CpuS390State: -diff --git a/qapi/misc-target.json b/qapi/misc-target.json -index ede905244..2cf4fa418 100644 ---- a/qapi/misc-target.json -+++ b/qapi/misc-target.json -@@ -33,6 +33,7 @@ - 'TARGET_PPC64', - 'TARGET_S390X', - 'TARGET_SH4', -+ 'TARGET_LOONGARCH64', - 'TARGET_SPARC' ] } } - - ## --- -2.43.5 - diff --git a/0007-anolis-target-i386-csv-load-initial-image-to-private.patch b/0007-anolis-target-i386-csv-load-initial-image-to-private.patch deleted file mode 100644 index a40bcfe..0000000 --- a/0007-anolis-target-i386-csv-load-initial-image-to-private.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 2df9c321195bd47485867e1d821913f1f3c21fc2 Mon Sep 17 00:00:00 2001 -From: Xin Jiang -Date: Fri, 25 Aug 2023 14:51:16 +0800 -Subject: [PATCH 7/8] anolis: target/i386: csv: load initial image to private - memory - -The initial image of CSV guest should be loaded into private memory -before guest boot. - -Add APIs to implement the image load. - -Signed-off-by: Xin Jiang -Change-Id: I708e7521bfe079216c0e0aea619a9c6bb1d7af04 ---- - hw/i386/pc_sysfw.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c -index c8b17af953..84aad306dc 100644 ---- a/hw/i386/pc_sysfw.c -+++ b/hw/i386/pc_sysfw.c -@@ -38,6 +38,7 @@ - #include "hw/block/flash.h" - #include "sysemu/kvm.h" - #include "sev.h" -+#include "csv.h" - - #define FLASH_SECTOR_SIZE 4096 - -@@ -208,7 +209,10 @@ static void pc_system_flash_map(PCMachineState *pcms, - exit(1); - } - -- sev_encrypt_flash(flash_ptr, flash_size, &error_fatal); -+ if (csv_enabled()) -+ csv_load_data(flash_mem->addr, flash_ptr, flash_size, &error_fatal); -+ else -+ sev_encrypt_flash(flash_ptr, flash_size, &error_fatal); - } - } - } --- -2.17.1 - diff --git a/0008-Modify-compile-script.patch b/0008-Modify-compile-script.patch deleted file mode 100644 index bcf14cc..0000000 --- a/0008-Modify-compile-script.patch +++ /dev/null @@ -1,36 +0,0 @@ -From c46de76fc41792974d0e1c9896f89ab257cae345 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 22 Aug 2022 08:22:03 -0400 -Subject: [PATCH 08/28] Modify compile script. - -Change-Id: I8573477d64f5974092001869d7aa9bb093f347e8 -Signed-off-by: lixianglai ---- - meson.build | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/meson.build b/meson.build -index fc2dc58f3..c0fb5788f 100644 ---- a/meson.build -+++ b/meson.build -@@ -56,7 +56,7 @@ python = import('python').find_installation() - - supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] - supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64', -- 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64'] -+ 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64', 'loongarch64'] - - cpu = host_machine.cpu_family() - -@@ -77,6 +77,8 @@ elif cpu in ['ppc', 'ppc64'] - kvm_targets = ['ppc-softmmu', 'ppc64-softmmu'] - elif cpu in ['mips', 'mips64'] - kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu'] -+elif cpu == 'loongarch64' -+ kvm_targets = ['loongarch64-softmmu'] - else - kvm_targets = [] - endif --- -2.43.5 - diff --git a/0008-anolis-vga-force-full-update-for-CSV-guest.patch b/0008-anolis-vga-force-full-update-for-CSV-guest.patch deleted file mode 100644 index 40842ec..0000000 --- a/0008-anolis-vga-force-full-update-for-CSV-guest.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 42d8658a8868721a0c4fb08295a8957e9fdc96c6 Mon Sep 17 00:00:00 2001 -From: Xin Jiang -Date: Thu, 13 Jul 2023 09:35:10 +0800 -Subject: [PATCH 8/8] anolis: vga: force full update for CSV guest - -As CSV's NPT(nested page table) is managed by firmware, VMM is hard -to track the dirty pages of vga buffer. Although VMM could perform -a command to firmware to update read/write attribute of vga buffer -in NPT, it costs more time due to communication between VMM and -firmware. So the simplest method is to fully update vga buffer -always. - -Signed-off-by: Xin Jiang -Change-Id: I51ff00440483011fb9088a75005644beb378f8dd ---- - hw/display/vga.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/hw/display/vga.c b/hw/display/vga.c -index 9d1f66af40..be4282a2f5 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -36,6 +36,9 @@ - #include "migration/vmstate.h" - #include "trace.h" - -+#include "target/i386/sev.h" -+#include "target/i386/csv.h" -+ - //#define DEBUG_VGA_MEM - //#define DEBUG_VGA_REG - -@@ -1779,6 +1782,11 @@ static void vga_update_display(void *opaque) - s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); - full_update = 1; - } -+ -+ /* Force to full update in CSV guest. */ -+ if (csv_enabled()) -+ full_update = 1; -+ - switch(graphic_mode) { - case GMODE_TEXT: - vga_draw_text(s, full_update); --- -2.17.1 - diff --git a/0009-Add-loongarch64-rh-devices.mak.patch b/0009-Add-loongarch64-rh-devices.mak.patch deleted file mode 100644 index a06c1f0..0000000 --- a/0009-Add-loongarch64-rh-devices.mak.patch +++ /dev/null @@ -1,3227 +0,0 @@ -From 89fb9c8e0ca11e311417981d46768642d1f8e6d2 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Wed, 24 Aug 2022 22:56:29 -0400 -Subject: [PATCH 09/28] Add loongarch64-rh-devices.mak. - -Change-Id: I375face82c0aa68c053254b879267830d6981756 -Signed-off-by: lixianglai ---- - .../loongarch64-rh-devices.mak | 155 ++ - configure | 5 + - meson.build | 2 + - pc-bios/meson.build | 1 + - tcg/loongarch64/tcg-insn-defs.c.inc | 979 +++++++++ - tcg/loongarch64/tcg-target-con-set.h | 31 + - tcg/loongarch64/tcg-target-con-str.h | 28 + - tcg/loongarch64/tcg-target.c.inc | 1744 +++++++++++++++++ - tcg/loongarch64/tcg-target.h | 178 ++ - 9 files changed, 3123 insertions(+) - create mode 100644 configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak - create mode 100644 tcg/loongarch64/tcg-insn-defs.c.inc - create mode 100644 tcg/loongarch64/tcg-target-con-set.h - create mode 100644 tcg/loongarch64/tcg-target-con-str.h - create mode 100644 tcg/loongarch64/tcg-target.c.inc - create mode 100644 tcg/loongarch64/tcg-target.h - -diff --git a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -new file mode 100644 -index 000000000..e7b5bdc8e ---- /dev/null -+++ b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -@@ -0,0 +1,155 @@ -+ -+include ../rh-virtio.mak -+# Default configuration for loongarch-softmmu -+ -+CONFIG_PCI=y -+CONFIG_ACPI_PCI=y -+# For now, CONFIG_IDE_CORE requires ISA, so we enable it here -+CONFIG_ISA_BUS=y -+CONFIG_VIRTIO_PCI=y -+ -+CONFIG_VGA_PCI=y -+CONFIG_ACPI_SMBUS=y -+#CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+CONFIG_VHOST_USER_SCSI=y -+#CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+CONFIG_VHOST_USER_BLK=y -+CONFIG_VIRTIO=y -+CONFIG_VIRTIO_BALLOON=y -+CONFIG_VIRTIO_BLK=y -+CONFIG_VIRTIO_CRYPTO=y -+CONFIG_VIRTIO_GPU=y -+CONFIG_VIRTIO_INPUT=y -+CONFIG_VIRTIO_NET=y -+CONFIG_VIRTIO_RNG=y -+CONFIG_SCSI=y -+CONFIG_VIRTIO_SCSI=y -+CONFIG_VIRTIO_SERIAL=y -+ -+CONFIG_USB_UHCI=y -+CONFIG_USB_OHCI=y -+CONFIG_USB_OHCI_PCI=y -+CONFIG_USB_XHCI=y -+CONFIG_USB_XHCI_NEC=y -+CONFIG_NE2000_PCI=y -+CONFIG_EEPRO100_PCI=y -+CONFIG_PCNET_PCI=y -+CONFIG_PCNET_COMMON=y -+CONFIG_AC97=y -+CONFIG_HDA=y -+CONFIG_ES1370=y -+CONFIG_SCSI=y -+CONFIG_LSI_SCSI_PCI=y -+CONFIG_VMW_PVSCSI_SCSI_PCI=y -+CONFIG_MEGASAS_SCSI_PCI=y -+CONFIG_MPTSAS_SCSI_PCI=y -+CONFIG_RTL8139_PCI=y -+CONFIG_E1000_PCI=y -+CONFIG_IDE_CORE=y -+CONFIG_IDE_QDEV=y -+CONFIG_IDE_PCI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_ICH9=y -+CONFIG_ESP=y -+CONFIG_ESP_PCI=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_SERIAL_PCI=y -+CONFIG_CAN_BUS=y -+CONFIG_CAN_SJA1000=y -+CONFIG_CAN_PCI=y -+CONFIG_USB_UHCI=y -+CONFIG_USB_OHCI=y -+CONFIG_USB_XHCI=y -+CONFIG_USB_XHCI_NEC=y -+CONFIG_NE2000_PCI=y -+CONFIG_EEPRO100_PCI=y -+CONFIG_PCNET_PCI=y -+CONFIG_PCNET_COMMON=y -+CONFIG_AC97=y -+CONFIG_HDA=y -+CONFIG_ES1370=y -+CONFIG_SCSI=y -+CONFIG_LSI_SCSI_PCI=y -+CONFIG_VMW_PVSCSI_SCSI_PCI=y -+CONFIG_MEGASAS_SCSI_PCI=y -+CONFIG_MPTSAS_SCSI_PCI=y -+CONFIG_RTL8139_PCI=y -+CONFIG_E1000_PCI=y -+CONFIG_IDE_CORE=y -+CONFIG_IDE_QDEV=y -+CONFIG_IDE_PCI=y -+CONFIG_AHCI=y -+CONFIG_ESP=y -+CONFIG_ESP_PCI=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_SERIAL_PCI=y -+CONFIG_CAN_BUS=y -+CONFIG_CAN_SJA1000=y -+CONFIG_CAN_PCI=y -+ -+CONFIG_SPICE=y -+CONFIG_QXL=y -+CONFIG_ESP=y -+CONFIG_SCSI=y -+CONFIG_VGA_ISA=y -+CONFIG_VGA_ISA_MM=y -+CONFIG_VGA_CIRRUS=y -+CONFIG_VMWARE_VGA=y -+CONFIG_VIRTIO_VGA=y -+CONFIG_SERIAL_ISA=y -+CONFIG_PARALLEL=y -+CONFIG_I8254=y -+CONFIG_PCSPK=y -+CONFIG_PCKBD=y -+CONFIG_FDC=y -+CONFIG_ACPI=y -+CONFIG_ACPI_MEMORY_HOTPLUG=y -+CONFIG_ACPI_NVDIMM=y -+CONFIG_ACPI_CPU_HOTPLUG=y -+CONFIG_APM=y -+CONFIG_I8257=y -+CONFIG_PIIX4=y -+CONFIG_IDE_ISA=y -+CONFIG_IDE_PIIX=y -+#CONFIG_NE2000_ISA=y -+CONFIG_MIPSNET=y -+CONFIG_PFLASH_CFI01=y -+CONFIG_I8259=y -+CONFIG_MC146818RTC=y -+CONFIG_ISA_TESTDEV=y -+CONFIG_EMPTY_SLOT=y -+CONFIG_I2C=y -+CONFIG_DIMM=y -+CONFIG_MEM_DEVICE=y -+ -+# Arch Specified CONFIG defines -+CONFIG_IDE_VIA=y -+CONFIG_VT82C686=y -+CONFIG_RC4030=y -+CONFIG_DP8393X=y -+CONFIG_DS1225Y=y -+CONFIG_FITLOADER=y -+CONFIG_SMBIOS=y -+ -+CONFIG_PCIE_PORT=y -+CONFIG_I82801B11=y -+CONFIG_XIO3130=y -+CONFIG_PCI_EXPRESS=y -+CONFIG_MSI_NONBROKEN=y -+CONFIG_IOH3420=y -+CONFIG_SD=y -+CONFIG_SDHCI=y -+CONFIG_VIRTFS=y -+CONFIG_VIRTIO_9P=y -+CONFIG_USB_EHCI=y -+CONFIG_USB_EHCI_PCI=y -+CONFIG_USB_EHCI_SYSBUS=y -+CONFIG_USB_STORAGE_BOT=y -+CONFIG_TPM_EMULATOR=y -+CONFIG_TPM_TIS=y -+CONFIG_PLATFORM_BUS=y -+CONFIG_TPM_TIS_SYSBUS=y -+CONFIG_ACPI_LOONGARCH=y -+CONFIG_LS7A_RTC=y -diff --git a/configure b/configure -index 48c21775f..1f932f7ee 100755 ---- a/configure -+++ b/configure -@@ -581,6 +581,8 @@ elif check_define __arm__ ; then - cpu="arm" - elif check_define __aarch64__ ; then - cpu="aarch64" -+elif check_define __loongarch__ ; then -+ cpu="loongarch64" - else - cpu=$(uname -m) - fi -@@ -606,6 +608,9 @@ case "$cpu" in - aarch64) - cpu="aarch64" - ;; -+ loongarch64) -+ cpu="loongarch64" -+ ;; - mips*) - cpu="mips" - ;; -diff --git a/meson.build b/meson.build -index c0fb5788f..c5fdb7856 100644 ---- a/meson.build -+++ b/meson.build -@@ -361,6 +361,8 @@ if not get_option('tcg').disabled() - tcg_arch = 'i386' - elif config_host['ARCH'] == 'ppc64' - tcg_arch = 'ppc' -+ elif config_host['ARCH'] == 'loongarch64' -+ tcg_arch = 'loongarch64' - endif - add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch, - language: ['c', 'cpp', 'objc']) -diff --git a/pc-bios/meson.build b/pc-bios/meson.build -index a09ca4d03..60009bd89 100644 ---- a/pc-bios/meson.build -+++ b/pc-bios/meson.build -@@ -84,6 +84,7 @@ blobs = files( - 'opensbi-riscv64-generic-fw_dynamic.elf', - 'npcm7xx_bootrom.bin', - 'loongarch_bios.bin', -+ 'loongarch_vars.bin', - ) - - if get_option('install_blobs') -diff --git a/tcg/loongarch64/tcg-insn-defs.c.inc b/tcg/loongarch64/tcg-insn-defs.c.inc -new file mode 100644 -index 000000000..d16257185 ---- /dev/null -+++ b/tcg/loongarch64/tcg-insn-defs.c.inc -@@ -0,0 +1,979 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * LoongArch instruction formats, opcodes, and encoders for TCG use. -+ * -+ * This file is auto-generated by genqemutcgdefs from -+ * https://github.com/loongson-community/loongarch-opcodes, -+ * from commit 961f0c60f5b63e574d785995600c71ad5413fdc4. -+ * DO NOT EDIT. -+ */ -+ -+typedef enum { -+ OPC_CLZ_W = 0x00001400, -+ OPC_CTZ_W = 0x00001c00, -+ OPC_CLZ_D = 0x00002400, -+ OPC_CTZ_D = 0x00002c00, -+ OPC_REVB_2H = 0x00003000, -+ OPC_REVB_2W = 0x00003800, -+ OPC_REVB_D = 0x00003c00, -+ OPC_SEXT_H = 0x00005800, -+ OPC_SEXT_B = 0x00005c00, -+ OPC_ADD_W = 0x00100000, -+ OPC_ADD_D = 0x00108000, -+ OPC_SUB_W = 0x00110000, -+ OPC_SUB_D = 0x00118000, -+ OPC_SLT = 0x00120000, -+ OPC_SLTU = 0x00128000, -+ OPC_MASKEQZ = 0x00130000, -+ OPC_MASKNEZ = 0x00138000, -+ OPC_NOR = 0x00140000, -+ OPC_AND = 0x00148000, -+ OPC_OR = 0x00150000, -+ OPC_XOR = 0x00158000, -+ OPC_ORN = 0x00160000, -+ OPC_ANDN = 0x00168000, -+ OPC_SLL_W = 0x00170000, -+ OPC_SRL_W = 0x00178000, -+ OPC_SRA_W = 0x00180000, -+ OPC_SLL_D = 0x00188000, -+ OPC_SRL_D = 0x00190000, -+ OPC_SRA_D = 0x00198000, -+ OPC_ROTR_W = 0x001b0000, -+ OPC_ROTR_D = 0x001b8000, -+ OPC_MUL_W = 0x001c0000, -+ OPC_MULH_W = 0x001c8000, -+ OPC_MULH_WU = 0x001d0000, -+ OPC_MUL_D = 0x001d8000, -+ OPC_MULH_D = 0x001e0000, -+ OPC_MULH_DU = 0x001e8000, -+ OPC_DIV_W = 0x00200000, -+ OPC_MOD_W = 0x00208000, -+ OPC_DIV_WU = 0x00210000, -+ OPC_MOD_WU = 0x00218000, -+ OPC_DIV_D = 0x00220000, -+ OPC_MOD_D = 0x00228000, -+ OPC_DIV_DU = 0x00230000, -+ OPC_MOD_DU = 0x00238000, -+ OPC_SLLI_W = 0x00408000, -+ OPC_SLLI_D = 0x00410000, -+ OPC_SRLI_W = 0x00448000, -+ OPC_SRLI_D = 0x00450000, -+ OPC_SRAI_W = 0x00488000, -+ OPC_SRAI_D = 0x00490000, -+ OPC_ROTRI_W = 0x004c8000, -+ OPC_ROTRI_D = 0x004d0000, -+ OPC_BSTRINS_W = 0x00600000, -+ OPC_BSTRPICK_W = 0x00608000, -+ OPC_BSTRINS_D = 0x00800000, -+ OPC_BSTRPICK_D = 0x00c00000, -+ OPC_SLTI = 0x02000000, -+ OPC_SLTUI = 0x02400000, -+ OPC_ADDI_W = 0x02800000, -+ OPC_ADDI_D = 0x02c00000, -+ OPC_CU52I_D = 0x03000000, -+ OPC_ANDI = 0x03400000, -+ OPC_ORI = 0x03800000, -+ OPC_XORI = 0x03c00000, -+ OPC_LU12I_W = 0x14000000, -+ OPC_CU32I_D = 0x16000000, -+ OPC_PCADDU2I = 0x18000000, -+ OPC_PCALAU12I = 0x1a000000, -+ OPC_PCADDU12I = 0x1c000000, -+ OPC_PCADDU18I = 0x1e000000, -+ OPC_LD_B = 0x28000000, -+ OPC_LD_H = 0x28400000, -+ OPC_LD_W = 0x28800000, -+ OPC_LD_D = 0x28c00000, -+ OPC_ST_B = 0x29000000, -+ OPC_ST_H = 0x29400000, -+ OPC_ST_W = 0x29800000, -+ OPC_ST_D = 0x29c00000, -+ OPC_LD_BU = 0x2a000000, -+ OPC_LD_HU = 0x2a400000, -+ OPC_LD_WU = 0x2a800000, -+ OPC_LDX_B = 0x38000000, -+ OPC_LDX_H = 0x38040000, -+ OPC_LDX_W = 0x38080000, -+ OPC_LDX_D = 0x380c0000, -+ OPC_STX_B = 0x38100000, -+ OPC_STX_H = 0x38140000, -+ OPC_STX_W = 0x38180000, -+ OPC_STX_D = 0x381c0000, -+ OPC_LDX_BU = 0x38200000, -+ OPC_LDX_HU = 0x38240000, -+ OPC_LDX_WU = 0x38280000, -+ OPC_DBAR = 0x38720000, -+ OPC_JIRL = 0x4c000000, -+ OPC_B = 0x50000000, -+ OPC_BL = 0x54000000, -+ OPC_BEQ = 0x58000000, -+ OPC_BNE = 0x5c000000, -+ OPC_BGT = 0x60000000, -+ OPC_BLE = 0x64000000, -+ OPC_BGTU = 0x68000000, -+ OPC_BLEU = 0x6c000000, -+} LoongArchInsn; -+ -+static int32_t __attribute__((unused)) -+encode_d_slot(LoongArchInsn opc, uint32_t d) -+{ -+ return opc | d; -+} -+ -+static int32_t __attribute__((unused)) -+encode_dj_slots(LoongArchInsn opc, uint32_t d, uint32_t j) -+{ -+ return opc | d | j << 5; -+} -+ -+static int32_t __attribute__((unused)) -+encode_djk_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k) -+{ -+ return opc | d | j << 5 | k << 10; -+} -+ -+static int32_t __attribute__((unused)) -+encode_djkm_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k, -+ uint32_t m) -+{ -+ return opc | d | j << 5 | k << 10 | m << 16; -+} -+ -+static int32_t __attribute__((unused)) -+encode_dk_slots(LoongArchInsn opc, uint32_t d, uint32_t k) -+{ -+ return opc | d | k << 10; -+} -+ -+static int32_t __attribute__((unused)) -+encode_dj_insn(LoongArchInsn opc, TCGReg d, TCGReg j) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ return encode_dj_slots(opc, d, j); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djk_insn(LoongArchInsn opc, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(k >= 0 && k <= 0x1f); -+ return encode_djk_slots(opc, d, j, k); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djsk12_insn(LoongArchInsn opc, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(sk12 >= -0x800 && sk12 <= 0x7ff); -+ return encode_djk_slots(opc, d, j, sk12 & 0xfff); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djsk16_insn(LoongArchInsn opc, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(sk16 >= -0x8000 && sk16 <= 0x7fff); -+ return encode_djk_slots(opc, d, j, sk16 & 0xffff); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk12_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk12) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk12 <= 0xfff); -+ return encode_djk_slots(opc, d, j, uk12); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk5_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk5 <= 0x1f); -+ return encode_djk_slots(opc, d, j, uk5); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk5um5_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk5, -+ uint32_t um5) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk5 <= 0x1f); -+ tcg_debug_assert(um5 <= 0x1f); -+ return encode_djkm_slots(opc, d, j, uk5, um5); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk6_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk6 <= 0x3f); -+ return encode_djk_slots(opc, d, j, uk6); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk6um6_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk6, -+ uint32_t um6) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk6 <= 0x3f); -+ tcg_debug_assert(um6 <= 0x3f); -+ return encode_djkm_slots(opc, d, j, uk6, um6); -+} -+ -+static int32_t __attribute__((unused)) -+encode_dsj20_insn(LoongArchInsn opc, TCGReg d, int32_t sj20) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(sj20 >= -0x80000 && sj20 <= 0x7ffff); -+ return encode_dj_slots(opc, d, sj20 & 0xfffff); -+} -+ -+static int32_t __attribute__((unused)) -+encode_sd10k16_insn(LoongArchInsn opc, int32_t sd10k16) -+{ -+ tcg_debug_assert(sd10k16 >= -0x2000000 && sd10k16 <= 0x1ffffff); -+ return encode_dk_slots(opc, (sd10k16 >> 16) & 0x3ff, sd10k16 & 0xffff); -+} -+ -+static int32_t __attribute__((unused)) -+encode_ud15_insn(LoongArchInsn opc, uint32_t ud15) -+{ -+ tcg_debug_assert(ud15 <= 0x7fff); -+ return encode_d_slot(opc, ud15); -+} -+ -+/* Emits the `clz.w d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_clz_w(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_CLZ_W, d, j)); -+} -+ -+/* Emits the `ctz.w d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ctz_w(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_CTZ_W, d, j)); -+} -+ -+/* Emits the `clz.d d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_clz_d(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_CLZ_D, d, j)); -+} -+ -+/* Emits the `ctz.d d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ctz_d(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_CTZ_D, d, j)); -+} -+ -+/* Emits the `revb.2h d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_revb_2h(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_REVB_2H, d, j)); -+} -+ -+/* Emits the `revb.2w d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_revb_2w(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_REVB_2W, d, j)); -+} -+ -+/* Emits the `revb.d d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_revb_d(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_REVB_D, d, j)); -+} -+ -+/* Emits the `sext.h d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sext_h(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_SEXT_H, d, j)); -+} -+ -+/* Emits the `sext.b d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sext_b(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_SEXT_B, d, j)); -+} -+ -+/* Emits the `add.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_add_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ADD_W, d, j, k)); -+} -+ -+/* Emits the `add.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_add_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ADD_D, d, j, k)); -+} -+ -+/* Emits the `sub.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sub_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SUB_W, d, j, k)); -+} -+ -+/* Emits the `sub.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sub_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SUB_D, d, j, k)); -+} -+ -+/* Emits the `slt d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_slt(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SLT, d, j, k)); -+} -+ -+/* Emits the `sltu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sltu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SLTU, d, j, k)); -+} -+ -+/* Emits the `maskeqz d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_maskeqz(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MASKEQZ, d, j, k)); -+} -+ -+/* Emits the `masknez d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_masknez(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MASKNEZ, d, j, k)); -+} -+ -+/* Emits the `nor d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_nor(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_NOR, d, j, k)); -+} -+ -+/* Emits the `and d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_and(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_AND, d, j, k)); -+} -+ -+/* Emits the `or d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_or(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_OR, d, j, k)); -+} -+ -+/* Emits the `xor d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_xor(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_XOR, d, j, k)); -+} -+ -+/* Emits the `orn d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_orn(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ORN, d, j, k)); -+} -+ -+/* Emits the `andn d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_andn(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ANDN, d, j, k)); -+} -+ -+/* Emits the `sll.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sll_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SLL_W, d, j, k)); -+} -+ -+/* Emits the `srl.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srl_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SRL_W, d, j, k)); -+} -+ -+/* Emits the `sra.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sra_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SRA_W, d, j, k)); -+} -+ -+/* Emits the `sll.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sll_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SLL_D, d, j, k)); -+} -+ -+/* Emits the `srl.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srl_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SRL_D, d, j, k)); -+} -+ -+/* Emits the `sra.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sra_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SRA_D, d, j, k)); -+} -+ -+/* Emits the `rotr.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_rotr_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ROTR_W, d, j, k)); -+} -+ -+/* Emits the `rotr.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_rotr_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ROTR_D, d, j, k)); -+} -+ -+/* Emits the `mul.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mul_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MUL_W, d, j, k)); -+} -+ -+/* Emits the `mulh.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mulh_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MULH_W, d, j, k)); -+} -+ -+/* Emits the `mulh.wu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mulh_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MULH_WU, d, j, k)); -+} -+ -+/* Emits the `mul.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mul_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MUL_D, d, j, k)); -+} -+ -+/* Emits the `mulh.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mulh_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MULH_D, d, j, k)); -+} -+ -+/* Emits the `mulh.du d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mulh_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MULH_DU, d, j, k)); -+} -+ -+/* Emits the `div.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_div_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_DIV_W, d, j, k)); -+} -+ -+/* Emits the `mod.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mod_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MOD_W, d, j, k)); -+} -+ -+/* Emits the `div.wu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_div_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_DIV_WU, d, j, k)); -+} -+ -+/* Emits the `mod.wu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mod_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MOD_WU, d, j, k)); -+} -+ -+/* Emits the `div.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_div_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_DIV_D, d, j, k)); -+} -+ -+/* Emits the `mod.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mod_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MOD_D, d, j, k)); -+} -+ -+/* Emits the `div.du d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_div_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_DIV_DU, d, j, k)); -+} -+ -+/* Emits the `mod.du d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mod_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MOD_DU, d, j, k)); -+} -+ -+/* Emits the `slli.w d, j, uk5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_slli_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_out32(s, encode_djuk5_insn(OPC_SLLI_W, d, j, uk5)); -+} -+ -+/* Emits the `slli.d d, j, uk6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_slli_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_out32(s, encode_djuk6_insn(OPC_SLLI_D, d, j, uk6)); -+} -+ -+/* Emits the `srli.w d, j, uk5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srli_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_out32(s, encode_djuk5_insn(OPC_SRLI_W, d, j, uk5)); -+} -+ -+/* Emits the `srli.d d, j, uk6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srli_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_out32(s, encode_djuk6_insn(OPC_SRLI_D, d, j, uk6)); -+} -+ -+/* Emits the `srai.w d, j, uk5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srai_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_out32(s, encode_djuk5_insn(OPC_SRAI_W, d, j, uk5)); -+} -+ -+/* Emits the `srai.d d, j, uk6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srai_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_out32(s, encode_djuk6_insn(OPC_SRAI_D, d, j, uk6)); -+} -+ -+/* Emits the `rotri.w d, j, uk5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_rotri_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_out32(s, encode_djuk5_insn(OPC_ROTRI_W, d, j, uk5)); -+} -+ -+/* Emits the `rotri.d d, j, uk6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_rotri_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_out32(s, encode_djuk6_insn(OPC_ROTRI_D, d, j, uk6)); -+} -+ -+/* Emits the `bstrins.w d, j, uk5, um5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bstrins_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5, -+ uint32_t um5) -+{ -+ tcg_out32(s, encode_djuk5um5_insn(OPC_BSTRINS_W, d, j, uk5, um5)); -+} -+ -+/* Emits the `bstrpick.w d, j, uk5, um5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bstrpick_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5, -+ uint32_t um5) -+{ -+ tcg_out32(s, encode_djuk5um5_insn(OPC_BSTRPICK_W, d, j, uk5, um5)); -+} -+ -+/* Emits the `bstrins.d d, j, uk6, um6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bstrins_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6, -+ uint32_t um6) -+{ -+ tcg_out32(s, encode_djuk6um6_insn(OPC_BSTRINS_D, d, j, uk6, um6)); -+} -+ -+/* Emits the `bstrpick.d d, j, uk6, um6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bstrpick_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6, -+ uint32_t um6) -+{ -+ tcg_out32(s, encode_djuk6um6_insn(OPC_BSTRPICK_D, d, j, uk6, um6)); -+} -+ -+/* Emits the `slti d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_slti(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_SLTI, d, j, sk12)); -+} -+ -+/* Emits the `sltui d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sltui(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_SLTUI, d, j, sk12)); -+} -+ -+/* Emits the `addi.w d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_addi_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ADDI_W, d, j, sk12)); -+} -+ -+/* Emits the `addi.d d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_addi_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ADDI_D, d, j, sk12)); -+} -+ -+/* Emits the `cu52i.d d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_cu52i_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_CU52I_D, d, j, sk12)); -+} -+ -+/* Emits the `andi d, j, uk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_andi(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) -+{ -+ tcg_out32(s, encode_djuk12_insn(OPC_ANDI, d, j, uk12)); -+} -+ -+/* Emits the `ori d, j, uk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ori(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) -+{ -+ tcg_out32(s, encode_djuk12_insn(OPC_ORI, d, j, uk12)); -+} -+ -+/* Emits the `xori d, j, uk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_xori(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) -+{ -+ tcg_out32(s, encode_djuk12_insn(OPC_XORI, d, j, uk12)); -+} -+ -+/* Emits the `lu12i.w d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_lu12i_w(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_LU12I_W, d, sj20)); -+} -+ -+/* Emits the `cu32i.d d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_cu32i_d(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_CU32I_D, d, sj20)); -+} -+ -+/* Emits the `pcaddu2i d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_pcaddu2i(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_PCADDU2I, d, sj20)); -+} -+ -+/* Emits the `pcalau12i d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_pcalau12i(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_PCALAU12I, d, sj20)); -+} -+ -+/* Emits the `pcaddu12i d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_pcaddu12i(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_PCADDU12I, d, sj20)); -+} -+ -+/* Emits the `pcaddu18i d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_pcaddu18i(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_PCADDU18I, d, sj20)); -+} -+ -+/* Emits the `ld.b d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_b(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_B, d, j, sk12)); -+} -+ -+/* Emits the `ld.h d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_h(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_H, d, j, sk12)); -+} -+ -+/* Emits the `ld.w d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_W, d, j, sk12)); -+} -+ -+/* Emits the `ld.d d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_D, d, j, sk12)); -+} -+ -+/* Emits the `st.b d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_st_b(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ST_B, d, j, sk12)); -+} -+ -+/* Emits the `st.h d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_st_h(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ST_H, d, j, sk12)); -+} -+ -+/* Emits the `st.w d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_st_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ST_W, d, j, sk12)); -+} -+ -+/* Emits the `st.d d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_st_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ST_D, d, j, sk12)); -+} -+ -+/* Emits the `ld.bu d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_bu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_BU, d, j, sk12)); -+} -+ -+/* Emits the `ld.hu d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_hu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_HU, d, j, sk12)); -+} -+ -+/* Emits the `ld.wu d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_wu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_WU, d, j, sk12)); -+} -+ -+/* Emits the `ldx.b d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_b(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_B, d, j, k)); -+} -+ -+/* Emits the `ldx.h d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_h(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_H, d, j, k)); -+} -+ -+/* Emits the `ldx.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_W, d, j, k)); -+} -+ -+/* Emits the `ldx.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_D, d, j, k)); -+} -+ -+/* Emits the `stx.b d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_stx_b(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_STX_B, d, j, k)); -+} -+ -+/* Emits the `stx.h d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_stx_h(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_STX_H, d, j, k)); -+} -+ -+/* Emits the `stx.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_stx_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_STX_W, d, j, k)); -+} -+ -+/* Emits the `stx.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_stx_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_STX_D, d, j, k)); -+} -+ -+/* Emits the `ldx.bu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_bu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_BU, d, j, k)); -+} -+ -+/* Emits the `ldx.hu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_hu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_HU, d, j, k)); -+} -+ -+/* Emits the `ldx.wu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_WU, d, j, k)); -+} -+ -+/* Emits the `dbar ud15` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_dbar(TCGContext *s, uint32_t ud15) -+{ -+ tcg_out32(s, encode_ud15_insn(OPC_DBAR, ud15)); -+} -+ -+/* Emits the `jirl d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_jirl(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_JIRL, d, j, sk16)); -+} -+ -+/* Emits the `b sd10k16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_b(TCGContext *s, int32_t sd10k16) -+{ -+ tcg_out32(s, encode_sd10k16_insn(OPC_B, sd10k16)); -+} -+ -+/* Emits the `bl sd10k16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bl(TCGContext *s, int32_t sd10k16) -+{ -+ tcg_out32(s, encode_sd10k16_insn(OPC_BL, sd10k16)); -+} -+ -+/* Emits the `beq d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_beq(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BEQ, d, j, sk16)); -+} -+ -+/* Emits the `bne d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bne(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BNE, d, j, sk16)); -+} -+ -+/* Emits the `bgt d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bgt(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BGT, d, j, sk16)); -+} -+ -+/* Emits the `ble d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ble(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BLE, d, j, sk16)); -+} -+ -+/* Emits the `bgtu d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bgtu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BGTU, d, j, sk16)); -+} -+ -+/* Emits the `bleu d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bleu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BLEU, d, j, sk16)); -+} -+ -+/* End of generated code. */ -diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h -new file mode 100644 -index 000000000..349c67268 ---- /dev/null -+++ b/tcg/loongarch64/tcg-target-con-set.h -@@ -0,0 +1,31 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * Define LoongArch target-specific constraint sets. -+ * -+ * Copyright (c) 2021 WANG Xuerui -+ * -+ * Based on tcg/riscv/tcg-target-con-set.h -+ * -+ * Copyright (c) 2021 Linaro -+ */ -+ -+/* -+ * C_On_Im(...) defines a constraint set with outputs and inputs. -+ * Each operand should be a sequence of constraint letters as defined by -+ * tcg-target-con-str.h; the constraint combination is inclusive or. -+ */ -+C_O0_I1(r) -+C_O0_I2(rZ, r) -+C_O0_I2(rZ, rZ) -+C_O0_I2(LZ, L) -+C_O1_I1(r, r) -+C_O1_I1(r, L) -+C_O1_I2(r, r, rC) -+C_O1_I2(r, r, ri) -+C_O1_I2(r, r, rI) -+C_O1_I2(r, r, rU) -+C_O1_I2(r, r, rW) -+C_O1_I2(r, r, rZ) -+C_O1_I2(r, 0, rZ) -+C_O1_I2(r, rZ, rN) -+C_O1_I2(r, rZ, rZ) -diff --git a/tcg/loongarch64/tcg-target-con-str.h b/tcg/loongarch64/tcg-target-con-str.h -new file mode 100644 -index 000000000..c3986a4fd ---- /dev/null -+++ b/tcg/loongarch64/tcg-target-con-str.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * Define LoongArch target-specific operand constraints. -+ * -+ * Copyright (c) 2021 WANG Xuerui -+ * -+ * Based on tcg/riscv/tcg-target-con-str.h -+ * -+ * Copyright (c) 2021 Linaro -+ */ -+ -+/* -+ * Define constraint letters for register sets: -+ * REGS(letter, register_mask) -+ */ -+REGS('r', ALL_GENERAL_REGS) -+REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) -+ -+/* -+ * Define constraint letters for constants: -+ * CONST(letter, TCG_CT_CONST_* bit set) -+ */ -+CONST('I', TCG_CT_CONST_S12) -+CONST('N', TCG_CT_CONST_N12) -+CONST('U', TCG_CT_CONST_U12) -+CONST('Z', TCG_CT_CONST_ZERO) -+CONST('C', TCG_CT_CONST_C12) -+CONST('W', TCG_CT_CONST_WSZ) -diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc -new file mode 100644 -index 000000000..9b53549ed ---- /dev/null -+++ b/tcg/loongarch64/tcg-target.c.inc -@@ -0,0 +1,1744 @@ -+/* -+ * Tiny Code Generator for QEMU -+ * -+ * Copyright (c) 2021 WANG Xuerui -+ * -+ * Based on tcg/riscv/tcg-target.c.inc -+ * -+ * Copyright (c) 2018 SiFive, Inc -+ * Copyright (c) 2008-2009 Arnaud Patard -+ * Copyright (c) 2009 Aurelien Jarno -+ * Copyright (c) 2008 Fabrice Bellard -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "../tcg-ldst.c.inc" -+ -+#ifdef CONFIG_DEBUG_TCG -+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { -+ "zero", -+ "ra", -+ "tp", -+ "sp", -+ "a0", -+ "a1", -+ "a2", -+ "a3", -+ "a4", -+ "a5", -+ "a6", -+ "a7", -+ "t0", -+ "t1", -+ "t2", -+ "t3", -+ "t4", -+ "t5", -+ "t6", -+ "t7", -+ "t8", -+ "r21", /* reserved in the LP64* ABI, hence no ABI name */ -+ "s9", -+ "s0", -+ "s1", -+ "s2", -+ "s3", -+ "s4", -+ "s5", -+ "s6", -+ "s7", -+ "s8" -+}; -+#endif -+ -+static const int tcg_target_reg_alloc_order[] = { -+ /* Registers preserved across calls */ -+ /* TCG_REG_S0 reserved for TCG_AREG0 */ -+ TCG_REG_S1, -+ TCG_REG_S2, -+ TCG_REG_S3, -+ TCG_REG_S4, -+ TCG_REG_S5, -+ TCG_REG_S6, -+ TCG_REG_S7, -+ TCG_REG_S8, -+ TCG_REG_S9, -+ -+ /* Registers (potentially) clobbered across calls */ -+ TCG_REG_T0, -+ TCG_REG_T1, -+ TCG_REG_T2, -+ TCG_REG_T3, -+ TCG_REG_T4, -+ TCG_REG_T5, -+ TCG_REG_T6, -+ TCG_REG_T7, -+ TCG_REG_T8, -+ -+ /* Argument registers, opposite order of allocation. */ -+ TCG_REG_A7, -+ TCG_REG_A6, -+ TCG_REG_A5, -+ TCG_REG_A4, -+ TCG_REG_A3, -+ TCG_REG_A2, -+ TCG_REG_A1, -+ TCG_REG_A0, -+}; -+ -+static const int tcg_target_call_iarg_regs[] = { -+ TCG_REG_A0, -+ TCG_REG_A1, -+ TCG_REG_A2, -+ TCG_REG_A3, -+ TCG_REG_A4, -+ TCG_REG_A5, -+ TCG_REG_A6, -+ TCG_REG_A7, -+}; -+ -+static const int tcg_target_call_oarg_regs[] = { -+ TCG_REG_A0, -+ TCG_REG_A1, -+}; -+ -+#ifndef CONFIG_SOFTMMU -+#define USE_GUEST_BASE (guest_base != 0) -+#define TCG_GUEST_BASE_REG TCG_REG_S1 -+#endif -+ -+#define TCG_CT_CONST_ZERO 0x100 -+#define TCG_CT_CONST_S12 0x200 -+#define TCG_CT_CONST_N12 0x400 -+#define TCG_CT_CONST_U12 0x800 -+#define TCG_CT_CONST_C12 0x1000 -+#define TCG_CT_CONST_WSZ 0x2000 -+ -+#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32) -+/* -+ * For softmmu, we need to avoid conflicts with the first 5 -+ * argument registers to call the helper. Some of these are -+ * also used for the tlb lookup. -+ */ -+#ifdef CONFIG_SOFTMMU -+#define SOFTMMU_RESERVE_REGS MAKE_64BIT_MASK(TCG_REG_A0, 5) -+#else -+#define SOFTMMU_RESERVE_REGS 0 -+#endif -+ -+ -+static inline tcg_target_long sextreg(tcg_target_long val, int pos, int len) -+{ -+ return sextract64(val, pos, len); -+} -+ -+/* test if a constant matches the constraint */ -+static bool tcg_target_const_match(int64_t val, TCGType type, int ct) -+{ -+ if (ct & TCG_CT_CONST) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_ZERO) && val == 0) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_S12) && val == sextreg(val, 0, 12)) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_N12) && -val == sextreg(-val, 0, 12)) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_U12) && val >= 0 && val <= 0xfff) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_C12) && ~val >= 0 && ~val <= 0xfff) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_WSZ) && val == (type == TCG_TYPE_I32 ? 32 : 64)) { -+ return true; -+ } -+ return false; -+} -+ -+/* -+ * Relocations -+ */ -+ -+/* -+ * Relocation records defined in LoongArch ELF psABI v1.00 is way too -+ * complicated; a whopping stack machine is needed to stuff the fields, at -+ * the very least one SOP_PUSH and one SOP_POP (of the correct format) are -+ * needed. -+ * -+ * Hence, define our own simpler relocation types. Numbers are chosen as to -+ * not collide with potential future additions to the true ELF relocation -+ * type enum. -+ */ -+ -+/* Field Sk16, shifted right by 2; suitable for conditional jumps */ -+#define R_LOONGARCH_BR_SK16 256 -+/* Field Sd10k16, shifted right by 2; suitable for B and BL */ -+#define R_LOONGARCH_BR_SD10K16 257 -+ -+static bool reloc_br_sk16(tcg_insn_unit *src_rw, const tcg_insn_unit *target) -+{ -+ const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); -+ intptr_t offset = (intptr_t)target - (intptr_t)src_rx; -+ -+ tcg_debug_assert((offset & 3) == 0); -+ offset >>= 2; -+ if (offset == sextreg(offset, 0, 16)) { -+ *src_rw = deposit64(*src_rw, 10, 16, offset); -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool reloc_br_sd10k16(tcg_insn_unit *src_rw, -+ const tcg_insn_unit *target) -+{ -+ const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); -+ intptr_t offset = (intptr_t)target - (intptr_t)src_rx; -+ -+ tcg_debug_assert((offset & 3) == 0); -+ offset >>= 2; -+ if (offset == sextreg(offset, 0, 26)) { -+ *src_rw = deposit64(*src_rw, 0, 10, offset >> 16); /* slot d10 */ -+ *src_rw = deposit64(*src_rw, 10, 16, offset); /* slot k16 */ -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool patch_reloc(tcg_insn_unit *code_ptr, int type, -+ intptr_t value, intptr_t addend) -+{ -+ tcg_debug_assert(addend == 0); -+ switch (type) { -+ case R_LOONGARCH_BR_SK16: -+ return reloc_br_sk16(code_ptr, (tcg_insn_unit *)value); -+ case R_LOONGARCH_BR_SD10K16: -+ return reloc_br_sd10k16(code_ptr, (tcg_insn_unit *)value); -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+#include "tcg-insn-defs.c.inc" -+ -+/* -+ * TCG intrinsics -+ */ -+ -+static void tcg_out_mb(TCGContext *s, TCGArg a0) -+{ -+ /* Baseline LoongArch only has the full barrier, unfortunately. */ -+ tcg_out_opc_dbar(s, 0); -+} -+ -+static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) -+{ -+ if (ret == arg) { -+ return true; -+ } -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ /* -+ * Conventional register-register move used in LoongArch is -+ * `or dst, src, zero`. -+ */ -+ tcg_out_opc_or(s, ret, arg, TCG_REG_ZERO); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ return true; -+} -+ -+static bool imm_part_needs_loading(bool high_bits_are_ones, -+ tcg_target_long part) -+{ -+ if (high_bits_are_ones) { -+ return part != -1; -+ } else { -+ return part != 0; -+ } -+} -+ -+/* Loads a 32-bit immediate into rd, sign-extended. */ -+static void tcg_out_movi_i32(TCGContext *s, TCGReg rd, int32_t val) -+{ -+ tcg_target_long lo = sextreg(val, 0, 12); -+ tcg_target_long hi12 = sextreg(val, 12, 20); -+ -+ /* Single-instruction cases. */ -+ if (lo == val) { -+ /* val fits in simm12: addi.w rd, zero, val */ -+ tcg_out_opc_addi_w(s, rd, TCG_REG_ZERO, val); -+ return; -+ } -+ if (0x800 <= val && val <= 0xfff) { -+ /* val fits in uimm12: ori rd, zero, val */ -+ tcg_out_opc_ori(s, rd, TCG_REG_ZERO, val); -+ return; -+ } -+ -+ /* High bits must be set; load with lu12i.w + optional ori. */ -+ tcg_out_opc_lu12i_w(s, rd, hi12); -+ if (lo != 0) { -+ tcg_out_opc_ori(s, rd, rd, lo & 0xfff); -+ } -+} -+ -+static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, -+ tcg_target_long val) -+{ -+ /* -+ * LoongArch conventionally loads 64-bit immediates in at most 4 steps, -+ * with dedicated instructions for filling the respective bitfields -+ * below: -+ * -+ * 6 5 4 3 -+ * 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 -+ * +-----------------------+---------------------------------------+... -+ * | hi52 | hi32 | -+ * +-----------------------+---------------------------------------+... -+ * 3 2 1 -+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 -+ * ...+-------------------------------------+-------------------------+ -+ * | hi12 | lo | -+ * ...+-------------------------------------+-------------------------+ -+ * -+ * Check if val belong to one of the several fast cases, before falling -+ * back to the slow path. -+ */ -+ -+ intptr_t pc_offset; -+ tcg_target_long val_lo, val_hi, pc_hi, offset_hi; -+ tcg_target_long hi32, hi52; -+ bool rd_high_bits_are_ones; -+ -+ /* Value fits in signed i32. */ -+ if (type == TCG_TYPE_I32 || val == (int32_t)val) { -+ tcg_out_movi_i32(s, rd, val); -+ return; -+ } -+ -+ /* PC-relative cases. */ -+ pc_offset = tcg_pcrel_diff(s, (void *)val); -+ if (pc_offset == sextreg(pc_offset, 0, 22) && (pc_offset & 3) == 0) { -+ /* Single pcaddu2i. */ -+ tcg_out_opc_pcaddu2i(s, rd, pc_offset >> 2); -+ return; -+ } -+ -+ if (pc_offset == (int32_t)pc_offset) { -+ /* Offset within 32 bits; load with pcalau12i + ori. */ -+ val_lo = sextreg(val, 0, 12); -+ val_hi = val >> 12; -+ pc_hi = (val - pc_offset) >> 12; -+ offset_hi = val_hi - pc_hi; -+ -+ tcg_debug_assert(offset_hi == sextreg(offset_hi, 0, 20)); -+ tcg_out_opc_pcalau12i(s, rd, offset_hi); -+ if (val_lo != 0) { -+ tcg_out_opc_ori(s, rd, rd, val_lo & 0xfff); -+ } -+ return; -+ } -+ -+ hi32 = sextreg(val, 32, 20); -+ hi52 = sextreg(val, 52, 12); -+ -+ /* Single cu52i.d case. */ -+ if (ctz64(val) >= 52) { -+ tcg_out_opc_cu52i_d(s, rd, TCG_REG_ZERO, hi52); -+ return; -+ } -+ -+ /* Slow path. Initialize the low 32 bits, then concat high bits. */ -+ tcg_out_movi_i32(s, rd, val); -+ rd_high_bits_are_ones = (int32_t)val < 0; -+ -+ if (imm_part_needs_loading(rd_high_bits_are_ones, hi32)) { -+ tcg_out_opc_cu32i_d(s, rd, hi32); -+ rd_high_bits_are_ones = hi32 < 0; -+ } -+ -+ if (imm_part_needs_loading(rd_high_bits_are_ones, hi52)) { -+ tcg_out_opc_cu52i_d(s, rd, rd, hi52); -+ } -+} -+ -+static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_andi(s, ret, arg, 0xff); -+} -+ -+static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_bstrpick_w(s, ret, arg, 0, 15); -+} -+ -+static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_bstrpick_d(s, ret, arg, 0, 31); -+} -+ -+static void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_sext_b(s, ret, arg); -+} -+ -+static void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_sext_h(s, ret, arg); -+} -+ -+static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_addi_w(s, ret, arg, 0); -+} -+ -+static void tcg_out_clzctz(TCGContext *s, LoongArchInsn opc, -+ TCGReg a0, TCGReg a1, TCGReg a2, -+ bool c2, bool is_32bit) -+{ -+ if (c2) { -+ /* -+ * Fast path: semantics already satisfied due to constraint and -+ * insn behavior, single instruction is enough. -+ */ -+ tcg_debug_assert(a2 == (is_32bit ? 32 : 64)); -+ /* all clz/ctz insns belong to DJ-format */ -+ tcg_out32(s, encode_dj_insn(opc, a0, a1)); -+ return; -+ } -+ -+ tcg_out32(s, encode_dj_insn(opc, TCG_REG_TMP0, a1)); -+ /* a0 = a1 ? REG_TMP0 : a2 */ -+ tcg_out_opc_maskeqz(s, TCG_REG_TMP0, TCG_REG_TMP0, a1); -+ tcg_out_opc_masknez(s, a0, a2, a1); -+ tcg_out_opc_or(s, a0, TCG_REG_TMP0, a0); -+} -+ -+static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, -+ TCGReg arg1, TCGReg arg2, bool c2) -+{ -+ TCGReg tmp; -+ -+ if (c2) { -+ tcg_debug_assert(arg2 == 0); -+ } -+ -+ switch (cond) { -+ case TCG_COND_EQ: -+ if (c2) { -+ tmp = arg1; -+ } else { -+ tcg_out_opc_sub_d(s, ret, arg1, arg2); -+ tmp = ret; -+ } -+ tcg_out_opc_sltui(s, ret, tmp, 1); -+ break; -+ case TCG_COND_NE: -+ if (c2) { -+ tmp = arg1; -+ } else { -+ tcg_out_opc_sub_d(s, ret, arg1, arg2); -+ tmp = ret; -+ } -+ tcg_out_opc_sltu(s, ret, TCG_REG_ZERO, tmp); -+ break; -+ case TCG_COND_LT: -+ tcg_out_opc_slt(s, ret, arg1, arg2); -+ break; -+ case TCG_COND_GE: -+ tcg_out_opc_slt(s, ret, arg1, arg2); -+ tcg_out_opc_xori(s, ret, ret, 1); -+ break; -+ case TCG_COND_LE: -+ tcg_out_setcond(s, TCG_COND_GE, ret, arg2, arg1, false); -+ break; -+ case TCG_COND_GT: -+ tcg_out_setcond(s, TCG_COND_LT, ret, arg2, arg1, false); -+ break; -+ case TCG_COND_LTU: -+ tcg_out_opc_sltu(s, ret, arg1, arg2); -+ break; -+ case TCG_COND_GEU: -+ tcg_out_opc_sltu(s, ret, arg1, arg2); -+ tcg_out_opc_xori(s, ret, ret, 1); -+ break; -+ case TCG_COND_LEU: -+ tcg_out_setcond(s, TCG_COND_GEU, ret, arg2, arg1, false); -+ break; -+ case TCG_COND_GTU: -+ tcg_out_setcond(s, TCG_COND_LTU, ret, arg2, arg1, false); -+ break; -+ default: -+ g_assert_not_reached(); -+ break; -+ } -+} -+ -+/* -+ * Branch helpers -+ */ -+ -+static const struct { -+ LoongArchInsn op; -+ bool swap; -+} tcg_brcond_to_loongarch[] = { -+ [TCG_COND_EQ] = { OPC_BEQ, false }, -+ [TCG_COND_NE] = { OPC_BNE, false }, -+ [TCG_COND_LT] = { OPC_BGT, true }, -+ [TCG_COND_GE] = { OPC_BLE, true }, -+ [TCG_COND_LE] = { OPC_BLE, false }, -+ [TCG_COND_GT] = { OPC_BGT, false }, -+ [TCG_COND_LTU] = { OPC_BGTU, true }, -+ [TCG_COND_GEU] = { OPC_BLEU, true }, -+ [TCG_COND_LEU] = { OPC_BLEU, false }, -+ [TCG_COND_GTU] = { OPC_BGTU, false } -+}; -+ -+static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, -+ TCGReg arg2, TCGLabel *l) -+{ -+ LoongArchInsn op = tcg_brcond_to_loongarch[cond].op; -+ -+ tcg_debug_assert(op != 0); -+ -+ if (tcg_brcond_to_loongarch[cond].swap) { -+ TCGReg t = arg1; -+ arg1 = arg2; -+ arg2 = t; -+ } -+ -+ /* all conditional branch insns belong to DJSk16-format */ -+ tcg_out_reloc(s, s->code_ptr, R_LOONGARCH_BR_SK16, l, 0); -+ tcg_out32(s, encode_djsk16_insn(op, arg1, arg2, 0)); -+} -+ -+static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) -+{ -+ TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA; -+ ptrdiff_t offset = tcg_pcrel_diff(s, arg); -+ -+ tcg_debug_assert((offset & 3) == 0); -+ if (offset == sextreg(offset, 0, 28)) { -+ /* short jump: +/- 256MiB */ -+ if (tail) { -+ tcg_out_opc_b(s, offset >> 2); -+ } else { -+ tcg_out_opc_bl(s, offset >> 2); -+ } -+ } else if (offset == sextreg(offset, 0, 38)) { -+ /* long jump: +/- 256GiB */ -+ tcg_target_long lo = sextreg(offset, 0, 18); -+ tcg_target_long hi = offset - lo; -+ tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, hi >> 18); -+ tcg_out_opc_jirl(s, link, TCG_REG_TMP0, lo >> 2); -+ } else { -+ /* far jump: 64-bit */ -+ tcg_target_long lo = sextreg((tcg_target_long)arg, 0, 18); -+ tcg_target_long hi = (tcg_target_long)arg - lo; -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, hi); -+ tcg_out_opc_jirl(s, link, TCG_REG_TMP0, lo >> 2); -+ } -+} -+ -+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg) -+{ -+ tcg_out_call_int(s, arg, false); -+} -+ -+/* -+ * Load/store helpers -+ */ -+ -+static void tcg_out_ldst(TCGContext *s, LoongArchInsn opc, TCGReg data, -+ TCGReg addr, intptr_t offset) -+{ -+ intptr_t imm12 = sextreg(offset, 0, 12); -+ -+ if (offset != imm12) { -+ intptr_t diff = offset - (uintptr_t)s->code_ptr; -+ -+ if (addr == TCG_REG_ZERO && diff == (int32_t)diff) { -+ imm12 = sextreg(diff, 0, 12); -+ tcg_out_opc_pcaddu12i(s, TCG_REG_TMP2, (diff - imm12) >> 12); -+ } else { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP2, offset - imm12); -+ if (addr != TCG_REG_ZERO) { -+ tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, addr); -+ } -+ } -+ addr = TCG_REG_TMP2; -+ } -+ -+ switch (opc) { -+ case OPC_LD_B: -+ case OPC_LD_BU: -+ case OPC_LD_H: -+ case OPC_LD_HU: -+ case OPC_LD_W: -+ case OPC_LD_WU: -+ case OPC_LD_D: -+ case OPC_ST_B: -+ case OPC_ST_H: -+ case OPC_ST_W: -+ case OPC_ST_D: -+ tcg_out32(s, encode_djsk12_insn(opc, data, addr, imm12)); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg, -+ TCGReg arg1, intptr_t arg2) -+{ -+ bool is_32bit = type == TCG_TYPE_I32; -+ tcg_out_ldst(s, is_32bit ? OPC_LD_W : OPC_LD_D, arg, arg1, arg2); -+} -+ -+static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, -+ TCGReg arg1, intptr_t arg2) -+{ -+ bool is_32bit = type == TCG_TYPE_I32; -+ tcg_out_ldst(s, is_32bit ? OPC_ST_W : OPC_ST_D, arg, arg1, arg2); -+} -+ -+static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, -+ TCGReg base, intptr_t ofs) -+{ -+ if (val == 0) { -+ tcg_out_st(s, type, TCG_REG_ZERO, base, ofs); -+ return true; -+ } -+ return false; -+} -+ -+/* -+ * Load/store helpers for SoftMMU, and qemu_ld/st implementations -+ */ -+ -+#if defined(CONFIG_SOFTMMU) -+/* -+ * helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, -+ * MemOpIdx oi, uintptr_t ra) -+ */ -+static void * const qemu_ld_helpers[4] = { -+ [MO_8] = helper_ret_ldub_mmu, -+ [MO_16] = helper_le_lduw_mmu, -+ [MO_32] = helper_le_ldul_mmu, -+ [MO_64] = helper_le_ldq_mmu, -+}; -+ -+/* -+ * helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr, -+ * uintxx_t val, MemOpIdx oi, -+ * uintptr_t ra) -+ */ -+static void * const qemu_st_helpers[4] = { -+ [MO_8] = helper_ret_stb_mmu, -+ [MO_16] = helper_le_stw_mmu, -+ [MO_32] = helper_le_stl_mmu, -+ [MO_64] = helper_le_stq_mmu, -+}; -+ -+/* We expect to use a 12-bit negative offset from ENV. */ -+QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0); -+QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 11)); -+ -+static bool tcg_out_goto(TCGContext *s, const tcg_insn_unit *target) -+{ -+ tcg_out_opc_b(s, 0); -+ return reloc_br_sd10k16(s->code_ptr - 1, target); -+} -+ -+/* -+ * Emits common code for TLB addend lookup, that eventually loads the -+ * addend in TCG_REG_TMP2. -+ */ -+static void tcg_out_tlb_load(TCGContext *s, TCGReg addrl, MemOpIdx oi, -+ tcg_insn_unit **label_ptr, bool is_load) -+{ -+ MemOp opc = get_memop(oi); -+ unsigned s_bits = opc & MO_SIZE; -+ unsigned a_bits = get_alignment_bits(opc); -+ tcg_target_long compare_mask; -+ int mem_index = get_mmuidx(oi); -+ int fast_ofs = TLB_MASK_TABLE_OFS(mem_index); -+ int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask); -+ int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table); -+ -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_AREG0, mask_ofs); -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs); -+ -+ tcg_out_opc_srli_d(s, TCG_REG_TMP2, addrl, -+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); -+ tcg_out_opc_and(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0); -+ tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1); -+ -+ /* Load the tlb comparator and the addend. */ -+ tcg_out_ld(s, TCG_TYPE_TL, TCG_REG_TMP0, TCG_REG_TMP2, -+ is_load ? offsetof(CPUTLBEntry, addr_read) -+ : offsetof(CPUTLBEntry, addr_write)); -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_REG_TMP2, -+ offsetof(CPUTLBEntry, addend)); -+ -+ /* We don't support unaligned accesses. */ -+ if (a_bits < s_bits) { -+ a_bits = s_bits; -+ } -+ /* Clear the non-page, non-alignment bits from the address. */ -+ compare_mask = (tcg_target_long)TARGET_PAGE_MASK | ((1 << a_bits) - 1); -+ tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_TMP1, compare_mask); -+ tcg_out_opc_and(s, TCG_REG_TMP1, TCG_REG_TMP1, addrl); -+ -+ /* Compare masked address with the TLB entry. */ -+ label_ptr[0] = s->code_ptr; -+ tcg_out_opc_bne(s, TCG_REG_TMP0, TCG_REG_TMP1, 0); -+ -+ /* TLB Hit - addend in TCG_REG_TMP2, ready for use. */ -+} -+ -+static void add_qemu_ldst_label(TCGContext *s, int is_ld, MemOpIdx oi, -+ TCGType type, -+ TCGReg datalo, TCGReg addrlo, -+ void *raddr, tcg_insn_unit **label_ptr) -+{ -+ TCGLabelQemuLdst *label = new_ldst_label(s); -+ -+ label->is_ld = is_ld; -+ label->oi = oi; -+ label->type = type; -+ label->datalo_reg = datalo; -+ label->datahi_reg = 0; /* unused */ -+ label->addrlo_reg = addrlo; -+ label->addrhi_reg = 0; /* unused */ -+ label->raddr = tcg_splitwx_to_rx(raddr); -+ label->label_ptr[0] = label_ptr[0]; -+} -+ -+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ MemOpIdx oi = l->oi; -+ MemOp opc = get_memop(oi); -+ MemOp size = opc & MO_SIZE; -+ TCGType type = l->type; -+ -+ /* resolve label address */ -+ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { -+ return false; -+ } -+ -+ /* call load helper */ -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0); -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A1, l->addrlo_reg); -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A2, oi); -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, (tcg_target_long)l->raddr); -+ -+ tcg_out_call(s, qemu_ld_helpers[size]); -+ -+ switch (opc & MO_SSIZE) { -+ case MO_SB: -+ tcg_out_ext8s(s, l->datalo_reg, TCG_REG_A0); -+ break; -+ case MO_SW: -+ tcg_out_ext16s(s, l->datalo_reg, TCG_REG_A0); -+ break; -+ case MO_SL: -+ tcg_out_ext32s(s, l->datalo_reg, TCG_REG_A0); -+ break; -+ case MO_UL: -+ if (type == TCG_TYPE_I32) { -+ /* MO_UL loads of i32 should be sign-extended too */ -+ tcg_out_ext32s(s, l->datalo_reg, TCG_REG_A0); -+ break; -+ } -+ /* fallthrough */ -+ default: -+ tcg_out_mov(s, type, l->datalo_reg, TCG_REG_A0); -+ break; -+ } -+ -+ return tcg_out_goto(s, l->raddr); -+} -+ -+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ MemOpIdx oi = l->oi; -+ MemOp opc = get_memop(oi); -+ MemOp size = opc & MO_SIZE; -+ -+ /* resolve label address */ -+ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { -+ return false; -+ } -+ -+ /* call store helper */ -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0); -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A1, l->addrlo_reg); -+ switch (size) { -+ case MO_8: -+ tcg_out_ext8u(s, TCG_REG_A2, l->datalo_reg); -+ break; -+ case MO_16: -+ tcg_out_ext16u(s, TCG_REG_A2, l->datalo_reg); -+ break; -+ case MO_32: -+ tcg_out_ext32u(s, TCG_REG_A2, l->datalo_reg); -+ break; -+ case MO_64: -+ tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_A2, l->datalo_reg); -+ break; -+ default: -+ g_assert_not_reached(); -+ break; -+ } -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, oi); -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A4, (tcg_target_long)l->raddr); -+ -+ tcg_out_call(s, qemu_st_helpers[size]); -+ -+ return tcg_out_goto(s, l->raddr); -+} -+#else -+ -+/* -+ * Alignment helpers for user-mode emulation -+ */ -+ -+static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addr_reg, -+ unsigned a_bits) -+{ -+ TCGLabelQemuLdst *l = new_ldst_label(s); -+ -+ l->is_ld = is_ld; -+ l->addrlo_reg = addr_reg; -+ -+ /* -+ * Without micro-architecture details, we don't know which of bstrpick or -+ * andi is faster, so use bstrpick as it's not constrained by imm field -+ * width. (Not to say alignments >= 2^12 are going to happen any time -+ * soon, though) -+ */ -+ tcg_out_opc_bstrpick_d(s, TCG_REG_TMP1, addr_reg, 0, a_bits - 1); -+ -+ l->label_ptr[0] = s->code_ptr; -+ tcg_out_opc_bne(s, TCG_REG_TMP1, TCG_REG_ZERO, 0); -+ -+ l->raddr = tcg_splitwx_to_rx(s->code_ptr); -+} -+ -+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ /* resolve label address */ -+ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { -+ return false; -+ } -+ -+ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_A1, l->addrlo_reg); -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0); -+ -+ /* tail call, with the return address back inline. */ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RA, (uintptr_t)l->raddr); -+ tcg_out_call_int(s, (const void *)(l->is_ld ? helper_unaligned_ld -+ : helper_unaligned_st), true); -+ return true; -+} -+ -+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ return tcg_out_fail_alignment(s, l); -+} -+ -+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ return tcg_out_fail_alignment(s, l); -+} -+ -+#endif /* CONFIG_SOFTMMU */ -+ -+/* -+ * `ext32u` the address register into the temp register given, -+ * if target is 32-bit, no-op otherwise. -+ * -+ * Returns the address register ready for use with TLB addend. -+ */ -+static TCGReg tcg_out_zext_addr_if_32_bit(TCGContext *s, -+ TCGReg addr, TCGReg tmp) -+{ -+ if (TARGET_LONG_BITS == 32) { -+ tcg_out_ext32u(s, tmp, addr); -+ return tmp; -+ } -+ return addr; -+} -+ -+static void tcg_out_qemu_ld_indexed(TCGContext *s, TCGReg rd, TCGReg rj, -+ TCGReg rk, MemOp opc, TCGType type) -+{ -+ /* Byte swapping is left to middle-end expansion. */ -+ tcg_debug_assert((opc & MO_BSWAP) == 0); -+ -+ switch (opc & MO_SSIZE) { -+ case MO_UB: -+ tcg_out_opc_ldx_bu(s, rd, rj, rk); -+ break; -+ case MO_SB: -+ tcg_out_opc_ldx_b(s, rd, rj, rk); -+ break; -+ case MO_UW: -+ tcg_out_opc_ldx_hu(s, rd, rj, rk); -+ break; -+ case MO_SW: -+ tcg_out_opc_ldx_h(s, rd, rj, rk); -+ break; -+ case MO_UL: -+ if (type == TCG_TYPE_I64) { -+ tcg_out_opc_ldx_wu(s, rd, rj, rk); -+ break; -+ } -+ /* fallthrough */ -+ case MO_SL: -+ tcg_out_opc_ldx_w(s, rd, rj, rk); -+ break; -+ case MO_Q: -+ tcg_out_opc_ldx_d(s, rd, rj, rk); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, TCGType type) -+{ -+ TCGReg addr_regl; -+ TCGReg data_regl; -+ MemOpIdx oi; -+ MemOp opc; -+#if defined(CONFIG_SOFTMMU) -+ tcg_insn_unit *label_ptr[1]; -+#else -+ unsigned a_bits; -+#endif -+ TCGReg base; -+ -+ data_regl = *args++; -+ addr_regl = *args++; -+ oi = *args++; -+ opc = get_memop(oi); -+ -+#if defined(CONFIG_SOFTMMU) -+ tcg_out_tlb_load(s, addr_regl, oi, label_ptr, 1); -+ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); -+ tcg_out_qemu_ld_indexed(s, data_regl, base, TCG_REG_TMP2, opc, type); -+ add_qemu_ldst_label(s, 1, oi, type, -+ data_regl, addr_regl, -+ s->code_ptr, label_ptr); -+#else -+ a_bits = get_alignment_bits(opc); -+ if (a_bits) { -+ tcg_out_test_alignment(s, true, addr_regl, a_bits); -+ } -+ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); -+ TCGReg guest_base_reg = USE_GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_ZERO; -+ tcg_out_qemu_ld_indexed(s, data_regl, base, guest_base_reg, opc, type); -+#endif -+} -+ -+static void tcg_out_qemu_st_indexed(TCGContext *s, TCGReg data, -+ TCGReg rj, TCGReg rk, MemOp opc) -+{ -+ /* Byte swapping is left to middle-end expansion. */ -+ tcg_debug_assert((opc & MO_BSWAP) == 0); -+ -+ switch (opc & MO_SIZE) { -+ case MO_8: -+ tcg_out_opc_stx_b(s, data, rj, rk); -+ break; -+ case MO_16: -+ tcg_out_opc_stx_h(s, data, rj, rk); -+ break; -+ case MO_32: -+ tcg_out_opc_stx_w(s, data, rj, rk); -+ break; -+ case MO_64: -+ tcg_out_opc_stx_d(s, data, rj, rk); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args) -+{ -+ TCGReg addr_regl; -+ TCGReg data_regl; -+ MemOpIdx oi; -+ MemOp opc; -+#if defined(CONFIG_SOFTMMU) -+ tcg_insn_unit *label_ptr[1]; -+#else -+ unsigned a_bits; -+#endif -+ TCGReg base; -+ -+ data_regl = *args++; -+ addr_regl = *args++; -+ oi = *args++; -+ opc = get_memop(oi); -+ -+#if defined(CONFIG_SOFTMMU) -+ tcg_out_tlb_load(s, addr_regl, oi, label_ptr, 0); -+ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); -+ tcg_out_qemu_st_indexed(s, data_regl, base, TCG_REG_TMP2, opc); -+ add_qemu_ldst_label(s, 0, oi, -+ 0, /* type param is unused for stores */ -+ data_regl, addr_regl, -+ s->code_ptr, label_ptr); -+#else -+ a_bits = get_alignment_bits(opc); -+ if (a_bits) { -+ tcg_out_test_alignment(s, false, addr_regl, a_bits); -+ } -+ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); -+ TCGReg guest_base_reg = USE_GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_ZERO; -+ tcg_out_qemu_st_indexed(s, data_regl, base, guest_base_reg, opc); -+#endif -+} -+ -+/* -+ * Entry-points -+ */ -+ -+static const tcg_insn_unit *tb_ret_addr; -+ -+static void tcg_out_op(TCGContext *s, TCGOpcode opc, -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) -+{ -+ TCGArg a0 = args[0]; -+ TCGArg a1 = args[1]; -+ TCGArg a2 = args[2]; -+ int c2 = const_args[2]; -+ -+ switch (opc) { -+ case INDEX_op_exit_tb: -+ /* Reuse the zeroing that exists for goto_ptr. */ -+ if (a0 == 0) { -+ tcg_out_call_int(s, tcg_code_gen_epilogue, true); -+ } else { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0); -+ tcg_out_call_int(s, tb_ret_addr, true); -+ } -+ break; -+ -+ case INDEX_op_goto_tb: -+ assert(s->tb_jmp_insn_offset == 0); -+ /* indirect jump method */ -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, -+ (uintptr_t)(s->tb_jmp_target_addr + a0)); -+ tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0); -+ set_jmp_reset_offset(s, a0); -+ break; -+ -+ case INDEX_op_mb: -+ tcg_out_mb(s, a0); -+ break; -+ -+ case INDEX_op_goto_ptr: -+ tcg_out_opc_jirl(s, TCG_REG_ZERO, a0, 0); -+ break; -+ -+ case INDEX_op_br: -+ tcg_out_reloc(s, s->code_ptr, R_LOONGARCH_BR_SD10K16, arg_label(a0), -+ 0); -+ tcg_out_opc_b(s, 0); -+ break; -+ -+ case INDEX_op_brcond_i32: -+ case INDEX_op_brcond_i64: -+ tcg_out_brcond(s, a2, a0, a1, arg_label(args[3])); -+ break; -+ -+ case INDEX_op_ext8s_i32: -+ case INDEX_op_ext8s_i64: -+ tcg_out_ext8s(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext8u_i32: -+ case INDEX_op_ext8u_i64: -+ tcg_out_ext8u(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext16s_i32: -+ case INDEX_op_ext16s_i64: -+ tcg_out_ext16s(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext16u_i32: -+ case INDEX_op_ext16u_i64: -+ tcg_out_ext16u(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext32u_i64: -+ case INDEX_op_extu_i32_i64: -+ tcg_out_ext32u(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext32s_i64: -+ case INDEX_op_extrl_i64_i32: -+ case INDEX_op_ext_i32_i64: -+ tcg_out_ext32s(s, a0, a1); -+ break; -+ -+ case INDEX_op_extrh_i64_i32: -+ tcg_out_opc_srai_d(s, a0, a1, 32); -+ break; -+ -+ case INDEX_op_not_i32: -+ case INDEX_op_not_i64: -+ tcg_out_opc_nor(s, a0, a1, TCG_REG_ZERO); -+ break; -+ -+ case INDEX_op_nor_i32: -+ case INDEX_op_nor_i64: -+ if (c2) { -+ tcg_out_opc_ori(s, a0, a1, a2); -+ tcg_out_opc_nor(s, a0, a0, TCG_REG_ZERO); -+ } else { -+ tcg_out_opc_nor(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_andc_i32: -+ case INDEX_op_andc_i64: -+ if (c2) { -+ /* guaranteed to fit due to constraint */ -+ tcg_out_opc_andi(s, a0, a1, ~a2); -+ } else { -+ tcg_out_opc_andn(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_orc_i32: -+ case INDEX_op_orc_i64: -+ if (c2) { -+ /* guaranteed to fit due to constraint */ -+ tcg_out_opc_ori(s, a0, a1, ~a2); -+ } else { -+ tcg_out_opc_orn(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_and_i32: -+ case INDEX_op_and_i64: -+ if (c2) { -+ tcg_out_opc_andi(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_and(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_or_i32: -+ case INDEX_op_or_i64: -+ if (c2) { -+ tcg_out_opc_ori(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_or(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_xor_i32: -+ case INDEX_op_xor_i64: -+ if (c2) { -+ tcg_out_opc_xori(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_xor(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_extract_i32: -+ tcg_out_opc_bstrpick_w(s, a0, a1, a2, a2 + args[3] - 1); -+ break; -+ case INDEX_op_extract_i64: -+ tcg_out_opc_bstrpick_d(s, a0, a1, a2, a2 + args[3] - 1); -+ break; -+ -+ case INDEX_op_deposit_i32: -+ tcg_out_opc_bstrins_w(s, a0, a2, args[3], args[3] + args[4] - 1); -+ break; -+ case INDEX_op_deposit_i64: -+ tcg_out_opc_bstrins_d(s, a0, a2, args[3], args[3] + args[4] - 1); -+ break; -+ -+ case INDEX_op_bswap16_i32: -+ case INDEX_op_bswap16_i64: -+ tcg_out_opc_revb_2h(s, a0, a1); -+ if (a2 & TCG_BSWAP_OS) { -+ tcg_out_ext16s(s, a0, a0); -+ } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { -+ tcg_out_ext16u(s, a0, a0); -+ } -+ break; -+ -+ case INDEX_op_bswap32_i32: -+ /* All 32-bit values are computed sign-extended in the register. */ -+ a2 = TCG_BSWAP_OS; -+ /* fallthrough */ -+ case INDEX_op_bswap32_i64: -+ tcg_out_opc_revb_2w(s, a0, a1); -+ if (a2 & TCG_BSWAP_OS) { -+ tcg_out_ext32s(s, a0, a0); -+ } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { -+ tcg_out_ext32u(s, a0, a0); -+ } -+ break; -+ -+ case INDEX_op_bswap64_i64: -+ tcg_out_opc_revb_d(s, a0, a1); -+ break; -+ -+ case INDEX_op_clz_i32: -+ tcg_out_clzctz(s, OPC_CLZ_W, a0, a1, a2, c2, true); -+ break; -+ case INDEX_op_clz_i64: -+ tcg_out_clzctz(s, OPC_CLZ_D, a0, a1, a2, c2, false); -+ break; -+ -+ case INDEX_op_ctz_i32: -+ tcg_out_clzctz(s, OPC_CTZ_W, a0, a1, a2, c2, true); -+ break; -+ case INDEX_op_ctz_i64: -+ tcg_out_clzctz(s, OPC_CTZ_D, a0, a1, a2, c2, false); -+ break; -+ -+ case INDEX_op_shl_i32: -+ if (c2) { -+ tcg_out_opc_slli_w(s, a0, a1, a2 & 0x1f); -+ } else { -+ tcg_out_opc_sll_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_shl_i64: -+ if (c2) { -+ tcg_out_opc_slli_d(s, a0, a1, a2 & 0x3f); -+ } else { -+ tcg_out_opc_sll_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_shr_i32: -+ if (c2) { -+ tcg_out_opc_srli_w(s, a0, a1, a2 & 0x1f); -+ } else { -+ tcg_out_opc_srl_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_shr_i64: -+ if (c2) { -+ tcg_out_opc_srli_d(s, a0, a1, a2 & 0x3f); -+ } else { -+ tcg_out_opc_srl_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_sar_i32: -+ if (c2) { -+ tcg_out_opc_srai_w(s, a0, a1, a2 & 0x1f); -+ } else { -+ tcg_out_opc_sra_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_sar_i64: -+ if (c2) { -+ tcg_out_opc_srai_d(s, a0, a1, a2 & 0x3f); -+ } else { -+ tcg_out_opc_sra_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_rotl_i32: -+ /* transform into equivalent rotr/rotri */ -+ if (c2) { -+ tcg_out_opc_rotri_w(s, a0, a1, (32 - a2) & 0x1f); -+ } else { -+ tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2); -+ tcg_out_opc_rotr_w(s, a0, a1, TCG_REG_TMP0); -+ } -+ break; -+ case INDEX_op_rotl_i64: -+ /* transform into equivalent rotr/rotri */ -+ if (c2) { -+ tcg_out_opc_rotri_d(s, a0, a1, (64 - a2) & 0x3f); -+ } else { -+ tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2); -+ tcg_out_opc_rotr_d(s, a0, a1, TCG_REG_TMP0); -+ } -+ break; -+ -+ case INDEX_op_rotr_i32: -+ if (c2) { -+ tcg_out_opc_rotri_w(s, a0, a1, a2 & 0x1f); -+ } else { -+ tcg_out_opc_rotr_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_rotr_i64: -+ if (c2) { -+ tcg_out_opc_rotri_d(s, a0, a1, a2 & 0x3f); -+ } else { -+ tcg_out_opc_rotr_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_add_i32: -+ if (c2) { -+ tcg_out_opc_addi_w(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_add_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_add_i64: -+ if (c2) { -+ tcg_out_opc_addi_d(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_add_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_sub_i32: -+ if (c2) { -+ tcg_out_opc_addi_w(s, a0, a1, -a2); -+ } else { -+ tcg_out_opc_sub_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_sub_i64: -+ if (c2) { -+ tcg_out_opc_addi_d(s, a0, a1, -a2); -+ } else { -+ tcg_out_opc_sub_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_mul_i32: -+ tcg_out_opc_mul_w(s, a0, a1, a2); -+ break; -+ case INDEX_op_mul_i64: -+ tcg_out_opc_mul_d(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_mulsh_i32: -+ tcg_out_opc_mulh_w(s, a0, a1, a2); -+ break; -+ case INDEX_op_mulsh_i64: -+ tcg_out_opc_mulh_d(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_muluh_i32: -+ tcg_out_opc_mulh_wu(s, a0, a1, a2); -+ break; -+ case INDEX_op_muluh_i64: -+ tcg_out_opc_mulh_du(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_div_i32: -+ tcg_out_opc_div_w(s, a0, a1, a2); -+ break; -+ case INDEX_op_div_i64: -+ tcg_out_opc_div_d(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_divu_i32: -+ tcg_out_opc_div_wu(s, a0, a1, a2); -+ break; -+ case INDEX_op_divu_i64: -+ tcg_out_opc_div_du(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_rem_i32: -+ tcg_out_opc_mod_w(s, a0, a1, a2); -+ break; -+ case INDEX_op_rem_i64: -+ tcg_out_opc_mod_d(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_remu_i32: -+ tcg_out_opc_mod_wu(s, a0, a1, a2); -+ break; -+ case INDEX_op_remu_i64: -+ tcg_out_opc_mod_du(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_setcond_i32: -+ case INDEX_op_setcond_i64: -+ tcg_out_setcond(s, args[3], a0, a1, a2, c2); -+ break; -+ -+ case INDEX_op_ld8s_i32: -+ case INDEX_op_ld8s_i64: -+ tcg_out_ldst(s, OPC_LD_B, a0, a1, a2); -+ break; -+ case INDEX_op_ld8u_i32: -+ case INDEX_op_ld8u_i64: -+ tcg_out_ldst(s, OPC_LD_BU, a0, a1, a2); -+ break; -+ case INDEX_op_ld16s_i32: -+ case INDEX_op_ld16s_i64: -+ tcg_out_ldst(s, OPC_LD_H, a0, a1, a2); -+ break; -+ case INDEX_op_ld16u_i32: -+ case INDEX_op_ld16u_i64: -+ tcg_out_ldst(s, OPC_LD_HU, a0, a1, a2); -+ break; -+ case INDEX_op_ld_i32: -+ case INDEX_op_ld32s_i64: -+ tcg_out_ldst(s, OPC_LD_W, a0, a1, a2); -+ break; -+ case INDEX_op_ld32u_i64: -+ tcg_out_ldst(s, OPC_LD_WU, a0, a1, a2); -+ break; -+ case INDEX_op_ld_i64: -+ tcg_out_ldst(s, OPC_LD_D, a0, a1, a2); -+ break; -+ -+ case INDEX_op_st8_i32: -+ case INDEX_op_st8_i64: -+ tcg_out_ldst(s, OPC_ST_B, a0, a1, a2); -+ break; -+ case INDEX_op_st16_i32: -+ case INDEX_op_st16_i64: -+ tcg_out_ldst(s, OPC_ST_H, a0, a1, a2); -+ break; -+ case INDEX_op_st_i32: -+ case INDEX_op_st32_i64: -+ tcg_out_ldst(s, OPC_ST_W, a0, a1, a2); -+ break; -+ case INDEX_op_st_i64: -+ tcg_out_ldst(s, OPC_ST_D, a0, a1, a2); -+ break; -+ -+ case INDEX_op_qemu_ld_i32: -+ tcg_out_qemu_ld(s, args, TCG_TYPE_I32); -+ break; -+ case INDEX_op_qemu_ld_i64: -+ tcg_out_qemu_ld(s, args, TCG_TYPE_I64); -+ break; -+ case INDEX_op_qemu_st_i32: -+ tcg_out_qemu_st(s, args); -+ break; -+ case INDEX_op_qemu_st_i64: -+ tcg_out_qemu_st(s, args); -+ break; -+ -+ case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ -+ case INDEX_op_mov_i64: -+ case INDEX_op_call: /* Always emitted via tcg_out_call. */ -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) -+{ -+ switch (op) { -+ case INDEX_op_goto_ptr: -+ return C_O0_I1(r); -+ -+ case INDEX_op_st8_i32: -+ case INDEX_op_st8_i64: -+ case INDEX_op_st16_i32: -+ case INDEX_op_st16_i64: -+ case INDEX_op_st32_i64: -+ case INDEX_op_st_i32: -+ case INDEX_op_st_i64: -+ return C_O0_I2(rZ, r); -+ -+ case INDEX_op_brcond_i32: -+ case INDEX_op_brcond_i64: -+ return C_O0_I2(rZ, rZ); -+ -+ case INDEX_op_qemu_st_i32: -+ case INDEX_op_qemu_st_i64: -+ return C_O0_I2(LZ, L); -+ -+ case INDEX_op_ext8s_i32: -+ case INDEX_op_ext8s_i64: -+ case INDEX_op_ext8u_i32: -+ case INDEX_op_ext8u_i64: -+ case INDEX_op_ext16s_i32: -+ case INDEX_op_ext16s_i64: -+ case INDEX_op_ext16u_i32: -+ case INDEX_op_ext16u_i64: -+ case INDEX_op_ext32s_i64: -+ case INDEX_op_ext32u_i64: -+ case INDEX_op_extu_i32_i64: -+ case INDEX_op_extrl_i64_i32: -+ case INDEX_op_extrh_i64_i32: -+ case INDEX_op_ext_i32_i64: -+ case INDEX_op_not_i32: -+ case INDEX_op_not_i64: -+ case INDEX_op_extract_i32: -+ case INDEX_op_extract_i64: -+ case INDEX_op_bswap16_i32: -+ case INDEX_op_bswap16_i64: -+ case INDEX_op_bswap32_i32: -+ case INDEX_op_bswap32_i64: -+ case INDEX_op_bswap64_i64: -+ case INDEX_op_ld8s_i32: -+ case INDEX_op_ld8s_i64: -+ case INDEX_op_ld8u_i32: -+ case INDEX_op_ld8u_i64: -+ case INDEX_op_ld16s_i32: -+ case INDEX_op_ld16s_i64: -+ case INDEX_op_ld16u_i32: -+ case INDEX_op_ld16u_i64: -+ case INDEX_op_ld32s_i64: -+ case INDEX_op_ld32u_i64: -+ case INDEX_op_ld_i32: -+ case INDEX_op_ld_i64: -+ return C_O1_I1(r, r); -+ -+ case INDEX_op_qemu_ld_i32: -+ case INDEX_op_qemu_ld_i64: -+ return C_O1_I1(r, L); -+ -+ case INDEX_op_andc_i32: -+ case INDEX_op_andc_i64: -+ case INDEX_op_orc_i32: -+ case INDEX_op_orc_i64: -+ /* -+ * LoongArch insns for these ops don't have reg-imm forms, but we -+ * can express using andi/ori if ~constant satisfies -+ * TCG_CT_CONST_U12. -+ */ -+ return C_O1_I2(r, r, rC); -+ -+ case INDEX_op_shl_i32: -+ case INDEX_op_shl_i64: -+ case INDEX_op_shr_i32: -+ case INDEX_op_shr_i64: -+ case INDEX_op_sar_i32: -+ case INDEX_op_sar_i64: -+ case INDEX_op_rotl_i32: -+ case INDEX_op_rotl_i64: -+ case INDEX_op_rotr_i32: -+ case INDEX_op_rotr_i64: -+ return C_O1_I2(r, r, ri); -+ -+ case INDEX_op_add_i32: -+ case INDEX_op_add_i64: -+ return C_O1_I2(r, r, rI); -+ -+ case INDEX_op_and_i32: -+ case INDEX_op_and_i64: -+ case INDEX_op_nor_i32: -+ case INDEX_op_nor_i64: -+ case INDEX_op_or_i32: -+ case INDEX_op_or_i64: -+ case INDEX_op_xor_i32: -+ case INDEX_op_xor_i64: -+ /* LoongArch reg-imm bitops have their imms ZERO-extended */ -+ return C_O1_I2(r, r, rU); -+ -+ case INDEX_op_clz_i32: -+ case INDEX_op_clz_i64: -+ case INDEX_op_ctz_i32: -+ case INDEX_op_ctz_i64: -+ return C_O1_I2(r, r, rW); -+ -+ case INDEX_op_setcond_i32: -+ case INDEX_op_setcond_i64: -+ return C_O1_I2(r, r, rZ); -+ -+ case INDEX_op_deposit_i32: -+ case INDEX_op_deposit_i64: -+ /* Must deposit into the same register as input */ -+ return C_O1_I2(r, 0, rZ); -+ -+ case INDEX_op_sub_i32: -+ case INDEX_op_sub_i64: -+ return C_O1_I2(r, rZ, rN); -+ -+ case INDEX_op_mul_i32: -+ case INDEX_op_mul_i64: -+ case INDEX_op_mulsh_i32: -+ case INDEX_op_mulsh_i64: -+ case INDEX_op_muluh_i32: -+ case INDEX_op_muluh_i64: -+ case INDEX_op_div_i32: -+ case INDEX_op_div_i64: -+ case INDEX_op_divu_i32: -+ case INDEX_op_divu_i64: -+ case INDEX_op_rem_i32: -+ case INDEX_op_rem_i64: -+ case INDEX_op_remu_i32: -+ case INDEX_op_remu_i64: -+ return C_O1_I2(r, rZ, rZ); -+ -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static const int tcg_target_callee_save_regs[] = { -+ TCG_REG_S0, /* used for the global env (TCG_AREG0) */ -+ TCG_REG_S1, -+ TCG_REG_S2, -+ TCG_REG_S3, -+ TCG_REG_S4, -+ TCG_REG_S5, -+ TCG_REG_S6, -+ TCG_REG_S7, -+ TCG_REG_S8, -+ TCG_REG_S9, -+ TCG_REG_RA, /* should be last for ABI compliance */ -+}; -+ -+/* Stack frame parameters. */ -+#define REG_SIZE (TCG_TARGET_REG_BITS / 8) -+#define SAVE_SIZE ((int)ARRAY_SIZE(tcg_target_callee_save_regs) * REG_SIZE) -+#define TEMP_SIZE (CPU_TEMP_BUF_NLONGS * (int)sizeof(long)) -+#define FRAME_SIZE ((TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE + SAVE_SIZE \ -+ + TCG_TARGET_STACK_ALIGN - 1) \ -+ & -TCG_TARGET_STACK_ALIGN) -+#define SAVE_OFS (TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE) -+ -+/* We're expecting to be able to use an immediate for frame allocation. */ -+QEMU_BUILD_BUG_ON(FRAME_SIZE > 0x7ff); -+ -+/* Generate global QEMU prologue and epilogue code */ -+static void tcg_target_qemu_prologue(TCGContext *s) -+{ -+ int i; -+ -+ tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, TEMP_SIZE); -+ -+ /* TB prologue */ -+ tcg_out_opc_addi_d(s, TCG_REG_SP, TCG_REG_SP, -FRAME_SIZE); -+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { -+ tcg_out_st(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i], -+ TCG_REG_SP, SAVE_OFS + i * REG_SIZE); -+ } -+ -+#if !defined(CONFIG_SOFTMMU) -+ if (USE_GUEST_BASE) { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); -+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); -+ } -+#endif -+ -+ /* Call generated code */ -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); -+ tcg_out_opc_jirl(s, TCG_REG_ZERO, tcg_target_call_iarg_regs[1], 0); -+ -+ /* Return path for goto_ptr. Set return value to 0 */ -+ tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr); -+ tcg_out_mov(s, TCG_TYPE_REG, TCG_REG_A0, TCG_REG_ZERO); -+ -+ /* TB epilogue */ -+ tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr); -+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { -+ tcg_out_ld(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i], -+ TCG_REG_SP, SAVE_OFS + i * REG_SIZE); -+ } -+ -+ tcg_out_opc_addi_d(s, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE); -+ tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_RA, 0); -+} -+ -+static void tcg_target_init(TCGContext *s) -+{ -+ tcg_target_available_regs[TCG_TYPE_I32] = ALL_GENERAL_REGS; -+ tcg_target_available_regs[TCG_TYPE_I64] = ALL_GENERAL_REGS; -+ -+ tcg_target_call_clobber_regs = ALL_GENERAL_REGS; -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S0); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S1); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S2); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S3); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S4); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S5); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S6); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S7); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S8); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S9); -+ -+ s->reserved_regs = 0; -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP0); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP1); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TP); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_RESERVED); -+} -+ -+typedef struct { -+ DebugFrameHeader h; -+ uint8_t fde_def_cfa[4]; -+ uint8_t fde_reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2]; -+} DebugFrame; -+ -+#define ELF_HOST_MACHINE EM_LOONGARCH -+ -+static const DebugFrame debug_frame = { -+ .h.cie.len = sizeof(DebugFrameCIE) - 4, /* length after .len member */ -+ .h.cie.id = -1, -+ .h.cie.version = 1, -+ .h.cie.code_align = 1, -+ .h.cie.data_align = -(TCG_TARGET_REG_BITS / 8) & 0x7f, /* sleb128 */ -+ .h.cie.return_column = TCG_REG_RA, -+ -+ /* Total FDE size does not include the "len" member. */ -+ .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset), -+ -+ .fde_def_cfa = { -+ 12, TCG_REG_SP, /* DW_CFA_def_cfa sp, ... */ -+ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ -+ (FRAME_SIZE >> 7) -+ }, -+ .fde_reg_ofs = { -+ 0x80 + 23, 11, /* DW_CFA_offset, s0, -88 */ -+ 0x80 + 24, 10, /* DW_CFA_offset, s1, -80 */ -+ 0x80 + 25, 9, /* DW_CFA_offset, s2, -72 */ -+ 0x80 + 26, 8, /* DW_CFA_offset, s3, -64 */ -+ 0x80 + 27, 7, /* DW_CFA_offset, s4, -56 */ -+ 0x80 + 28, 6, /* DW_CFA_offset, s5, -48 */ -+ 0x80 + 29, 5, /* DW_CFA_offset, s6, -40 */ -+ 0x80 + 30, 4, /* DW_CFA_offset, s7, -32 */ -+ 0x80 + 31, 3, /* DW_CFA_offset, s8, -24 */ -+ 0x80 + 22, 2, /* DW_CFA_offset, s9, -16 */ -+ 0x80 + 1 , 1, /* DW_CFA_offset, ra, -8 */ -+ } -+}; -+ -+void tcg_register_jit(const void *buf, size_t buf_size) -+{ -+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); -+} -diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h -new file mode 100644 -index 000000000..d58a6162f ---- /dev/null -+++ b/tcg/loongarch64/tcg-target.h -@@ -0,0 +1,178 @@ -+/* -+ * Tiny Code Generator for QEMU -+ * -+ * Copyright (c) 2021 WANG Xuerui -+ * -+ * Based on tcg/riscv/tcg-target.h -+ * -+ * Copyright (c) 2018 SiFive, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#ifndef LOONGARCH_TCG_TARGET_H -+#define LOONGARCH_TCG_TARGET_H -+ -+/* -+ * Loongson removed the (incomplete) 32-bit support from kernel and toolchain -+ * for the initial upstreaming of this architecture, so don't bother and just -+ * support the LP64* ABI for now. -+ */ -+#if defined(__loongarch64) -+# define TCG_TARGET_REG_BITS 64 -+#else -+# error unsupported LoongArch register size -+#endif -+ -+#define TCG_TARGET_INSN_UNIT_SIZE 4 -+#define TCG_TARGET_NB_REGS 32 -+#define MAX_CODE_GEN_BUFFER_SIZE SIZE_MAX -+ -+typedef enum { -+ TCG_REG_ZERO, -+ TCG_REG_RA, -+ TCG_REG_TP, -+ TCG_REG_SP, -+ TCG_REG_A0, -+ TCG_REG_A1, -+ TCG_REG_A2, -+ TCG_REG_A3, -+ TCG_REG_A4, -+ TCG_REG_A5, -+ TCG_REG_A6, -+ TCG_REG_A7, -+ TCG_REG_T0, -+ TCG_REG_T1, -+ TCG_REG_T2, -+ TCG_REG_T3, -+ TCG_REG_T4, -+ TCG_REG_T5, -+ TCG_REG_T6, -+ TCG_REG_T7, -+ TCG_REG_T8, -+ TCG_REG_RESERVED, -+ TCG_REG_S9, -+ TCG_REG_S0, -+ TCG_REG_S1, -+ TCG_REG_S2, -+ TCG_REG_S3, -+ TCG_REG_S4, -+ TCG_REG_S5, -+ TCG_REG_S6, -+ TCG_REG_S7, -+ TCG_REG_S8, -+ -+ /* aliases */ -+ TCG_AREG0 = TCG_REG_S0, -+ TCG_REG_TMP0 = TCG_REG_T8, -+ TCG_REG_TMP1 = TCG_REG_T7, -+ TCG_REG_TMP2 = TCG_REG_T6, -+} TCGReg; -+ -+/* used for function call generation */ -+#define TCG_REG_CALL_STACK TCG_REG_SP -+#define TCG_TARGET_STACK_ALIGN 16 -+#define TCG_TARGET_CALL_ALIGN_ARGS 1 -+#define TCG_TARGET_CALL_STACK_OFFSET 0 -+ -+/* optional instructions */ -+#define TCG_TARGET_HAS_movcond_i32 0 -+#define TCG_TARGET_HAS_div_i32 1 -+#define TCG_TARGET_HAS_rem_i32 1 -+#define TCG_TARGET_HAS_div2_i32 0 -+#define TCG_TARGET_HAS_rot_i32 1 -+#define TCG_TARGET_HAS_deposit_i32 1 -+#define TCG_TARGET_HAS_extract_i32 1 -+#define TCG_TARGET_HAS_sextract_i32 0 -+#define TCG_TARGET_HAS_extract2_i32 0 -+#define TCG_TARGET_HAS_add2_i32 0 -+#define TCG_TARGET_HAS_sub2_i32 0 -+#define TCG_TARGET_HAS_mulu2_i32 0 -+#define TCG_TARGET_HAS_muls2_i32 0 -+#define TCG_TARGET_HAS_muluh_i32 1 -+#define TCG_TARGET_HAS_mulsh_i32 1 -+#define TCG_TARGET_HAS_ext8s_i32 1 -+#define TCG_TARGET_HAS_ext16s_i32 1 -+#define TCG_TARGET_HAS_ext8u_i32 1 -+#define TCG_TARGET_HAS_ext16u_i32 1 -+#define TCG_TARGET_HAS_bswap16_i32 1 -+#define TCG_TARGET_HAS_bswap32_i32 1 -+#define TCG_TARGET_HAS_not_i32 1 -+#define TCG_TARGET_HAS_neg_i32 0 -+#define TCG_TARGET_HAS_andc_i32 1 -+#define TCG_TARGET_HAS_orc_i32 1 -+#define TCG_TARGET_HAS_eqv_i32 0 -+#define TCG_TARGET_HAS_nand_i32 0 -+#define TCG_TARGET_HAS_nor_i32 1 -+#define TCG_TARGET_HAS_clz_i32 1 -+#define TCG_TARGET_HAS_ctz_i32 1 -+#define TCG_TARGET_HAS_ctpop_i32 0 -+#define TCG_TARGET_HAS_direct_jump 0 -+#define TCG_TARGET_HAS_brcond2 0 -+#define TCG_TARGET_HAS_setcond2 0 -+#define TCG_TARGET_HAS_qemu_st8_i32 0 -+ -+/* 64-bit operations */ -+#define TCG_TARGET_HAS_movcond_i64 0 -+#define TCG_TARGET_HAS_div_i64 1 -+#define TCG_TARGET_HAS_rem_i64 1 -+#define TCG_TARGET_HAS_div2_i64 0 -+#define TCG_TARGET_HAS_rot_i64 1 -+#define TCG_TARGET_HAS_deposit_i64 1 -+#define TCG_TARGET_HAS_extract_i64 1 -+#define TCG_TARGET_HAS_sextract_i64 0 -+#define TCG_TARGET_HAS_extract2_i64 0 -+#define TCG_TARGET_HAS_extrl_i64_i32 1 -+#define TCG_TARGET_HAS_extrh_i64_i32 1 -+#define TCG_TARGET_HAS_ext8s_i64 1 -+#define TCG_TARGET_HAS_ext16s_i64 1 -+#define TCG_TARGET_HAS_ext32s_i64 1 -+#define TCG_TARGET_HAS_ext8u_i64 1 -+#define TCG_TARGET_HAS_ext16u_i64 1 -+#define TCG_TARGET_HAS_ext32u_i64 1 -+#define TCG_TARGET_HAS_bswap16_i64 1 -+#define TCG_TARGET_HAS_bswap32_i64 1 -+#define TCG_TARGET_HAS_bswap64_i64 1 -+#define TCG_TARGET_HAS_not_i64 1 -+#define TCG_TARGET_HAS_neg_i64 0 -+#define TCG_TARGET_HAS_andc_i64 1 -+#define TCG_TARGET_HAS_orc_i64 1 -+#define TCG_TARGET_HAS_eqv_i64 0 -+#define TCG_TARGET_HAS_nand_i64 0 -+#define TCG_TARGET_HAS_nor_i64 1 -+#define TCG_TARGET_HAS_clz_i64 1 -+#define TCG_TARGET_HAS_ctz_i64 1 -+#define TCG_TARGET_HAS_ctpop_i64 0 -+#define TCG_TARGET_HAS_add2_i64 0 -+#define TCG_TARGET_HAS_sub2_i64 0 -+#define TCG_TARGET_HAS_mulu2_i64 0 -+#define TCG_TARGET_HAS_muls2_i64 0 -+#define TCG_TARGET_HAS_muluh_i64 1 -+#define TCG_TARGET_HAS_mulsh_i64 1 -+ -+/* not defined -- call should be eliminated at compile time */ -+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); -+ -+#define TCG_TARGET_DEFAULT_MO (0) -+ -+#define TCG_TARGET_NEED_LDST_LABELS -+ -+#define TCG_TARGET_HAS_MEMORY_BSWAP 0 -+ -+#endif /* LOONGARCH_TCG_TARGET_H */ --- -2.43.5 - diff --git a/1038-doc-update-AMD-SEV-to-include-Live-migration-flow.patch b/1038-doc-update-AMD-SEV-to-include-Live-migration-flow.patch deleted file mode 100644 index 6672e3f..0000000 --- a/1038-doc-update-AMD-SEV-to-include-Live-migration-flow.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 5152d49cc4aead7dc06e9f788e9c078701c5a160 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Thu, 7 May 2020 22:26:17 +0000 -Subject: [PATCH 01/29] doc: update AMD SEV to include Live migration flow - -cherry-picked from https://github.com/AMDESE/qemu/commit/0e2b3d80e3. - -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Brijesh Singh -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - docs/amd-memory-encryption.txt | 40 +++++++++++++++++++++++++++++++++- - 1 file changed, 39 insertions(+), 1 deletion(-) - -diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt -index ffca382b5..17e2714d9 100644 ---- a/docs/amd-memory-encryption.txt -+++ b/docs/amd-memory-encryption.txt -@@ -126,7 +126,45 @@ TODO - - Live Migration - ---------------- --TODO -+AMD SEV encrypts the memory of VMs and because a different key is used -+in each VM, the hypervisor will be unable to simply copy the -+ciphertext from one VM to another to migrate the VM. Instead the AMD SEV Key -+Management API provides sets of function which the hypervisor can use -+to package a guest page for migration, while maintaining the confidentiality -+provided by AMD SEV. -+ -+SEV guest VMs have the concept of private and shared memory. The private -+memory is encrypted with the guest-specific key, while shared memory may -+be encrypted with the hypervisor key. The migration APIs provided by the -+SEV API spec should be used for migrating the private pages. The -+KVM_GET_PAGE_ENC_BITMAP ioctl can be used to get the guest page encryption -+bitmap. The bitmap can be used to check if the given guest page is -+private or shared. -+ -+Before initiating the migration, we need to know the targets machine's public -+Diffie-Hellman key (PDH) and certificate chain. It can be retrieved -+with the 'query-sev-capabilities' QMP command or using the sev-tool. The -+migrate-set-parameter can be used to pass the target machine's PDH and -+certificate chain. -+ -+During the migration flow, the SEND_START is called on the source hypervisor -+to create an outgoing encryption context. The SEV guest policy dictates whether -+the certificate passed through the migrate-sev-set-info command will be -+validated. SEND_UPDATE_DATA is called to encrypt the guest private pages. -+After migration is completed, SEND_FINISH is called to destroy the encryption -+context and make the VM non-runnable to protect it against cloning. -+ -+On the target machine, RECEIVE_START is called first to create an -+incoming encryption context. The RECEIVE_UPDATE_DATA is called to copy -+the received encrypted page into guest memory. After migration has -+completed, RECEIVE_FINISH is called to make the VM runnable. -+ -+For more information about the migration see SEV API Appendix A -+Usage flow (Live migration section). -+ -+NOTE: -+To protect against the memory clone SEV APIs are designed to make the VM -+unrunnable in case of the migration failure. - - References - ----------------- --- -2.31.1 - diff --git a/1039-migration.json-add-AMD-SEV-specific-migration-parame.patch b/1039-migration.json-add-AMD-SEV-specific-migration-parame.patch deleted file mode 100644 index bd46ba7..0000000 --- a/1039-migration.json-add-AMD-SEV-specific-migration-parame.patch +++ /dev/null @@ -1,253 +0,0 @@ -From 7dc7f0659bfe9c8be64f65873df9595b3791dce5 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 11:27:00 +0000 -Subject: [PATCH 02/29] migration.json: add AMD SEV specific migration - parameters - -cherry-picked from https://github.com/AMDESE/qemu/commit/d6a23bde6b6e. - -AMD SEV migration flow requires that target machine's public Diffie-Hellman -key (PDH) and certificate chain must be passed before initiating the guest -migration. User can use QMP 'migrate-set-parameters' to pass the certificate -chain. The certificate chain will be used while creating the outgoing -encryption context. - -Signed-off-by: Brijesh Singh -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - migration/migration.c | 66 +++++++++++++++++++++++++++++++++++++++++++ - monitor/hmp-cmds.c | 18 ++++++++++++ - qapi/migration.json | 40 ++++++++++++++++++++++++-- - 3 files changed, 121 insertions(+), 3 deletions(-) - -diff --git a/migration/migration.c b/migration/migration.c -index 0885549de..6810bcefc 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -932,6 +932,12 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) - params->announce_rounds = s->parameters.announce_rounds; - params->has_announce_step = true; - params->announce_step = s->parameters.announce_step; -+ params->has_sev_pdh = true; -+ params->sev_pdh = g_strdup(s->parameters.sev_pdh); -+ params->has_sev_plat_cert = true; -+ params->sev_plat_cert = g_strdup(s->parameters.sev_plat_cert); -+ params->has_sev_amd_cert = true; -+ params->sev_amd_cert = g_strdup(s->parameters.sev_amd_cert); - - if (s->parameters.has_block_bitmap_mapping) { - params->has_block_bitmap_mapping = true; -@@ -1633,6 +1639,19 @@ static void migrate_params_test_apply(MigrateSetParameters *params, - dest->has_block_bitmap_mapping = true; - dest->block_bitmap_mapping = params->block_bitmap_mapping; - } -+ -+ if (params->has_sev_pdh) { -+ assert(params->sev_pdh->type == QTYPE_QSTRING); -+ dest->sev_pdh = g_strdup(params->sev_pdh->u.s); -+ } -+ if (params->has_sev_plat_cert) { -+ assert(params->sev_plat_cert->type == QTYPE_QSTRING); -+ dest->sev_plat_cert = g_strdup(params->sev_plat_cert->u.s); -+ } -+ if (params->has_sev_amd_cert) { -+ assert(params->sev_amd_cert->type == QTYPE_QSTRING); -+ dest->sev_amd_cert = g_strdup(params->sev_amd_cert->u.s); -+ } - } - - static void migrate_params_apply(MigrateSetParameters *params, Error **errp) -@@ -1755,6 +1774,22 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) - QAPI_CLONE(BitmapMigrationNodeAliasList, - params->block_bitmap_mapping); - } -+ -+ if (params->has_sev_pdh) { -+ g_free(s->parameters.sev_pdh); -+ assert(params->sev_pdh->type == QTYPE_QSTRING); -+ s->parameters.sev_pdh = g_strdup(params->sev_pdh->u.s); -+ } -+ if (params->has_sev_plat_cert) { -+ g_free(s->parameters.sev_plat_cert); -+ assert(params->sev_plat_cert->type == QTYPE_QSTRING); -+ s->parameters.sev_plat_cert = g_strdup(params->sev_plat_cert->u.s); -+ } -+ if (params->has_sev_amd_cert) { -+ g_free(s->parameters.sev_amd_cert); -+ assert(params->sev_amd_cert->type == QTYPE_QSTRING); -+ s->parameters.sev_amd_cert = g_strdup(params->sev_amd_cert->u.s); -+ } - } - - void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) -@@ -1775,6 +1810,27 @@ void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) - params->tls_hostname->type = QTYPE_QSTRING; - params->tls_hostname->u.s = strdup(""); - } -+ /* TODO Rewrite "" to null instead */ -+ if (params->has_sev_pdh -+ && params->sev_pdh->type == QTYPE_QNULL) { -+ qobject_unref(params->sev_pdh->u.n); -+ params->sev_pdh->type = QTYPE_QSTRING; -+ params->sev_pdh->u.s = strdup(""); -+ } -+ /* TODO Rewrite "" to null instead */ -+ if (params->has_sev_plat_cert -+ && params->sev_plat_cert->type == QTYPE_QNULL) { -+ qobject_unref(params->sev_plat_cert->u.n); -+ params->sev_plat_cert->type = QTYPE_QSTRING; -+ params->sev_plat_cert->u.s = strdup(""); -+ } -+ /* TODO Rewrite "" to null instead */ -+ if (params->has_sev_amd_cert -+ && params->sev_amd_cert->type == QTYPE_QNULL) { -+ qobject_unref(params->sev_amd_cert->u.n); -+ params->sev_amd_cert->type = QTYPE_QSTRING; -+ params->sev_amd_cert->u.s = strdup(""); -+ } - - migrate_params_test_apply(params, &tmp); - -@@ -4332,6 +4388,9 @@ static void migration_instance_finalize(Object *obj) - qemu_mutex_destroy(&ms->qemu_file_lock); - g_free(params->tls_hostname); - g_free(params->tls_creds); -+ g_free(params->sev_pdh); -+ g_free(params->sev_plat_cert); -+ g_free(params->sev_amd_cert); - qemu_sem_destroy(&ms->wait_unplug_sem); - qemu_sem_destroy(&ms->rate_limit_sem); - qemu_sem_destroy(&ms->pause_sem); -@@ -4383,6 +4442,13 @@ static void migration_instance_init(Object *obj) - params->has_tls_hostname = true; - params->has_tls_authz = true; - -+ params->sev_pdh = g_strdup(""); -+ params->sev_plat_cert = g_strdup(""); -+ params->sev_amd_cert = g_strdup(""); -+ params->has_sev_pdh = true; -+ params->has_sev_plat_cert = true; -+ params->has_sev_amd_cert = true; -+ - qemu_sem_init(&ms->postcopy_pause_sem, 0); - qemu_sem_init(&ms->postcopy_pause_rp_sem, 0); - qemu_sem_init(&ms->rp_state.rp_sem, 0); -diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c -index f7216ab5d..409bd15a6 100644 ---- a/monitor/hmp-cmds.c -+++ b/monitor/hmp-cmds.c -@@ -1349,6 +1349,24 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) - error_setg(&err, "The block-bitmap-mapping parameter can only be set " - "through QMP"); - break; -+ case MIGRATION_PARAMETER_SEV_PDH: -+ p->has_sev_pdh = true; -+ p->sev_pdh = g_new0(StrOrNull, 1); -+ p->sev_pdh->type = QTYPE_QSTRING; -+ visit_type_str(v, param, &p->sev_pdh->u.s, &err); -+ break; -+ case MIGRATION_PARAMETER_SEV_PLAT_CERT: -+ p->has_sev_plat_cert = true; -+ p->sev_plat_cert = g_new0(StrOrNull, 1); -+ p->sev_plat_cert->type = QTYPE_QSTRING; -+ visit_type_str(v, param, &p->sev_plat_cert->u.s, &err); -+ break; -+ case MIGRATION_PARAMETER_SEV_AMD_CERT: -+ p->has_sev_amd_cert = true; -+ p->sev_amd_cert = g_new0(StrOrNull, 1); -+ p->sev_amd_cert->type = QTYPE_QSTRING; -+ visit_type_str(v, param, &p->sev_amd_cert->u.s, &err); -+ break; - default: - assert(0); - } -diff --git a/qapi/migration.json b/qapi/migration.json -index 94bc5c69d..bad53a2f8 100644 ---- a/qapi/migration.json -+++ b/qapi/migration.json -@@ -774,6 +774,15 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# (Since 4.2) -+# -+# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# (Since 4.2) -+# -+# @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in -+# base64 (Since 4.2) -+# - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. - # -@@ -794,7 +803,8 @@ - 'xbzrle-cache-size', 'max-postcopy-bandwidth', - 'max-cpu-throttle', 'multifd-compression', - 'multifd-zlib-level' ,'multifd-zstd-level', -- 'block-bitmap-mapping' ] } -+ 'block-bitmap-mapping', -+ 'sev-pdh', 'sev-plat-cert', 'sev-amd-cert' ] } - - ## - # @MigrateSetParameters: -@@ -939,6 +949,15 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# (Since 4.2) -+# -+# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# (Since 4.2) -+# -+# @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in -+# base64 (Since 4.2) -+# - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. - # -@@ -974,7 +993,10 @@ - '*multifd-compression': 'MultiFDCompression', - '*multifd-zlib-level': 'uint8', - '*multifd-zstd-level': 'uint8', -- '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } -+ '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ], -+ '*sev-pdh':'StrOrNull', -+ '*sev-plat-cert': 'StrOrNull', -+ '*sev-amd-cert' : 'StrOrNull' } } - - ## - # @migrate-set-parameters: -@@ -1139,6 +1161,15 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# (Since 4.2) -+# -+# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# (Since 4.2) -+# -+# @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in -+# base64 (Since 4.2) -+# - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. - # -@@ -1172,7 +1203,10 @@ - '*multifd-compression': 'MultiFDCompression', - '*multifd-zlib-level': 'uint8', - '*multifd-zstd-level': 'uint8', -- '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } -+ '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ], -+ '*sev-pdh':'str', -+ '*sev-plat-cert': 'str', -+ '*sev-amd-cert' : 'str'} } - - ## - # @query-migrate-parameters: --- -2.31.1 - diff --git a/1040-confidential-guest-support-introduce-ConfidentialGue.patch b/1040-confidential-guest-support-introduce-ConfidentialGue.patch deleted file mode 100644 index c76a7dc..0000000 --- a/1040-confidential-guest-support-introduce-ConfidentialGue.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 7b50e920f4faacb529a43230565ae9e022e61649 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 11:41:37 +0000 -Subject: [PATCH 03/29] confidential guest support: introduce - ConfidentialGuestMemoryEncryptionOps for encrypted VMs - -cherry-picked from https://github.com/AMDESE/qemu/commit/74fce7be9bd. - -When memory encryption is enabled in VM, the guest RAM will be encrypted -with the guest-specific key, to protect the confidentiality of data while -in transit we need to platform specific hooks to save or migrate the -guest RAM. - -Introduce the new ConfidentialGuestMemoryEncryptionOps in this patch -which will be later used by the encrypted guest for migration. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 27 +++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index ba2dd4b5d..343f686fc 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -53,8 +53,35 @@ struct ConfidentialGuestSupport { - bool ready; - }; - -+/** -+ * The functions registers with ConfidentialGuestMemoryEncryptionOps will be -+ * used during the encrypted guest migration. -+ */ -+struct ConfidentialGuestMemoryEncryptionOps { -+ /* Initialize the platform specific state before starting the migration */ -+ int (*save_setup)(const char *pdh, const char *plat_cert, -+ const char *amd_cert); -+ -+ /* Write the encrypted page and metadata associated with it */ -+ int (*save_outgoing_page)(QEMUFile *f, uint8_t *ptr, uint32_t size, -+ uint64_t *bytes_sent); -+ -+ /* Load the incoming encrypted page into guest memory */ -+ int (*load_incoming_page)(QEMUFile *f, uint8_t *ptr); -+ -+ /* Check if gfn is in shared/unencrypted region */ -+ bool (*is_gfn_in_unshared_region)(unsigned long gfn); -+ -+ /* Write the shared regions list */ -+ int (*save_outgoing_shared_regions_list)(QEMUFile *f); -+ -+ /* Load the shared regions list */ -+ int (*load_incoming_shared_regions_list)(QEMUFile *f); -+}; -+ - typedef struct ConfidentialGuestSupportClass { - ObjectClass parent; -+ struct ConfidentialGuestMemoryEncryptionOps *memory_encryption_ops; - } ConfidentialGuestSupportClass; - - #endif /* !CONFIG_USER_ONLY */ --- -2.31.1 - diff --git a/1041-target-i386-sev-provide-callback-to-setup-outgoing-c.patch b/1041-target-i386-sev-provide-callback-to-setup-outgoing-c.patch deleted file mode 100644 index f7c60e2..0000000 --- a/1041-target-i386-sev-provide-callback-to-setup-outgoing-c.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 4e400056b6e3d895814d091da819ba742602581b Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 12:10:23 +0000 -Subject: [PATCH 04/29] target/i386: sev: provide callback to setup outgoing - context - -cherry-picked from https://github.com/AMDESE/qemu/commit/7521883afc0. - -The user provides the target machine's Platform Diffie-Hellman key (PDH) -and certificate chain before starting the SEV guest migration. Cache the -certificate chain as we need them while creating the outgoing context. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ - target/i386/sev.h | 2 ++ - 2 files changed, 61 insertions(+) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 36669bbdf..5dd6c0a3f 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -76,6 +76,12 @@ struct SevGuestState { - int sev_fd; - SevState state; - gchar *measurement; -+ guchar *remote_pdh; -+ size_t remote_pdh_len; -+ guchar *remote_plat_cert; -+ size_t remote_plat_cert_len; -+ guchar *amd_cert; -+ size_t amd_cert_len; - - uint32_t reset_cs; - uint32_t reset_ip; -@@ -160,6 +166,12 @@ static const char *const sev_fw_errlist[] = { - - #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist) - -+#define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */ -+ -+static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { -+ .save_setup = sev_save_setup, -+}; -+ - static int - sev_ioctl(int fd, int cmd, void *data, int *error) - { -@@ -872,6 +884,48 @@ sev_vm_state_change(void *opaque, bool running, RunState state) - } - } - -+static inline bool check_blob_length(size_t value) -+{ -+ if (value > SEV_FW_BLOB_MAX_SIZE) { -+ error_report("invalid length max=%d got=%ld", -+ SEV_FW_BLOB_MAX_SIZE, value); -+ return false; -+ } -+ -+ return true; -+} -+ -+int sev_save_setup(const char *pdh, const char *plat_cert, -+ const char *amd_cert) -+{ -+ SevGuestState *s = sev_guest; -+ -+ s->remote_pdh = g_base64_decode(pdh, &s->remote_pdh_len); -+ if (!check_blob_length(s->remote_pdh_len)) { -+ goto error; -+ } -+ -+ s->remote_plat_cert = g_base64_decode(plat_cert, -+ &s->remote_plat_cert_len); -+ if (!check_blob_length(s->remote_plat_cert_len)) { -+ goto error; -+ } -+ -+ s->amd_cert = g_base64_decode(amd_cert, &s->amd_cert_len); -+ if (!check_blob_length(s->amd_cert_len)) { -+ goto error; -+ } -+ -+ return 0; -+ -+error: -+ g_free(s->remote_pdh); -+ g_free(s->remote_plat_cert); -+ g_free(s->amd_cert); -+ -+ return 1; -+} -+ - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - { - SevGuestState *sev -@@ -886,6 +940,9 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - return 0; - } - -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(cgs)); -+ - ret = ram_block_discard_disable(true); - if (ret) { - error_report("%s: cannot disable RAM discard", __func__); -@@ -980,6 +1037,8 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - qemu_add_machine_init_done_notifier(&sev_machine_done_notify); - qemu_add_vm_change_state_handler(sev_vm_state_change, sev); - -+ cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; -+ - cgs->ready = true; - - return 0; -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 1c97bff99..14801ec44 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -51,6 +51,8 @@ extern uint32_t sev_get_reduced_phys_bits(void); - extern bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp); - - int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp); -+int sev_save_setup(const char *pdh, const char *plat_cert, -+ const char *amd_cert); - int sev_inject_launch_secret(const char *hdr, const char *secret, - uint64_t gpa, Error **errp); - --- -2.31.1 - diff --git a/1042-target-i386-sev-do-not-create-launch-context-for-an-.patch b/1042-target-i386-sev-do-not-create-launch-context-for-an-.patch deleted file mode 100644 index da664a3..0000000 --- a/1042-target-i386-sev-do-not-create-launch-context-for-an-.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 36b08d0392f2baec061e6fb90416db42dfad20f7 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 12:16:09 +0000 -Subject: [PATCH 05/29] target/i386: sev: do not create launch context for an - incoming guest - -cherry-picked from https://github.com/AMDESE/qemu/commit/b85694233495. - -The LAUNCH_START is used for creating an encryption context to encrypt -newly created guest, for an incoming guest the RECEIVE_START should be -used. - -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Brijesh Singh -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 5dd6c0a3f..fc8a2bb61 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -1024,10 +1024,16 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - } - } - -- ret = sev_launch_start(sev); -- if (ret) { -- error_setg(errp, "%s: failed to create encryption context", __func__); -- goto err; -+ /* -+ * The LAUNCH context is used for new guest, if its an incoming guest -+ * then RECEIVE context will be created after the connection is established. -+ */ -+ if (!runstate_check(RUN_STATE_INMIGRATE)) { -+ ret = sev_launch_start(sev); -+ if (ret) { -+ error_setg(errp, "%s: failed to create encryption context", __func__); -+ goto err; -+ } - } - - /* CSV guest needs no notifier to reg/unreg memory */ --- -2.31.1 - diff --git a/1043-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch b/1043-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch deleted file mode 100644 index f0a412a..0000000 --- a/1043-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch +++ /dev/null @@ -1,324 +0,0 @@ -From 196380db46216f207e57b00e4bbc95178683d0cf Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 12:55:25 +0000 -Subject: [PATCH 06/29] target/i386: sev: add support to encrypt the outgoing - page - -cherry-picked from https://github.com/AMDESE/qemu/commit/5187c6f86bd. - -The sev_save_outgoing_page() provide the implementation to encrypt the -guest private pages during the transit. The routines uses the SEND_START -command to create the outgoing encryption context on the first call then -uses the SEND_UPDATE_DATA command to encrypt the data before writing it -to the socket. While encrypting the data SEND_UPDATE_DATA produces some -metadata (e.g MAC, IV). The metadata is also sent to the target machine. -After migration is completed, we issue the SEND_FINISH command to transition -the SEV guest state from sending to unrunnable state. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 221 +++++++++++++++++++++++++++++++++++++++ - target/i386/sev.h | 2 + - target/i386/trace-events | 3 + - 3 files changed, 226 insertions(+) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index fc8a2bb61..622150106 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -31,6 +31,8 @@ - #include "sysemu/runstate.h" - #include "trace.h" - #include "migration/blocker.h" -+#include "migration/qemu-file.h" -+#include "migration/misc.h" - #include "qom/object.h" - #include "monitor/monitor.h" - #include "monitor/hmp-target.h" -@@ -82,6 +84,8 @@ struct SevGuestState { - size_t remote_plat_cert_len; - guchar *amd_cert; - size_t amd_cert_len; -+ gchar *send_packet_hdr; -+ size_t send_packet_hdr_len; - - uint32_t reset_cs; - uint32_t reset_ip; -@@ -170,6 +174,7 @@ static const char *const sev_fw_errlist[] = { - - static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, -+ .save_outgoing_page = sev_save_outgoing_page, - }; - - static int -@@ -926,6 +931,40 @@ error: - return 1; - } - -+static void -+sev_send_finish(void) -+{ -+ int ret, error; -+ -+ trace_kvm_sev_send_finish(); -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_FINISH, 0, &error); -+ if (ret) { -+ error_report("%s: SEND_FINISH ret=%d fw_error=%d '%s'", -+ __func__, ret, error, fw_error_to_str(error)); -+ } -+ -+ g_free(sev_guest->send_packet_hdr); -+ sev_set_guest_state(sev_guest, SEV_STATE_RUNNING); -+} -+ -+static void -+sev_migration_state_notifier(Notifier *notifier, void *data) -+{ -+ MigrationState *s = data; -+ -+ if (migration_has_finished(s) || -+ migration_in_postcopy_after_devices(s) || -+ migration_has_failed(s)) { -+ if (sev_check_state(sev_guest, SEV_STATE_SEND_UPDATE)) { -+ sev_send_finish(); -+ } -+ } -+} -+ -+static Notifier sev_migration_state_notify = { -+ .notify = sev_migration_state_notifier, -+}; -+ - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - { - SevGuestState *sev -@@ -1042,6 +1081,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - } - qemu_add_machine_init_done_notifier(&sev_machine_done_notify); - qemu_add_vm_change_state_handler(sev_vm_state_change, sev); -+ add_migration_state_change_notifier(&sev_migration_state_notify); - - cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; - -@@ -1283,6 +1323,187 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size) - return 0; - } - -+static int -+sev_get_send_session_length(void) -+{ -+ int ret, fw_err = 0; -+ struct kvm_sev_send_start start = {}; -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_START, &start, &fw_err); -+ if (fw_err != SEV_RET_INVALID_LEN) { -+ ret = -1; -+ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_err, fw_error_to_str(fw_err)); -+ goto err; -+ } -+ -+ ret = start.session_len; -+err: -+ return ret; -+} -+ -+static int -+sev_send_start(SevGuestState *s, QEMUFile *f, uint64_t *bytes_sent) -+{ -+ gsize pdh_len = 0, plat_cert_len; -+ int session_len, ret, fw_error; -+ struct kvm_sev_send_start start = { }; -+ guchar *pdh = NULL, *plat_cert = NULL, *session = NULL; -+ Error *local_err = NULL; -+ -+ if (!s->remote_pdh || !s->remote_plat_cert || !s->amd_cert_len) { -+ error_report("%s: missing remote PDH or PLAT_CERT", __func__); -+ return 1; -+ } -+ -+ start.pdh_cert_uaddr = (uintptr_t) s->remote_pdh; -+ start.pdh_cert_len = s->remote_pdh_len; -+ -+ start.plat_certs_uaddr = (uintptr_t)s->remote_plat_cert; -+ start.plat_certs_len = s->remote_plat_cert_len; -+ -+ start.amd_certs_uaddr = (uintptr_t)s->amd_cert; -+ start.amd_certs_len = s->amd_cert_len; -+ -+ /* get the session length */ -+ session_len = sev_get_send_session_length(); -+ if (session_len < 0) { -+ ret = 1; -+ goto err; -+ } -+ -+ session = g_new0(guchar, session_len); -+ start.session_uaddr = (unsigned long)session; -+ start.session_len = session_len; -+ -+ /* Get our PDH certificate */ -+ ret = sev_get_pdh_info(s->sev_fd, &pdh, &pdh_len, -+ &plat_cert, &plat_cert_len, &local_err); -+ if (ret) { -+ error_report("Failed to get our PDH cert"); -+ goto err; -+ } -+ -+ trace_kvm_sev_send_start(start.pdh_cert_uaddr, start.pdh_cert_len, -+ start.plat_certs_uaddr, start.plat_certs_len, -+ start.amd_certs_uaddr, start.amd_certs_len); -+ -+ ret = sev_ioctl(s->sev_fd, KVM_SEV_SEND_START, &start, &fw_error); -+ if (ret < 0) { -+ error_report("%s: SEND_START ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ qemu_put_be32(f, start.policy); -+ qemu_put_be32(f, pdh_len); -+ qemu_put_buffer(f, (uint8_t *)pdh, pdh_len); -+ qemu_put_be32(f, start.session_len); -+ qemu_put_buffer(f, (uint8_t *)start.session_uaddr, start.session_len); -+ *bytes_sent = 12 + pdh_len + start.session_len; -+ -+ sev_set_guest_state(s, SEV_STATE_SEND_UPDATE); -+ -+err: -+ g_free(pdh); -+ g_free(plat_cert); -+ return ret; -+} -+ -+static int -+sev_send_get_packet_len(int *fw_err) -+{ -+ int ret; -+ struct kvm_sev_send_update_data update = { 0, }; -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_UPDATE_DATA, -+ &update, fw_err); -+ if (*fw_err != SEV_RET_INVALID_LEN) { -+ ret = -1; -+ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ goto err; -+ } -+ -+ ret = update.hdr_len; -+ -+err: -+ return ret; -+} -+ -+static int -+sev_send_update_data(SevGuestState *s, QEMUFile *f, uint8_t *ptr, uint32_t size, -+ uint64_t *bytes_sent) -+{ -+ int ret, fw_error; -+ guchar *trans; -+ struct kvm_sev_send_update_data update = { }; -+ -+ /* -+ * If this is first call then query the packet header bytes and allocate -+ * the packet buffer. -+ */ -+ if (!s->send_packet_hdr) { -+ s->send_packet_hdr_len = sev_send_get_packet_len(&fw_error); -+ if (s->send_packet_hdr_len < 1) { -+ error_report("%s: SEND_UPDATE fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ -+ s->send_packet_hdr = g_new(gchar, s->send_packet_hdr_len); -+ } -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, size); -+ -+ update.hdr_uaddr = (uintptr_t)s->send_packet_hdr; -+ update.hdr_len = s->send_packet_hdr_len; -+ update.guest_uaddr = (uintptr_t)ptr; -+ update.guest_len = size; -+ update.trans_uaddr = (uintptr_t)trans; -+ update.trans_len = size; -+ -+ trace_kvm_sev_send_update_data(ptr, trans, size); -+ -+ ret = sev_ioctl(s->sev_fd, KVM_SEV_SEND_UPDATE_DATA, &update, &fw_error); -+ if (ret) { -+ error_report("%s: SEND_UPDATE_DATA ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ qemu_put_be32(f, update.hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); -+ *bytes_sent = 4 + update.hdr_len; -+ -+ qemu_put_be32(f, update.trans_len); -+ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ *bytes_sent += (4 + update.trans_len); -+ -+err: -+ g_free(trans); -+ return ret; -+} -+ -+int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, -+ uint32_t sz, uint64_t *bytes_sent) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* -+ * If this is a first buffer then create outgoing encryption context -+ * and write our PDH, policy and session data. -+ */ -+ if (!sev_check_state(s, SEV_STATE_SEND_UPDATE) && -+ sev_send_start(s, f, bytes_sent)) { -+ error_report("Failed to create outgoing context"); -+ return 1; -+ } -+ -+ return sev_send_update_data(s, f, ptr, sz, bytes_sent); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 14801ec44..19d3136dd 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -53,6 +53,8 @@ extern bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **er - int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp); - int sev_save_setup(const char *pdh, const char *plat_cert, - const char *amd_cert); -+int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, -+ uint32_t size, uint64_t *bytes_sent); - int sev_inject_launch_secret(const char *hdr, const char *secret, - uint64_t gpa, Error **errp); - -diff --git a/target/i386/trace-events b/target/i386/trace-events -index b7da9bd74..c165e3737 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -11,6 +11,9 @@ kvm_sev_launch_measurement(const char *value) "data %s" - kvm_sev_launch_finish(void) "" - kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d" - kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s" -+kvm_sev_send_start(uint64_t pdh, int l1, uint64_t plat, int l2, uint64_t amd, int l3) "pdh 0x%" PRIx64 " len %d plat 0x%" PRIx64 " len %d amd 0x%" PRIx64 " len %d" -+kvm_sev_send_update_data(void *src, void *dst, int len) "guest %p trans %p len %d" -+kvm_sev_send_finish(void) "" - - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 --- -2.31.1 - diff --git a/1044-target-i386-sev-add-support-to-load-incoming-encrypt.patch b/1044-target-i386-sev-add-support-to-load-incoming-encrypt.patch deleted file mode 100644 index cf10880..0000000 --- a/1044-target-i386-sev-add-support-to-load-incoming-encrypt.patch +++ /dev/null @@ -1,224 +0,0 @@ -From 10e03772a0a14f65602c496d65a4392b5b70da51 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 13:00:50 +0000 -Subject: [PATCH 07/29] target/i386: sev: add support to load incoming - encrypted page - -cherry-picked from https://github.com/AMDESE/qemu/commit/e86e5dccb045. - -The sev_load_incoming_page() provide the implementation to read the -incoming guest private pages from the socket and load it into the guest -memory. The routines uses the RECEIVE_START command to create the -incoming encryption context on the first call then uses the -RECEIEVE_UPDATE_DATA command to load the encrypted pages into the guest -memory. After migration is completed, we issue the RECEIVE_FINISH command -to transition the SEV guest to the runnable state so that it can be -executed. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 137 ++++++++++++++++++++++++++++++++++++++- - target/i386/sev.h | 1 + - target/i386/trace-events | 3 + - 3 files changed, 140 insertions(+), 1 deletion(-) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 622150106..bdd77fd0e 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -175,6 +175,7 @@ static const char *const sev_fw_errlist[] = { - static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = sev_save_outgoing_page, -+ .load_incoming_page = sev_load_incoming_page, - }; - - static int -@@ -877,13 +878,33 @@ sev_launch_finish(SevGuestState *sev) - migrate_add_blocker(sev_mig_blocker, &error_fatal); - } - -+static int -+sev_receive_finish(SevGuestState *s) -+{ -+ int error, ret = 1; -+ -+ trace_kvm_sev_receive_finish(); -+ ret = sev_ioctl(s->sev_fd, KVM_SEV_RECEIVE_FINISH, 0, &error); -+ if (ret) { -+ error_report("%s: RECEIVE_FINISH ret=%d fw_error=%d '%s'", -+ __func__, ret, error, fw_error_to_str(error)); -+ goto err; -+ } -+ -+ sev_set_guest_state(s, SEV_STATE_RUNNING); -+err: -+ return ret; -+} -+ - static void - sev_vm_state_change(void *opaque, bool running, RunState state) - { - SevGuestState *sev = opaque; - - if (running) { -- if (!sev_check_state(sev, SEV_STATE_RUNNING)) { -+ if (sev_check_state(sev, SEV_STATE_RECEIVE_UPDATE)) { -+ sev_receive_finish(sev); -+ } else if (!sev_check_state(sev, SEV_STATE_RUNNING)) { - sev_launch_finish(sev); - } - } -@@ -1504,6 +1525,120 @@ int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, - return sev_send_update_data(s, f, ptr, sz, bytes_sent); - } - -+static int -+sev_receive_start(SevGuestState *sev, QEMUFile *f) -+{ -+ int ret = 1; -+ int fw_error; -+ struct kvm_sev_receive_start start = { }; -+ gchar *session = NULL, *pdh_cert = NULL; -+ -+ /* get SEV guest handle */ -+ start.handle = object_property_get_int(OBJECT(sev), "handle", -+ &error_abort); -+ -+ /* get the source policy */ -+ start.policy = qemu_get_be32(f); -+ -+ /* get source PDH key */ -+ start.pdh_len = qemu_get_be32(f); -+ if (!check_blob_length(start.pdh_len)) { -+ return 1; -+ } -+ -+ pdh_cert = g_new(gchar, start.pdh_len); -+ qemu_get_buffer(f, (uint8_t *)pdh_cert, start.pdh_len); -+ start.pdh_uaddr = (uintptr_t)pdh_cert; -+ -+ /* get source session data */ -+ start.session_len = qemu_get_be32(f); -+ if (!check_blob_length(start.session_len)) { -+ return 1; -+ } -+ session = g_new(gchar, start.session_len); -+ qemu_get_buffer(f, (uint8_t *)session, start.session_len); -+ start.session_uaddr = (uintptr_t)session; -+ -+ trace_kvm_sev_receive_start(start.policy, session, pdh_cert); -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_RECEIVE_START, -+ &start, &fw_error); -+ if (ret < 0) { -+ error_report("Error RECEIVE_START ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ object_property_set_int(OBJECT(sev), "handle", start.handle, &error_abort); -+ sev_set_guest_state(sev, SEV_STATE_RECEIVE_UPDATE); -+err: -+ g_free(session); -+ g_free(pdh_cert); -+ -+ return ret; -+} -+ -+static int sev_receive_update_data(QEMUFile *f, uint8_t *ptr) -+{ -+ int ret = 1, fw_error = 0; -+ gchar *hdr = NULL, *trans = NULL; -+ struct kvm_sev_receive_update_data update = {}; -+ -+ /* get packet header */ -+ update.hdr_len = qemu_get_be32(f); -+ if (!check_blob_length(update.hdr_len)) { -+ return 1; -+ } -+ -+ hdr = g_new(gchar, update.hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); -+ update.hdr_uaddr = (uintptr_t)hdr; -+ -+ /* get transport buffer */ -+ update.trans_len = qemu_get_be32(f); -+ if (!check_blob_length(update.trans_len)) { -+ goto err; -+ } -+ -+ trans = g_new(gchar, update.trans_len); -+ update.trans_uaddr = (uintptr_t)trans; -+ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+ update.guest_uaddr = (uintptr_t) ptr; -+ update.guest_len = update.trans_len; -+ -+ trace_kvm_sev_receive_update_data(trans, ptr, update.guest_len, -+ hdr, update.hdr_len); -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_RECEIVE_UPDATE_DATA, -+ &update, &fw_error); -+ if (ret) { -+ error_report("Error RECEIVE_UPDATE_DATA ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+err: -+ g_free(trans); -+ g_free(hdr); -+ return ret; -+} -+ -+int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* -+ * If this is first buffer and SEV is not in recieiving state then -+ * use RECEIVE_START command to create a encryption context. -+ */ -+ if (!sev_check_state(s, SEV_STATE_RECEIVE_UPDATE) && -+ sev_receive_start(s, f)) { -+ return 1; -+ } -+ -+ return sev_receive_update_data(f, ptr); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 19d3136dd..1040b0cb2 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -55,6 +55,7 @@ int sev_save_setup(const char *pdh, const char *plat_cert, - const char *amd_cert); - int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, - uint32_t size, uint64_t *bytes_sent); -+int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr); - int sev_inject_launch_secret(const char *hdr, const char *secret, - uint64_t gpa, Error **errp); - -diff --git a/target/i386/trace-events b/target/i386/trace-events -index c165e3737..e32b0319b 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -14,6 +14,9 @@ kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data - kvm_sev_send_start(uint64_t pdh, int l1, uint64_t plat, int l2, uint64_t amd, int l3) "pdh 0x%" PRIx64 " len %d plat 0x%" PRIx64 " len %d amd 0x%" PRIx64 " len %d" - kvm_sev_send_update_data(void *src, void *dst, int len) "guest %p trans %p len %d" - kvm_sev_send_finish(void) "" -+kvm_sev_receive_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p" -+kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_len) "guest %p trans %p len %d hdr %p hdr_len %d" -+kvm_sev_receive_finish(void) "" - - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 --- -2.31.1 - diff --git a/1045-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch b/1045-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch deleted file mode 100644 index 27daa6b..0000000 --- a/1045-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch +++ /dev/null @@ -1,293 +0,0 @@ -From da756577d513a92fdfd4c1bdda3961dc704ccf12 Mon Sep 17 00:00:00 2001 -From: Ashish Kalra -Date: Tue, 27 Jul 2021 15:05:49 +0000 -Subject: [PATCH 08/29] kvm: Add support for SEV shared regions list and - KVM_EXIT_HYPERCALL. - -cherry-picked from https://github.com/AMDESE/qemu/commit/fcbbd9b19ac. - -KVM_HC_MAP_GPA_RANGE hypercall is used by the SEV guest to notify a -change in the page encryption status to the hypervisor. The hypercall -should be invoked only when the encryption attribute is changed from -encrypted -> decrypted and vice versa. By default all guest pages are -considered encrypted. - -The hypercall exits to userspace with KVM_EXIT_HYPERCALL exit code, -currently this is used only by SEV guests for guest page encryptiion -status tracking. Add support to handle this exit and invoke SEV -shared regions list handlers. - -Add support for SEV guest shared regions and implementation of the -SEV shared regions list. - -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - linux-headers/linux/kvm.h | 3 ++ - target/i386/kvm/kvm.c | 48 +++++++++++++++++ - target/i386/sev.c | 105 ++++++++++++++++++++++++++++++++++++++ - target/i386/sev.h | 3 ++ - 4 files changed, 159 insertions(+) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 3bc062a18..b640e72c8 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -344,6 +344,7 @@ struct kvm_run { - } mmio; - /* KVM_EXIT_HYPERCALL */ - struct { -+#define KVM_HC_MAP_GPA_RANGE 12 - __u64 nr; - __u64 args[6]; - __u64 ret; -@@ -1154,6 +1155,8 @@ struct kvm_ppc_resize_hpt { - #define KVM_CAP_S390_ZPCI_OP 221 - #define KVM_CAP_S390_CPU_TOPOLOGY 222 - -+#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) -+ - #ifdef KVM_CAP_IRQ_ROUTING - - struct kvm_irq_routing_irqchip { -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index a06221d3e..5262806c4 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -127,6 +127,7 @@ static int has_xsave2; - static int has_xcrs; - static int has_pit_state2; - static int has_exception_payload; -+static int has_map_gpa_range; - - static bool has_msr_mcg_ext_ctl; - -@@ -2052,6 +2053,17 @@ int kvm_arch_init_vcpu(CPUState *cs) - c->eax = MAX(c->eax, KVM_CPUID_SIGNATURE | 0x10); - } - -+ if (sev_enabled()) { -+ c = cpuid_find_entry(&cpuid_data.cpuid, -+ KVM_CPUID_FEATURES | kvm_base, 0); -+ if (c) { -+ c->eax |= (1 << KVM_FEATURE_MIGRATION_CONTROL); -+ if (has_map_gpa_range) { -+ c->eax |= (1 << KVM_FEATURE_HC_MAP_GPA_RANGE); -+ } -+ } -+ } -+ - cpuid_data.cpuid.nent = cpuid_i; - - cpuid_data.cpuid.padding = 0; -@@ -2397,6 +2409,17 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - } - } - -+ has_map_gpa_range = kvm_check_extension(s, KVM_CAP_EXIT_HYPERCALL); -+ if (has_map_gpa_range) { -+ ret = kvm_vm_enable_cap(s, KVM_CAP_EXIT_HYPERCALL, 0, -+ KVM_EXIT_HYPERCALL_VALID_MASK); -+ if (ret < 0) { -+ error_report("kvm: Failed to enable MAP_GPA_RANGE cap: %s", -+ strerror(-ret)); -+ return ret; -+ } -+ } -+ - ret = kvm_get_supported_msrs(s); - if (ret < 0) { - return ret; -@@ -4612,6 +4635,28 @@ static int kvm_handle_tpr_access(X86CPU *cpu) - return 1; - } - -+static int kvm_handle_exit_hypercall(X86CPU *cpu, struct kvm_run *run) -+{ -+ /* -+ * Currently this exit is only used by SEV guests for -+ * guest page encryption status tracking. -+ */ -+ if (run->hypercall.nr == KVM_HC_MAP_GPA_RANGE) { -+ unsigned long enc = run->hypercall.args[2]; -+ unsigned long gpa = run->hypercall.args[0]; -+ unsigned long npages = run->hypercall.args[1]; -+ unsigned long gfn_start = gpa >> TARGET_PAGE_BITS; -+ unsigned long gfn_end = gfn_start + npages; -+ -+ if (enc) { -+ sev_remove_shared_regions_list(gfn_start, gfn_end); -+ } else { -+ sev_add_shared_regions_list(gfn_start, gfn_end); -+ } -+ } -+ return 0; -+} -+ - int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) - { - static const uint8_t int3 = 0xcc; -@@ -4902,6 +4947,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) - /* already handled in kvm_arch_post_run */ - ret = 0; - break; -+ case KVM_EXIT_HYPERCALL: -+ ret = kvm_handle_exit_hypercall(cpu, run); -+ break; - default: - fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); - ret = -1; -diff --git a/target/i386/sev.c b/target/i386/sev.c -index bdd77fd0e..de57b0a27 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -45,6 +45,10 @@ - #define TYPE_SEV_GUEST "sev-guest" - OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST) - -+struct shared_region { -+ unsigned long gfn_start, gfn_end; -+ QTAILQ_ENTRY(shared_region) list; -+}; - - extern struct sev_ops sev_ops; - -@@ -90,6 +94,8 @@ struct SevGuestState { - uint32_t reset_cs; - uint32_t reset_ip; - bool reset_data_valid; -+ -+ QTAILQ_HEAD(, shared_region) shared_regions_list; - }; - - #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ -@@ -1105,6 +1111,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - add_migration_state_change_notifier(&sev_migration_state_notify); - - cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; -+ QTAILQ_INIT(&sev->shared_regions_list); - - cgs->ready = true; - -@@ -1639,6 +1646,104 @@ int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) - return sev_receive_update_data(f, ptr); - } - -+int sev_remove_shared_regions_list(unsigned long start, unsigned long end) -+{ -+ SevGuestState *s = sev_guest; -+ struct shared_region *pos; -+ -+ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ unsigned long l, r; -+ unsigned long curr_gfn_end = pos->gfn_end; -+ -+ /* -+ * Find if any intersection exists ? -+ * left bound for intersecting segment -+ */ -+ l = MAX(start, pos->gfn_start); -+ /* right bound for intersecting segment */ -+ r = MIN(end, pos->gfn_end); -+ if (l <= r) { -+ if (pos->gfn_start == l && pos->gfn_end == r) { -+ QTAILQ_REMOVE(&s->shared_regions_list, pos, list); -+ } else if (l == pos->gfn_start) { -+ pos->gfn_start = r; -+ } else if (r == pos->gfn_end) { -+ pos->gfn_end = l; -+ } else { -+ /* Do a de-merge -- split linked list nodes */ -+ struct shared_region *shrd_region; -+ -+ pos->gfn_end = l; -+ shrd_region = g_malloc0(sizeof(*shrd_region)); -+ if (!shrd_region) { -+ return 0; -+ } -+ shrd_region->gfn_start = r; -+ shrd_region->gfn_end = curr_gfn_end; -+ QTAILQ_INSERT_AFTER(&s->shared_regions_list, pos, -+ shrd_region, list); -+ } -+ } -+ if (end <= curr_gfn_end) { -+ break; -+ } -+ } -+ return 0; -+} -+ -+int sev_add_shared_regions_list(unsigned long start, unsigned long end) -+{ -+ struct shared_region *shrd_region; -+ struct shared_region *pos; -+ SevGuestState *s = sev_guest; -+ -+ if (QTAILQ_EMPTY(&s->shared_regions_list)) { -+ shrd_region = g_malloc0(sizeof(*shrd_region)); -+ if (!shrd_region) { -+ return -1; -+ } -+ shrd_region->gfn_start = start; -+ shrd_region->gfn_end = end; -+ QTAILQ_INSERT_TAIL(&s->shared_regions_list, shrd_region, list); -+ return 0; -+ } -+ -+ /* -+ * shared regions list is a sorted list in ascending order -+ * of guest PA's and also merges consecutive range of guest PA's -+ */ -+ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ /* handle duplicate overlapping regions */ -+ if (start >= pos->gfn_start && end <= pos->gfn_end) { -+ return 0; -+ } -+ if (pos->gfn_end < start) { -+ continue; -+ } -+ /* merge consecutive guest PA(s) -- forward merge */ -+ if (pos->gfn_start <= start && pos->gfn_end >= start) { -+ pos->gfn_end = end; -+ return 0; -+ } -+ break; -+ } -+ /* -+ * Add a new node -+ */ -+ shrd_region = g_malloc0(sizeof(*shrd_region)); -+ if (!shrd_region) { -+ return -1; -+ } -+ shrd_region->gfn_start = start; -+ shrd_region->gfn_end = end; -+ if (pos) { -+ QTAILQ_INSERT_BEFORE(pos, shrd_region, list); -+ } else { -+ QTAILQ_INSERT_TAIL(&s->shared_regions_list, shrd_region, list); -+ } -+ return 1; -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 1040b0cb2..8423b5522 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -61,6 +61,9 @@ int sev_inject_launch_secret(const char *hdr, const char *secret, - - int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size); - void sev_es_set_reset_vector(CPUState *cpu); -+int sev_remove_shared_regions_list(unsigned long gfn_start, -+ unsigned long gfn_end); -+int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - --- -2.31.1 - diff --git a/1046-migration-add-support-to-migrate-shared-regions-list.patch b/1046-migration-add-support-to-migrate-shared-regions-list.patch deleted file mode 100644 index 72e8cbe..0000000 --- a/1046-migration-add-support-to-migrate-shared-regions-list.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 9f9b6fbfc4cf9f73a001686954d34c40b29e3538 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 16:31:36 +0000 -Subject: [PATCH 09/29] migration: add support to migrate shared regions list - -cherry-picked from https://github.com/AMDESE/qemu/commit/9236f522e48b6. - -When memory encryption is enabled, the hypervisor maintains a shared -regions list which is referred by hypervisor during migration to check -if page is private or shared. This list is built during the VM bootup and -must be migrated to the target host so that hypervisor on target host can -use it for future migration. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - target/i386/sev.h | 2 ++ - 2 files changed, 45 insertions(+) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index de57b0a27..30cd436ab 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -178,10 +178,15 @@ static const char *const sev_fw_errlist[] = { - - #define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */ - -+#define SHARED_REGION_LIST_CONT 0x1 -+#define SHARED_REGION_LIST_END 0x2 -+ - static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = sev_save_outgoing_page, - .load_incoming_page = sev_load_incoming_page, -+ .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, -+ .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - }; - - static int -@@ -1744,6 +1749,44 @@ int sev_add_shared_regions_list(unsigned long start, unsigned long end) - return 1; - } - -+int sev_save_outgoing_shared_regions_list(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ struct shared_region *pos; -+ -+ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ qemu_put_be32(f, SHARED_REGION_LIST_CONT); -+ qemu_put_be32(f, pos->gfn_start); -+ qemu_put_be32(f, pos->gfn_end); -+ } -+ -+ qemu_put_be32(f, SHARED_REGION_LIST_END); -+ return 0; -+} -+ -+int sev_load_incoming_shared_regions_list(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ struct shared_region *shrd_region; -+ int status; -+ -+ status = qemu_get_be32(f); -+ while (status == SHARED_REGION_LIST_CONT) { -+ -+ shrd_region = g_malloc0(sizeof(*shrd_region)); -+ if (!shrd_region) { -+ return 0; -+ } -+ shrd_region->gfn_start = qemu_get_be32(f); -+ shrd_region->gfn_end = qemu_get_be32(f); -+ -+ QTAILQ_INSERT_TAIL(&s->shared_regions_list, shrd_region, list); -+ -+ status = qemu_get_be32(f); -+ } -+ return 0; -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 8423b5522..34814b9f2 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -64,6 +64,8 @@ void sev_es_set_reset_vector(CPUState *cpu); - int sev_remove_shared_regions_list(unsigned long gfn_start, - unsigned long gfn_end); - int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); -+int sev_save_outgoing_shared_regions_list(QEMUFile *f); -+int sev_load_incoming_shared_regions_list(QEMUFile *f); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - --- -2.31.1 - diff --git a/1047-migration-ram-add-support-to-send-encrypted-pages.patch b/1047-migration-ram-add-support-to-send-encrypted-pages.patch deleted file mode 100644 index 42223d6..0000000 --- a/1047-migration-ram-add-support-to-send-encrypted-pages.patch +++ /dev/null @@ -1,338 +0,0 @@ -From a973e7ee1489c9ee089f8c502f9b10f5ca4a4772 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 16:53:19 +0000 -Subject: [PATCH 10/29] migration/ram: add support to send encrypted pages - -cherry-picked from https://github.com/AMDESE/qemu/commit/2d6bda0d4cf. - -When memory encryption is enabled, the guest memory will be encrypted with -the guest specific key. The patch introduces RAM_SAVE_FLAG_ENCRYPTED_PAGE -flag to distinguish the encrypted data from plaintext. Encrypted pages -may need special handling. The sev_save_outgoing_page() is used -by the sender to write the encrypted pages onto the socket, similarly the -sev_load_incoming_page() is used by the target to read the -encrypted pages from the socket and load into the guest memory. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - migration/migration.h | 2 + - migration/ram.c | 163 +++++++++++++++++++++++++++++++++++++++++- - target/i386/sev.c | 14 ++++ - target/i386/sev.h | 4 ++ - 4 files changed, 182 insertions(+), 1 deletion(-) - -diff --git a/migration/migration.h b/migration/migration.h -index 0ae213332..596668d80 100644 ---- a/migration/migration.h -+++ b/migration/migration.h -@@ -403,4 +403,6 @@ void migration_cancel(const Error *error); - - void populate_vfio_info(MigrationInfo *info); - -+bool memcrypt_enabled(void); -+ - #endif -diff --git a/migration/ram.c b/migration/ram.c -index 93cdb456a..57f2c01bf 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -55,6 +55,10 @@ - #include "qemu/iov.h" - #include "multifd.h" - #include "sysemu/runstate.h" -+#include "exec/confidential-guest-support.h" -+ -+/* Defines RAM_SAVE_ENCRYPTED_PAGE and RAM_SAVE_SHARED_REGION_LIST */ -+#include "target/i386/sev.h" - - #include "hw/boards.h" /* for machine_dump_guest_core() */ - -@@ -80,6 +84,16 @@ - #define RAM_SAVE_FLAG_XBZRLE 0x40 - /* 0x80 is reserved in migration.h start with 0x100 next */ - #define RAM_SAVE_FLAG_COMPRESS_PAGE 0x100 -+#define RAM_SAVE_FLAG_ENCRYPTED_DATA 0x200 -+ -+bool memcrypt_enabled(void) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ if(ms->cgs) -+ return ms->cgs->ready; -+ else -+ return false; -+} - - static inline bool is_zero_range(uint8_t *p, uint64_t size) - { -@@ -468,6 +482,8 @@ static QemuCond decomp_done_cond; - - static bool do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block, - ram_addr_t offset, uint8_t *source_buf); -+static int ram_save_encrypted_page(RAMState *rs, PageSearchStatus *pss, -+ bool last_stage); - - static void *do_data_compress(void *opaque) - { -@@ -1301,6 +1317,80 @@ static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, - return 1; - } - -+/** -+ * ram_save_encrypted_page - send the given encrypted page to the stream -+ */ -+static int ram_save_encrypted_page(RAMState *rs, PageSearchStatus *pss, -+ bool last_stage) -+{ -+ int ret; -+ uint8_t *p; -+ RAMBlock *block = pss->block; -+ ram_addr_t offset = pss->page << TARGET_PAGE_BITS; -+ uint64_t bytes_xmit; -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ p = block->host + offset; -+ -+ ram_counters.transferred += -+ save_page_header(rs, rs->f, block, -+ offset | RAM_SAVE_FLAG_ENCRYPTED_DATA); -+ -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_PAGE); -+ ret = ops->save_outgoing_page(rs->f, p, TARGET_PAGE_SIZE, &bytes_xmit); -+ if (ret) { -+ return -1; -+ } -+ -+ ram_counters.transferred += bytes_xmit; -+ ram_counters.normal++; -+ -+ return 1; -+} -+ -+/** -+ * ram_save_shared_region_list: send the shared region list -+ */ -+static int ram_save_shared_region_list(RAMState *rs, QEMUFile *f) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ save_page_header(rs, rs->f, rs->last_seen_block, -+ RAM_SAVE_FLAG_ENCRYPTED_DATA); -+ qemu_put_be32(rs->f, RAM_SAVE_SHARED_REGIONS_LIST); -+ return ops->save_outgoing_shared_regions_list(rs->f); -+} -+ -+static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ int flag; -+ -+ flag = qemu_get_be32(f); -+ -+ if (flag == RAM_SAVE_ENCRYPTED_PAGE) { -+ return ops->load_incoming_page(f, ptr); -+ } else if (flag == RAM_SAVE_SHARED_REGIONS_LIST) { -+ return ops->load_incoming_shared_regions_list(f); -+ } else { -+ error_report("unknown encrypted flag %x", flag); -+ return 1; -+ } -+} -+ - /** - * ram_save_page: send the given page to the stream - * -@@ -2144,6 +2234,35 @@ static bool save_compress_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) - return false; - } - -+/** -+ * encrypted_test_list: check if the page is encrypted -+ * -+ * Returns a bool indicating whether the page is encrypted. -+ */ -+static bool encrypted_test_list(RAMState *rs, RAMBlock *block, -+ unsigned long page) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ unsigned long gfn; -+ -+ /* ROM devices contains the unencrypted data */ -+ if (memory_region_is_rom(block->mr)) { -+ return false; -+ } -+ -+ /* -+ * Translate page in ram_addr_t address space to GPA address -+ * space using memory region. -+ */ -+ gfn = page + (block->mr->addr >> TARGET_PAGE_BITS); -+ -+ return ops->is_gfn_in_unshared_region(gfn); -+} -+ - /** - * ram_save_target_page: save one target page - * -@@ -2164,6 +2283,17 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, - return res; - } - -+ /* -+ * If memory encryption is enabled then use memory encryption APIs -+ * to write the outgoing buffer to the wire. The encryption APIs -+ * will take care of accessing the guest memory and re-encrypt it -+ * for the transport purposes. -+ */ -+ if (memcrypt_enabled() && -+ encrypted_test_list(rs, pss->block, pss->page)) { -+ return ram_save_encrypted_page(rs, pss, last_stage); -+ } -+ - if (save_compress_page(rs, block, offset)) { - return 1; - } -@@ -2990,6 +3120,18 @@ void qemu_guest_free_page_hint(void *addr, size_t len) - } - } - -+static int ram_encrypted_save_setup(void) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ MigrationParameters *p = &migrate_get_current()->parameters; -+ -+ return ops->save_setup(p->sev_pdh, p->sev_plat_cert, p->sev_amd_cert); -+} -+ - /* - * Each of ram_save_setup, ram_save_iterate and ram_save_complete has - * long-running RCU critical section. When rcu-reclaims in the code -@@ -3025,6 +3167,13 @@ static int ram_save_setup(QEMUFile *f, void *opaque) - (*rsp)->f = f; - - WITH_RCU_READ_LOCK_GUARD() { -+ -+ if (memcrypt_enabled()) { -+ if (ram_encrypted_save_setup()) { -+ return -1; -+ } -+ } -+ - qemu_put_be64(f, ram_bytes_total_common(true) | RAM_SAVE_FLAG_MEM_SIZE); - - RAMBLOCK_FOREACH_MIGRATABLE(block) { -@@ -3217,6 +3366,11 @@ static int ram_save_complete(QEMUFile *f, void *opaque) - - flush_compressed_data(rs); - ram_control_after_iterate(f, RAM_CONTROL_FINISH); -+ -+ /* send the shared regions list */ -+ if (memcrypt_enabled()) { -+ ret = ram_save_shared_region_list(rs, f); -+ } - } - - if (ret < 0) { -@@ -4038,7 +4192,8 @@ static int ram_load_precopy(QEMUFile *f) - } - - if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE | -- RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE)) { -+ RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE | -+ RAM_SAVE_FLAG_ENCRYPTED_DATA)) { - RAMBlock *block = ram_block_from_stream(f, flags); - - host = host_from_ram_block_offset(block, addr); -@@ -4167,6 +4322,12 @@ static int ram_load_precopy(QEMUFile *f) - break; - } - break; -+ case RAM_SAVE_FLAG_ENCRYPTED_DATA: -+ if (load_encrypted_data(f, host)) { -+ error_report("Failed to load encrypted data"); -+ ret = -EINVAL; -+ } -+ break; - case RAM_SAVE_FLAG_EOS: - /* normal exit */ - multifd_recv_sync_main(); -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 30cd436ab..cc63a1aef 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -185,6 +185,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = sev_save_outgoing_page, - .load_incoming_page = sev_load_incoming_page, -+ .is_gfn_in_unshared_region = sev_is_gfn_in_unshared_region, - .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - }; -@@ -1787,6 +1788,19 @@ int sev_load_incoming_shared_regions_list(QEMUFile *f) - return 0; - } - -+bool sev_is_gfn_in_unshared_region(unsigned long gfn) -+{ -+ SevGuestState *s = sev_guest; -+ struct shared_region *pos; -+ -+ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ if (gfn >= pos->gfn_start && gfn < pos->gfn_end) { -+ return false; -+ } -+ } -+ return true; -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 34814b9f2..b8ad84014 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -38,6 +38,9 @@ typedef struct SevKernelLoaderContext { - size_t cmdline_size; - } SevKernelLoaderContext; - -+#define RAM_SAVE_ENCRYPTED_PAGE 0x1 -+#define RAM_SAVE_SHARED_REGIONS_LIST 0x2 -+ - #ifdef CONFIG_SEV - bool sev_enabled(void); - bool sev_es_enabled(void); -@@ -66,6 +69,7 @@ int sev_remove_shared_regions_list(unsigned long gfn_start, - int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); - int sev_save_outgoing_shared_regions_list(QEMUFile *f); - int sev_load_incoming_shared_regions_list(QEMUFile *f); -+bool sev_is_gfn_in_unshared_region(unsigned long gfn); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - --- -2.31.1 - diff --git a/1048-migration-ram-Force-encrypted-status-for-flash0-flas.patch b/1048-migration-ram-Force-encrypted-status-for-flash0-flas.patch deleted file mode 100644 index 8202afc..0000000 --- a/1048-migration-ram-Force-encrypted-status-for-flash0-flas.patch +++ /dev/null @@ -1,44 +0,0 @@ -From aae5a6ae741a985ff74b0ae7540d3c6ce3ef2fd0 Mon Sep 17 00:00:00 2001 -From: Ashish Kalra -Date: Tue, 27 Jul 2021 18:05:25 +0000 -Subject: [PATCH 11/29] migration/ram: Force encrypted status for flash0 & - flash1 devices. - -cherry-picked from https://github.com/AMDESE/qemu/commit/803d6a4c8d. - -Currently OVMF clears the C-bit and marks NonExistent memory space -as decrypted in the page encryption bitmap. By marking the -NonExistent memory space as decrypted it gurantees any future MMIO adds -will work correctly, but this marks flash0 device space as decrypted. -At reset the SEV core will be in forced encrypted state, so this -decrypted marking of flash0 device space will cause VCPU reset to fail -as flash0 device pages will be migrated incorrectly. - -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - migration/ram.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 57f2c01bf..da7a80994 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -2254,6 +2254,14 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, - return false; - } - -+ if (!strcmp(memory_region_name(block->mr), "system.flash0")) { -+ return true; -+ } -+ -+ if (!strcmp(memory_region_name(block->mr), "system.flash1")) { -+ return false; -+ } -+ - /* - * Translate page in ram_addr_t address space to GPA address - * space using memory region. --- -2.31.1 - diff --git a/1049-migration-for-SEV-live-migration-bump-downtime-limit.patch b/1049-migration-for-SEV-live-migration-bump-downtime-limit.patch deleted file mode 100644 index 70e9213..0000000 --- a/1049-migration-for-SEV-live-migration-bump-downtime-limit.patch +++ /dev/null @@ -1,64 +0,0 @@ -From a102d449e9601125c226cf40bc57b705bd1e3c28 Mon Sep 17 00:00:00 2001 -From: Ashish Kalra -Date: Tue, 3 Aug 2021 16:06:27 +0000 -Subject: [PATCH 12/29] migration: for SEV live migration bump downtime limit - to 1s. - -cherry-picked from https://github.com/AMDESE/qemu/commit/b1468803a2200. - -Now, qemu has a default expected downtime of 300 ms and -SEV Live migration has a page-per-second bandwidth of 350-450 pages -( SEV Live migration being generally slow due to guest RAM pages -being migrated after encryption using the security processor ). -With this expected downtime of 300ms and 350-450 pps bandwith, -the threshold size = <1/3 of the PPS bandwidth = ~100 pages. - -Now, this threshold size is the maximum pages/bytes that can be -sent in the final completion phase of Live migration -(where the source VM is stopped) with the expected downtime. -Therefore, with the threshold size computed above, -the migration completion phase which halts the source VM -and then transfers the leftover dirty pages, -is only reached in SEV live migration case when # of dirty pages are ~100. - -The dirty-pages-rate with larger guest RAM configuration like 4G, 8G, etc. -is much higher, typically in the range of 300-400+ pages, hence, -we always remain in the "dirty-sync" phase of migration and never -reach the migration completion phase with above guest RAM configs. - -To summarize, with larger guest RAM configs, -the dirty-pages-rate > threshold_size (with the default qemu expected downtime of 300ms). - -So, the fix is to increase qemu's expected downtime. - -This is a tweakable parameter which can be set using "migrate_set_downtime". - -With a downtime of 1 second, we get a threshold size of ~350-450 pages, -which will handle the "dirty-pages-rate" of 300+ pages and complete -the migration process, so we bump the default downtime to 1s in case -of SEV live migration being active. - -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - migration/migration.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/migration/migration.c b/migration/migration.c -index 6810bcefc..27c875c6c 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -3663,6 +3663,10 @@ static void migration_update_counters(MigrationState *s, - transferred = current_bytes - s->iteration_initial_bytes; - time_spent = current_time - s->iteration_start_time; - bandwidth = (double)transferred / time_spent; -+ if (memcrypt_enabled() && -+ s->parameters.downtime_limit < 1000) { -+ s->parameters.downtime_limit = 1000; -+ } - s->threshold_size = bandwidth * s->parameters.downtime_limit; - - s->mbps = (((double) transferred * 8.0) / --- -2.31.1 - diff --git a/1050-i386-kvm-Add-support-for-MSR-filtering.patch b/1050-i386-kvm-Add-support-for-MSR-filtering.patch deleted file mode 100644 index c967cf5..0000000 --- a/1050-i386-kvm-Add-support-for-MSR-filtering.patch +++ /dev/null @@ -1,201 +0,0 @@ -From b45eabe2febd210065e964b6425f73f1d53af43e Mon Sep 17 00:00:00 2001 -From: Alexander Graf -Date: Wed, 5 Oct 2022 00:56:42 +0200 -Subject: [PATCH 13/29] i386: kvm: Add support for MSR filtering - -commit 860054d8ce4067ef2bc3deb2a98cf93350fc03e4 upstream. - -KVM has grown support to deflect arbitrary MSRs to user space since -Linux 5.10. For now we don't expect to make a lot of use of this -feature, so let's expose it the easiest way possible: With up to 16 -individually maskable MSRs. - -This patch adds a kvm_filter_msr() function that other code can call -to install a hook on KVM MSR reads or writes. - -Signed-off-by: Alexander Graf -Message-Id: <20221004225643.65036-3-agraf@csgraf.de> -Signed-off-by: Paolo Bonzini ---- - target/i386/kvm/kvm.c | 123 +++++++++++++++++++++++++++++++++++++ - target/i386/kvm/kvm_i386.h | 11 ++++ - 2 files changed, 134 insertions(+) - -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 5262806c4..607469fb3 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -135,6 +135,8 @@ static struct kvm_cpuid2 *cpuid_cache; - static struct kvm_cpuid2 *hv_cpuid_cache; - static struct kvm_msr_list *kvm_feature_msrs; - -+static KVMMSRHandlers msr_handlers[KVM_MSR_FILTER_MAX_RANGES]; -+ - #define BUS_LOCK_SLICE_TIME 1000000000ULL /* ns */ - static RateLimit bus_lock_ratelimit_ctrl; - -@@ -2524,6 +2526,15 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - x86ms->bus_lock_ratelimit, BUS_LOCK_SLICE_TIME); - } - } -+ if (kvm_vm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR)) { -+ ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0, -+ KVM_MSR_EXIT_REASON_FILTER); -+ if (ret) { -+ error_report("Could not enable user space MSRs: %s", -+ strerror(-ret)); -+ exit(1); -+ } -+ } - - return 0; - } -@@ -4848,6 +4859,108 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) - } - } - -+static bool kvm_install_msr_filters(KVMState *s) -+{ -+ uint64_t zero = 0; -+ struct kvm_msr_filter filter = { -+ .flags = KVM_MSR_FILTER_DEFAULT_ALLOW, -+ }; -+ int r, i, j = 0; -+ -+ for (i = 0; i < KVM_MSR_FILTER_MAX_RANGES; i++) { -+ KVMMSRHandlers *handler = &msr_handlers[i]; -+ if (handler->msr) { -+ struct kvm_msr_filter_range *range = &filter.ranges[j++]; -+ -+ *range = (struct kvm_msr_filter_range) { -+ .flags = 0, -+ .nmsrs = 1, -+ .base = handler->msr, -+ .bitmap = (__u8 *)&zero, -+ }; -+ -+ if (handler->rdmsr) { -+ range->flags |= KVM_MSR_FILTER_READ; -+ } -+ -+ if (handler->wrmsr) { -+ range->flags |= KVM_MSR_FILTER_WRITE; -+ } -+ } -+ } -+ -+ r = kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter); -+ if (r) { -+ return false; -+ } -+ -+ return true; -+} -+ -+bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr, -+ QEMUWRMSRHandler *wrmsr) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) { -+ if (!msr_handlers[i].msr) { -+ msr_handlers[i] = (KVMMSRHandlers) { -+ .msr = msr, -+ .rdmsr = rdmsr, -+ .wrmsr = wrmsr, -+ }; -+ -+ if (!kvm_install_msr_filters(s)) { -+ msr_handlers[i] = (KVMMSRHandlers) { }; -+ return false; -+ } -+ -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+static int kvm_handle_rdmsr(X86CPU *cpu, struct kvm_run *run) -+{ -+ int i; -+ bool r; -+ -+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) { -+ KVMMSRHandlers *handler = &msr_handlers[i]; -+ if (run->msr.index == handler->msr) { -+ if (handler->rdmsr) { -+ r = handler->rdmsr(cpu, handler->msr, -+ (uint64_t *)&run->msr.data); -+ run->msr.error = r ? 0 : 1; -+ return 0; -+ } -+ } -+ } -+ -+ assert(false); -+} -+ -+static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run) -+{ -+ int i; -+ bool r; -+ -+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) { -+ KVMMSRHandlers *handler = &msr_handlers[i]; -+ if (run->msr.index == handler->msr) { -+ if (handler->wrmsr) { -+ r = handler->wrmsr(cpu, handler->msr, run->msr.data); -+ run->msr.error = r ? 0 : 1; -+ return 0; -+ } -+ } -+ } -+ -+ assert(false); -+} -+ - static bool has_sgx_provisioning; - - static bool __kvm_enable_sgx_provisioning(KVMState *s) -@@ -4947,6 +5060,16 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) - /* already handled in kvm_arch_post_run */ - ret = 0; - break; -+ case KVM_EXIT_X86_RDMSR: -+ /* We only enable MSR filtering, any other exit is bogus */ -+ assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER); -+ ret = kvm_handle_rdmsr(cpu, run); -+ break; -+ case KVM_EXIT_X86_WRMSR: -+ /* We only enable MSR filtering, any other exit is bogus */ -+ assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER); -+ ret = kvm_handle_wrmsr(cpu, run); -+ break; - case KVM_EXIT_HYPERCALL: - ret = kvm_handle_exit_hypercall(cpu, run); - break; -diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h -index 4124912c2..2ed586c11 100644 ---- a/target/i386/kvm/kvm_i386.h -+++ b/target/i386/kvm/kvm_i386.h -@@ -54,4 +54,15 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address); - bool kvm_enable_sgx_provisioning(KVMState *s); - void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask); - -+typedef bool QEMURDMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t *val); -+typedef bool QEMUWRMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t val); -+typedef struct kvm_msr_handlers { -+ uint32_t msr; -+ QEMURDMSRHandler *rdmsr; -+ QEMUWRMSRHandler *wrmsr; -+} KVMMSRHandlers; -+ -+bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr, -+ QEMUWRMSRHandler *wrmsr); -+ - #endif --- -2.31.1 - diff --git a/1051-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch b/1051-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch deleted file mode 100644 index 998be40..0000000 --- a/1051-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch +++ /dev/null @@ -1,118 +0,0 @@ -From f2f9d5860a3a32431b397f4a643de16423b5e4b3 Mon Sep 17 00:00:00 2001 -From: Ashish Kalra -Date: Tue, 27 Jul 2021 17:59:33 +0000 -Subject: [PATCH 14/29] kvm: Add support for userspace MSR filtering and - handling of MSR_KVM_MIGRATION_CONTROL. - -cherry-picked from https://github.com/AMDESE/qemu/commit/67935c3fd5f. - -Add support for userspace MSR filtering using KVM_X86_SET_MSR_FILTER -ioctl and handling of MSRs in userspace. Currently this is only used -for SEV guests which use MSR_KVM_MIGRATION_CONTROL to indicate if the -guest is enabled and ready for migration. - -KVM arch code calls into SEV guest specific code to delete the -SEV migrate blocker which has been setup at SEV_LAUNCH_FINISH. - -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/kvm/kvm.c | 37 +++++++++++++++++++++++++++++++++++++ - target/i386/sev.c | 6 ++++++ - target/i386/sev.h | 1 + - 3 files changed, 44 insertions(+) - -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 607469fb3..a833219d0 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -2330,6 +2330,32 @@ static int kvm_get_supported_msrs(KVMState *s) - return ret; - } - -+/* -+ * Currently this exit is only used by SEV guests for -+ * MSR_KVM_MIGRATION_CONTROL to indicate if the guest -+ * is ready for migration. -+ */ -+static uint64_t msr_kvm_migration_control; -+ -+static bool kvm_rdmsr_kvm_migration_control(X86CPU *cpu, uint32_t msr, -+ uint64_t *val) -+{ -+ *val = msr_kvm_migration_control; -+ -+ return true; -+} -+ -+static bool kvm_wrmsr_kvm_migration_control(X86CPU *cpu, uint32_t msr, -+ uint64_t val) -+{ -+ msr_kvm_migration_control = val; -+ -+ if (val == KVM_MIGRATION_READY) -+ sev_del_migrate_blocker(); -+ -+ return true; -+} -+ - static Notifier smram_machine_done; - static KVMMemoryListener smram_listener; - static AddressSpace smram_address_space; -@@ -2527,6 +2553,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - } - } - if (kvm_vm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR)) { -+ bool r; -+ - ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0, - KVM_MSR_EXIT_REASON_FILTER); - if (ret) { -@@ -2534,6 +2562,15 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - strerror(-ret)); - exit(1); - } -+ -+ r = kvm_filter_msr(s, MSR_KVM_MIGRATION_CONTROL, -+ kvm_rdmsr_kvm_migration_control, -+ kvm_wrmsr_kvm_migration_control); -+ if (!r) { -+ error_report("Could not install MSR_KVM_MIGRATION_CONTROL handler: %s", -+ strerror(-ret)); -+ exit(1); -+ } - } - - return 0; -diff --git a/target/i386/sev.c b/target/i386/sev.c -index cc63a1aef..b66665021 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -890,6 +890,12 @@ sev_launch_finish(SevGuestState *sev) - migrate_add_blocker(sev_mig_blocker, &error_fatal); - } - -+void -+sev_del_migrate_blocker(void) -+{ -+ migrate_del_blocker(sev_mig_blocker); -+} -+ - static int - sev_receive_finish(SevGuestState *s) - { -diff --git a/target/i386/sev.h b/target/i386/sev.h -index b8ad84014..7e53f8461 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -70,6 +70,7 @@ int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); - int sev_save_outgoing_shared_regions_list(QEMUFile *f); - int sev_load_incoming_shared_regions_list(QEMUFile *f); - bool sev_is_gfn_in_unshared_region(unsigned long gfn); -+void sev_del_migrate_blocker(void); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - --- -2.31.1 - diff --git a/1052-anolis-migration-ram-Force-encrypted-status-for-VGA-.patch b/1052-anolis-migration-ram-Force-encrypted-status-for-VGA-.patch deleted file mode 100644 index b9cfa6e..0000000 --- a/1052-anolis-migration-ram-Force-encrypted-status-for-VGA-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 1e332429c9aa4c996191ec703e3ec10a6bd459b3 Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Tue, 8 Dec 2020 22:57:46 -0500 -Subject: [PATCH 15/29] anolis: migration/ram: Force encrypted status for VGA - vram - -The VGA vram memory region act as frame buffer of VM. This memory -is decrypted in the QEMU process. For CSV VM live migration, we -should avoid memory encryption status check on VGA vram. - -Signed-off-by: hanliyang ---- - migration/ram.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index da7a80994..fb05ff44e 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -2262,6 +2262,10 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, - return false; - } - -+ if (!strcmp(memory_region_name(block->mr), "vga.vram")) { -+ return false; -+ } -+ - /* - * Translate page in ram_addr_t address space to GPA address - * space using memory region. --- -2.31.1 - diff --git a/1053-anolis-target-i386-sev-Clear-shared_regions_list-whe.patch b/1053-anolis-target-i386-sev-Clear-shared_regions_list-whe.patch deleted file mode 100644 index 9e00e54..0000000 --- a/1053-anolis-target-i386-sev-Clear-shared_regions_list-whe.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 6ff9e3e73b0a756c9a42f2df43178ef52cf5aa26 Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Sun, 16 Jan 2022 19:57:58 -0500 -Subject: [PATCH 16/29] anolis: target/i386: sev: Clear shared_regions_list - when reboot CSV Guest - -Also fix memory leak in sev_remove_shared_regions_list(). - -Signed-off-by: hanliyang ---- - target/i386/kvm/kvm.c | 6 ++++++ - target/i386/sev.c | 5 +++-- - 2 files changed, 9 insertions(+), 2 deletions(-) - -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index a833219d0..f0b61ec3c 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -2143,6 +2143,12 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) - - hyperv_x86_synic_reset(cpu); - } -+ -+ if (cpu_is_bsp(cpu) && -+ sev_enabled() && has_map_gpa_range) { -+ sev_remove_shared_regions_list(0, -1); -+ } -+ - /* enabled by default */ - env->poll_control_msr = 1; - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index b66665021..e3eab4119 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -1661,9 +1661,9 @@ int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) - int sev_remove_shared_regions_list(unsigned long start, unsigned long end) - { - SevGuestState *s = sev_guest; -- struct shared_region *pos; -+ struct shared_region *pos, *next_pos; - -- QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ QTAILQ_FOREACH_SAFE(pos, &s->shared_regions_list, list, next_pos) { - unsigned long l, r; - unsigned long curr_gfn_end = pos->gfn_end; - -@@ -1677,6 +1677,7 @@ int sev_remove_shared_regions_list(unsigned long start, unsigned long end) - if (l <= r) { - if (pos->gfn_start == l && pos->gfn_end == r) { - QTAILQ_REMOVE(&s->shared_regions_list, pos, list); -+ g_free(pos); - } else if (l == pos->gfn_start) { - pos->gfn_start = r; - } else if (r == pos->gfn_end) { --- -2.31.1 - diff --git a/1054-anolis-migration-ram-Fix-calculation-of-gfn-correpon.patch b/1054-anolis-migration-ram-Fix-calculation-of-gfn-correpon.patch deleted file mode 100644 index d385706..0000000 --- a/1054-anolis-migration-ram-Fix-calculation-of-gfn-correpon.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 7a8e357130982817732272c89a53adbb13408832 Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Sun, 16 Jan 2022 20:05:02 -0500 -Subject: [PATCH 17/29] anolis: migration/ram: Fix calculation of gfn correpond - to a page in ramblock - -A RAMBlock contains a host memory region which may consist of many -discontiguous MemoryRegion in AddressSpace of a Guest, so we cannot -get gpa by MemoryRegion.addr. Since KVM memslot records the relationship -between gpa and hva, so we can pass the hva of page in RAMBlock to -kvm_phisical_memory_addr_from_host() to get the expected gpa. - -Signed-off-by: hanliyang ---- - migration/ram.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/migration/ram.c b/migration/ram.c -index fb05ff44e..33e2c9d5f 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -59,6 +59,7 @@ - - /* Defines RAM_SAVE_ENCRYPTED_PAGE and RAM_SAVE_SHARED_REGION_LIST */ - #include "target/i386/sev.h" -+#include "sysemu/kvm.h" - - #include "hw/boards.h" /* for machine_dump_guest_core() */ - -@@ -2248,6 +2249,8 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, - struct ConfidentialGuestMemoryEncryptionOps *ops = - cgs_class->memory_encryption_ops; - unsigned long gfn; -+ hwaddr paddr = 0; -+ int ret; - - /* ROM devices contains the unencrypted data */ - if (memory_region_is_rom(block->mr)) { -@@ -2270,7 +2273,14 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, - * Translate page in ram_addr_t address space to GPA address - * space using memory region. - */ -- gfn = page + (block->mr->addr >> TARGET_PAGE_BITS); -+ if (kvm_enabled()) { -+ ret = kvm_physical_memory_addr_from_host(kvm_state, -+ block->host + (page << TARGET_PAGE_BITS), &paddr); -+ if (ret == 0) { -+ return false; -+ } -+ } -+ gfn = paddr >> TARGET_PAGE_BITS; - - return ops->is_gfn_in_unshared_region(gfn); - } --- -2.31.1 - diff --git a/1055-anolis-target-i386-csv-Move-is_hygon_cpu-to-header-f.patch b/1055-anolis-target-i386-csv-Move-is_hygon_cpu-to-header-f.patch deleted file mode 100644 index 41c6269..0000000 --- a/1055-anolis-target-i386-csv-Move-is_hygon_cpu-to-header-f.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 00e7b439f3c514d8ae20c20d5f18d24d71351c7d Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Wed, 1 Nov 2023 06:00:11 +0000 -Subject: [PATCH 18/29] anolis: target/i386: csv: Move is_hygon_cpu() to header - file csv.h - -The helper function is_hygon_cpu() will be called by functions out of -target/i386/csv.c. Move it to header file csv.h so that it can be a -common helper function. - -Signed-off-by: hanliyang ---- - target/i386/csv.c | 20 -------------------- - target/i386/csv.h | 22 ++++++++++++++++++++++ - 2 files changed, 22 insertions(+), 20 deletions(-) - -diff --git a/target/i386/csv.c b/target/i386/csv.c -index d166d3775..161cad39a 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -27,28 +27,8 @@ - - CsvGuestState csv_guest = { 0 }; - --#define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ --#define CPUID_VENDOR_HYGON_ECX 0x656e6975 /* "uine" */ --#define CPUID_VENDOR_HYGON_EDX 0x6e65476e /* "nGen" */ -- - #define GUEST_POLICY_CSV_BIT (1 << 6) - --static bool is_hygon_cpu(void) --{ -- uint32_t ebx = 0; -- uint32_t ecx = 0; -- uint32_t edx = 0; -- -- host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); -- -- if (ebx == CPUID_VENDOR_HYGON_EBX && -- ecx == CPUID_VENDOR_HYGON_ECX && -- edx == CPUID_VENDOR_HYGON_EDX) -- return true; -- else -- return false; --} -- - int - csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - { -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 7dc5c7536..4f5b2773c 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -16,6 +16,28 @@ - - #include "qapi/qapi-commands-misc-target.h" - -+#include "cpu.h" -+ -+#define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ -+#define CPUID_VENDOR_HYGON_ECX 0x656e6975 /* "uine" */ -+#define CPUID_VENDOR_HYGON_EDX 0x6e65476e /* "nGen" */ -+ -+static __attribute__((unused)) bool is_hygon_cpu(void) -+{ -+ uint32_t ebx = 0; -+ uint32_t ecx = 0; -+ uint32_t edx = 0; -+ -+ host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); -+ -+ if (ebx == CPUID_VENDOR_HYGON_EBX && -+ ecx == CPUID_VENDOR_HYGON_ECX && -+ edx == CPUID_VENDOR_HYGON_EDX) -+ return true; -+ else -+ return false; -+} -+ - #ifdef CONFIG_CSV - bool csv_enabled(void); - #else --- -2.31.1 - diff --git a/1056-anolis-target-i386-csv-Read-cert-chain-from-file-whe.patch b/1056-anolis-target-i386-csv-Read-cert-chain-from-file-whe.patch deleted file mode 100644 index 23a528c..0000000 --- a/1056-anolis-target-i386-csv-Read-cert-chain-from-file-whe.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 980dff011e266d60f8ce669a1dc14cc23b192c8b Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Mon, 13 Nov 2023 21:55:33 +0000 -Subject: [PATCH 19/29] anolis: target/i386: csv: Read cert chain from file - when prepared for CSV live migration - -The cert chain is too long when encoded with base64, use the filename -of cert chain instead of the encoded string when prepared for CSV live -migration. - -Signed-off-by: hanliyang ---- - qapi/migration.json | 24 +++++++++++++++--------- - target/i386/sev.c | 29 +++++++++++++++++++++++++---- - 2 files changed, 40 insertions(+), 13 deletions(-) - -diff --git a/qapi/migration.json b/qapi/migration.json -index bad53a2f8..8632abb20 100644 ---- a/qapi/migration.json -+++ b/qapi/migration.json -@@ -774,14 +774,16 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # --# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64, or -+# pdh filename for hygon - # (Since 4.2) - # --# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# @sev-plat-cert: The target host platform certificate chain encoded in base64, -+# or plat cert filename for hygon - # (Since 4.2) - # - # @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in --# base64 (Since 4.2) -+# base64, or vendor cert filename for hygon (Since 4.2) - # - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. -@@ -949,14 +951,16 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # --# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64, or -+# pdh filename for hygon - # (Since 4.2) - # --# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# @sev-plat-cert: The target host platform certificate chain encoded in base64, -+# or plat cert filename for hygon - # (Since 4.2) - # - # @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in --# base64 (Since 4.2) -+# base64, or vendor cert filename for hygon (Since 4.2) - # - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. -@@ -1161,14 +1165,16 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # --# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64, or -+# pdh filename for hygon - # (Since 4.2) - # --# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# @sev-plat-cert: The target host platform certificate chain encoded in base64, -+# or plat cert filename for hygon - # (Since 4.2) - # - # @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in --# base64 (Since 4.2) -+# base64, or vendor cert filename for hygon (Since 4.2) - # - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. -diff --git a/target/i386/sev.c b/target/i386/sev.c -index e3eab4119..ebe97799c 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -944,18 +944,39 @@ int sev_save_setup(const char *pdh, const char *plat_cert, - { - SevGuestState *s = sev_guest; - -- s->remote_pdh = g_base64_decode(pdh, &s->remote_pdh_len); -+ if (is_hygon_cpu()) { -+ if (sev_read_file_base64(pdh, &s->remote_pdh, -+ &s->remote_pdh_len) < 0) { -+ goto error; -+ } -+ } else { -+ s->remote_pdh = g_base64_decode(pdh, &s->remote_pdh_len); -+ } - if (!check_blob_length(s->remote_pdh_len)) { - goto error; - } - -- s->remote_plat_cert = g_base64_decode(plat_cert, -- &s->remote_plat_cert_len); -+ if (is_hygon_cpu()) { -+ if (sev_read_file_base64(plat_cert, &s->remote_plat_cert, -+ &s->remote_plat_cert_len) < 0) { -+ goto error; -+ } -+ } else { -+ s->remote_plat_cert = g_base64_decode(plat_cert, -+ &s->remote_plat_cert_len); -+ } - if (!check_blob_length(s->remote_plat_cert_len)) { - goto error; - } - -- s->amd_cert = g_base64_decode(amd_cert, &s->amd_cert_len); -+ if (is_hygon_cpu()) { -+ if (sev_read_file_base64(amd_cert, &s->amd_cert, -+ &s->amd_cert_len) < 0) { -+ goto error; -+ } -+ } else { -+ s->amd_cert = g_base64_decode(amd_cert, &s->amd_cert_len); -+ } - if (!check_blob_length(s->amd_cert_len)) { - goto error; - } --- -2.31.1 - diff --git a/1057-anolis-target-i386-csv-add-support-to-queue-the-outg.patch b/1057-anolis-target-i386-csv-add-support-to-queue-the-outg.patch deleted file mode 100644 index f6a3b3b..0000000 --- a/1057-anolis-target-i386-csv-add-support-to-queue-the-outg.patch +++ /dev/null @@ -1,270 +0,0 @@ -From 19941d177378b596a52a7905925525d68d152dea Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 11:00:07 +0800 -Subject: [PATCH 20/29] anolis: target/i386: csv: add support to queue the - outgoing page into a list - -The csv_queue_outgoing_page() provide the implementation to queue the -guest private pages during transmission. The routines queues the outgoing -pages into a listi, and then issues the KVM_CSV_COMMAND_BATCH command to -encrypt the pages togather before writing them to the socket. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 3 + - linux-headers/linux/kvm.h | 6 + - target/i386/sev.c | 172 ++++++++++++++++++++++ - target/i386/sev.h | 2 + - 4 files changed, 183 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 343f686fc..1f32519d4 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -77,6 +77,9 @@ struct ConfidentialGuestMemoryEncryptionOps { - - /* Load the shared regions list */ - int (*load_incoming_shared_regions_list)(QEMUFile *f); -+ -+ /* Queue the encrypted page and metadata associated with it into a list */ -+ int (*queue_outgoing_page)(uint8_t *ptr, uint32_t size, uint64_t addr); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index b640e72c8..8dd8c5e6a 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1938,6 +1938,12 @@ struct kvm_csv_init_data { - __u64 nodemask; - }; - -+struct kvm_csv_batch_list_node { -+ __u64 cmd_data_addr; -+ __u64 addr; -+ __u64 next_cmd_addr; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) -diff --git a/target/i386/sev.c b/target/i386/sev.c -index ebe97799c..e7ff3f4dd 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -50,6 +50,15 @@ struct shared_region { - QTAILQ_ENTRY(shared_region) list; - }; - -+typedef struct CsvBatchCmdList CsvBatchCmdList; -+typedef void (*CsvDestroyCmdNodeFn) (void *data); -+ -+struct CsvBatchCmdList { -+ struct kvm_csv_batch_list_node *head; -+ struct kvm_csv_batch_list_node *tail; -+ CsvDestroyCmdNodeFn destroy_fn; -+}; -+ - extern struct sev_ops sev_ops; - - /** -@@ -96,6 +105,9 @@ struct SevGuestState { - bool reset_data_valid; - - QTAILQ_HEAD(, shared_region) shared_regions_list; -+ -+ /* link list used for HYGON CSV */ -+ CsvBatchCmdList *csv_batch_cmd_list; - }; - - #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ -@@ -188,6 +200,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .is_gfn_in_unshared_region = sev_is_gfn_in_unshared_region, - .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, -+ .queue_outgoing_page = csv_queue_outgoing_page, - }; - - static int -@@ -1829,6 +1842,165 @@ bool sev_is_gfn_in_unshared_region(unsigned long gfn) - return true; - } - -+#include "csv.h" -+ -+static CsvBatchCmdList * -+csv_batch_cmd_list_create(struct kvm_csv_batch_list_node *head, -+ CsvDestroyCmdNodeFn func) -+{ -+ CsvBatchCmdList *csv_batch_cmd_list = -+ g_malloc0(sizeof(*csv_batch_cmd_list)); -+ -+ if (!csv_batch_cmd_list) { -+ return NULL; -+ } -+ -+ csv_batch_cmd_list->head = head; -+ csv_batch_cmd_list->tail = head; -+ csv_batch_cmd_list->destroy_fn = func; -+ -+ return csv_batch_cmd_list; -+} -+ -+static int -+csv_batch_cmd_list_add_after(CsvBatchCmdList *list, -+ struct kvm_csv_batch_list_node *new_node) -+{ -+ list->tail->next_cmd_addr = (__u64)new_node; -+ list->tail = new_node; -+ -+ return 0; -+} -+ -+static struct kvm_csv_batch_list_node * -+csv_batch_cmd_list_node_create(uint64_t cmd_data_addr, uint64_t addr) -+{ -+ struct kvm_csv_batch_list_node *new_node = -+ g_malloc0(sizeof(struct kvm_csv_batch_list_node)); -+ -+ if (!new_node) { -+ return NULL; -+ } -+ -+ new_node->cmd_data_addr = cmd_data_addr; -+ new_node->addr = addr; -+ new_node->next_cmd_addr = 0; -+ -+ return new_node; -+} -+ -+static int csv_batch_cmd_list_destroy(CsvBatchCmdList *list) -+{ -+ struct kvm_csv_batch_list_node *node = list->head; -+ -+ while (node != NULL) { -+ if (list->destroy_fn != NULL) -+ list->destroy_fn((void *)node->cmd_data_addr); -+ -+ list->head = (struct kvm_csv_batch_list_node *)node->next_cmd_addr; -+ g_free(node); -+ node = list->head; -+ } -+ -+ g_free(list); -+ return 0; -+} -+ -+static void send_update_data_free(void *data) -+{ -+ struct kvm_sev_send_update_data *update = -+ (struct kvm_sev_send_update_data *)data; -+ g_free((guchar *)update->hdr_uaddr); -+ g_free((guchar *)update->trans_uaddr); -+ g_free(update); -+} -+ -+static int -+csv_send_queue_data(SevGuestState *s, uint8_t *ptr, -+ uint32_t size, uint64_t addr) -+{ -+ int ret = 0; -+ int fw_error; -+ guchar *trans; -+ guchar *packet_hdr; -+ struct kvm_sev_send_update_data *update; -+ struct kvm_csv_batch_list_node *new_node = NULL; -+ -+ /* If this is first call then query the packet header bytes and allocate -+ * the packet buffer. -+ */ -+ if (s->send_packet_hdr_len < 1) { -+ s->send_packet_hdr_len = sev_send_get_packet_len(&fw_error); -+ if (s->send_packet_hdr_len < 1) { -+ error_report("%s: SEND_UPDATE fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ } -+ -+ packet_hdr = g_new(guchar, s->send_packet_hdr_len); -+ memset(packet_hdr, 0, s->send_packet_hdr_len); -+ -+ update = g_new0(struct kvm_sev_send_update_data, 1); -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, size); -+ -+ update->hdr_uaddr = (unsigned long)packet_hdr; -+ update->hdr_len = s->send_packet_hdr_len; -+ update->guest_uaddr = (unsigned long)ptr; -+ update->guest_len = size; -+ update->trans_uaddr = (unsigned long)trans; -+ update->trans_len = size; -+ -+ new_node = csv_batch_cmd_list_node_create((uint64_t)update, addr); -+ if (!new_node) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ if (s->csv_batch_cmd_list == NULL) { -+ s->csv_batch_cmd_list = csv_batch_cmd_list_create(new_node, -+ send_update_data_free); -+ if (s->csv_batch_cmd_list == NULL) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ } else { -+ /* Add new_node's command address to the last_node */ -+ csv_batch_cmd_list_add_after(s->csv_batch_cmd_list, new_node); -+ } -+ -+ trace_kvm_sev_send_update_data(ptr, trans, size); -+ -+ return ret; -+ -+err: -+ g_free(trans); -+ g_free(update); -+ g_free(packet_hdr); -+ g_free(new_node); -+ if (s->csv_batch_cmd_list) { -+ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); -+ s->csv_batch_cmd_list = NULL; -+ } -+ return ret; -+} -+ -+int -+csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* Only support for HYGON CSV */ -+ if (!is_hygon_cpu()) { -+ error_report("Only support enqueue pages for HYGON CSV"); -+ return -EINVAL; -+ } -+ -+ return csv_send_queue_data(s, ptr, sz, addr); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 7e53f8461..1eba67bcf 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -74,6 +74,8 @@ void sev_del_migrate_blocker(void); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - -+int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); -+ - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); - const char *(*fw_error_to_str)(int code); --- -2.31.1 - diff --git a/1058-anolis-target-i386-csv-add-support-to-encrypt-the-ou.patch b/1058-anolis-target-i386-csv-add-support-to-encrypt-the-ou.patch deleted file mode 100644 index 393b474..0000000 --- a/1058-anolis-target-i386-csv-add-support-to-encrypt-the-ou.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 500646168eb4dc297d01dbc35759e38d0206a3b6 Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 11:41:58 +0800 -Subject: [PATCH 21/29] anolis: target/i386: csv: add support to encrypt the - outgoing pages in the list queued before. - -The csv_save_queued_outgoing_pages() provide the implementation to encrypt -the guest private pages during transmission. The routines uses SEND_START -command to create the outgoing encryption context on the first call then -uses COMMAND_BATCH command to send the SEND_UPDATE_DATA commands queued -in the list to encrypt the data before writing it to the socket. While -encrypting the data SEND_UPDATE_DATA produces some metadata (e.g MAC, IV). -The metadata is also sent to the target machine. After migration is completed, -we issue the SEND_FINISH command to transition the SEV guest state from sending -to unrunnable state. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 4 + - linux-headers/linux/kvm.h | 8 ++ - target/i386/sev.c | 89 +++++++++++++++++++++++ - target/i386/sev.h | 4 + - 4 files changed, 105 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 1f32519d4..1ff4823b6 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -80,6 +80,10 @@ struct ConfidentialGuestMemoryEncryptionOps { - - /* Queue the encrypted page and metadata associated with it into a list */ - int (*queue_outgoing_page)(uint8_t *ptr, uint32_t size, uint64_t addr); -+ -+ /* Write the list queued with encrypted pages and metadata associated -+ * with them */ -+ int (*save_queued_outgoing_pages)(QEMUFile *f, uint64_t *bytes_sent); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 8dd8c5e6a..951afc8b2 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1823,6 +1823,9 @@ enum sev_cmd_id { - /* Guest Migration Extension */ - KVM_SEV_SEND_CANCEL, - -+ /* Hygon CSV batch command */ -+ KVM_CSV_COMMAND_BATCH = 0x18, -+ - KVM_SEV_NR_MAX, - }; - -@@ -1944,6 +1947,11 @@ struct kvm_csv_batch_list_node { - __u64 next_cmd_addr; - }; - -+struct kvm_csv_command_batch { -+ __u32 command_id; -+ __u64 csv_batch_list_uaddr; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) -diff --git a/target/i386/sev.c b/target/i386/sev.c -index e7ff3f4dd..6ff547a23 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -201,6 +201,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - .queue_outgoing_page = csv_queue_outgoing_page, -+ .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, - }; - - static int -@@ -1987,6 +1988,70 @@ err: - return ret; - } - -+static int -+csv_command_batch(uint32_t cmd_id, uint64_t head_uaddr, int *fw_err) -+{ -+ int ret; -+ struct kvm_csv_command_batch command_batch = { }; -+ -+ command_batch.command_id = cmd_id; -+ command_batch.csv_batch_list_uaddr = head_uaddr; -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_CSV_COMMAND_BATCH, -+ &command_batch, fw_err); -+ if (ret) { -+ error_report("%s: COMMAND_BATCH ret=%d fw_err=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ } -+ -+ return ret; -+} -+ -+static int -+csv_send_update_data_batch(SevGuestState *s, QEMUFile *f, uint64_t *bytes_sent) -+{ -+ int ret, fw_error = 0; -+ struct kvm_sev_send_update_data *update; -+ struct kvm_csv_batch_list_node *node; -+ -+ ret = csv_command_batch(KVM_SEV_SEND_UPDATE_DATA, -+ (uint64_t)s->csv_batch_cmd_list->head, &fw_error); -+ if (ret) { -+ error_report("%s: csv_command_batch ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ *bytes_sent = 0; -+ for (node = s->csv_batch_cmd_list->head; -+ node != NULL; -+ node = (struct kvm_csv_batch_list_node *)node->next_cmd_addr) { -+ if (node != s->csv_batch_cmd_list->head) { -+ /* head's page header is saved before send_update_data */ -+ qemu_put_be64(f, node->addr); -+ *bytes_sent += 8; -+ if (node->next_cmd_addr != 0) -+ qemu_put_be32(f, RAM_SAVE_ENCRYPTED_PAGE_BATCH); -+ else -+ qemu_put_be32(f, RAM_SAVE_ENCRYPTED_PAGE_BATCH_END); -+ *bytes_sent += 4; -+ } -+ update = (struct kvm_sev_send_update_data *)node->cmd_data_addr; -+ qemu_put_be32(f, update->hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update->hdr_uaddr, update->hdr_len); -+ *bytes_sent += (4 + update->hdr_len); -+ -+ qemu_put_be32(f, update->trans_len); -+ qemu_put_buffer(f, (uint8_t *)update->trans_uaddr, update->trans_len); -+ *bytes_sent += (4 + update->trans_len); -+ } -+ -+err: -+ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); -+ s->csv_batch_cmd_list = NULL; -+ return ret; -+} -+ - int - csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) - { -@@ -2001,6 +2066,30 @@ csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) - return csv_send_queue_data(s, ptr, sz, addr); - } - -+int -+csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* Only support for HYGON CSV */ -+ if (!is_hygon_cpu()) { -+ error_report("Only support transfer queued pages for HYGON CSV"); -+ return -EINVAL; -+ } -+ -+ /* -+ * If this is a first buffer then create outgoing encryption context -+ * and write our PDH, policy and session data. -+ */ -+ if (!sev_check_state(s, SEV_STATE_SEND_UPDATE) && -+ sev_send_start(s, f, bytes_sent)) { -+ error_report("Failed to create outgoing context"); -+ return 1; -+ } -+ -+ return csv_send_update_data_batch(s, f, bytes_sent); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 1eba67bcf..37ed17f32 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -41,6 +41,9 @@ typedef struct SevKernelLoaderContext { - #define RAM_SAVE_ENCRYPTED_PAGE 0x1 - #define RAM_SAVE_SHARED_REGIONS_LIST 0x2 - -+#define RAM_SAVE_ENCRYPTED_PAGE_BATCH 0x4 -+#define RAM_SAVE_ENCRYPTED_PAGE_BATCH_END 0x5 -+ - #ifdef CONFIG_SEV - bool sev_enabled(void); - bool sev_es_enabled(void); -@@ -75,6 +78,7 @@ void sev_del_migrate_blocker(void); - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - - int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); -+int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); --- -2.31.1 - diff --git a/1059-anolis-target-i386-csv-add-support-to-queue-the-inco.patch b/1059-anolis-target-i386-csv-add-support-to-queue-the-inco.patch deleted file mode 100644 index cc70aac..0000000 --- a/1059-anolis-target-i386-csv-add-support-to-queue-the-inco.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 8af625f3b5f4d2eb768b1eee2dc2e7938800d47e Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 13:49:48 +0800 -Subject: [PATCH 22/29] anolis: target/i386: csv: add support to queue the - incoming page into a list - -The csv_queue_incoming_page() provide the implementation to queue the -guest private pages during transmission. The routines queues the incoming -socket which contains the guest private pages into a list then uses the -COMMAND_BATCH command to load the encrypted pages into the guest memory. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 3 + - target/i386/sev.c | 92 +++++++++++++++++++++++ - target/i386/sev.h | 1 + - 3 files changed, 96 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 1ff4823b6..530b5057b 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -84,6 +84,9 @@ struct ConfidentialGuestMemoryEncryptionOps { - /* Write the list queued with encrypted pages and metadata associated - * with them */ - int (*save_queued_outgoing_pages)(QEMUFile *f, uint64_t *bytes_sent); -+ -+ /* Queue the incoming encrypted page into a list */ -+ int (*queue_incoming_page)(QEMUFile *f, uint8_t *ptr); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 6ff547a23..e235fb207 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -202,6 +202,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - .queue_outgoing_page = csv_queue_outgoing_page, - .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, -+ .queue_incoming_page = csv_queue_incoming_page, - }; - - static int -@@ -1916,6 +1917,15 @@ static void send_update_data_free(void *data) - g_free(update); - } - -+static void receive_update_data_free(void *data) -+{ -+ struct kvm_sev_receive_update_data *update = -+ (struct kvm_sev_receive_update_data *)data; -+ g_free((guchar *)update->hdr_uaddr); -+ g_free((guchar *)update->trans_uaddr); -+ g_free(update); -+} -+ - static int - csv_send_queue_data(SevGuestState *s, uint8_t *ptr, - uint32_t size, uint64_t addr) -@@ -1988,6 +1998,66 @@ err: - return ret; - } - -+static int -+csv_receive_queue_data(SevGuestState *s, QEMUFile *f, uint8_t *ptr) -+{ -+ int ret = 0; -+ gchar *hdr = NULL, *trans = NULL; -+ struct kvm_sev_receive_update_data *update; -+ struct kvm_csv_batch_list_node *new_node = NULL; -+ -+ update = g_new0(struct kvm_sev_receive_update_data, 1); -+ /* get packet header */ -+ update->hdr_len = qemu_get_be32(f); -+ hdr = g_new(gchar, update->hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update->hdr_len); -+ update->hdr_uaddr = (unsigned long)hdr; -+ -+ /* get transport buffer */ -+ update->trans_len = qemu_get_be32(f); -+ trans = g_new(gchar, update->trans_len); -+ update->trans_uaddr = (unsigned long)trans; -+ qemu_get_buffer(f, (uint8_t *)update->trans_uaddr, update->trans_len); -+ -+ /* set guest address,guest len is page_size */ -+ update->guest_uaddr = (uint64_t)ptr; -+ update->guest_len = TARGET_PAGE_SIZE; -+ -+ new_node = csv_batch_cmd_list_node_create((uint64_t)update, 0); -+ if (!new_node) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ if (s->csv_batch_cmd_list == NULL) { -+ s->csv_batch_cmd_list = csv_batch_cmd_list_create(new_node, -+ receive_update_data_free); -+ if (s->csv_batch_cmd_list == NULL) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ } else { -+ /* Add new_node's command address to the last_node */ -+ csv_batch_cmd_list_add_after(s->csv_batch_cmd_list, new_node); -+ } -+ -+ trace_kvm_sev_receive_update_data(trans, (void *)ptr, update->guest_len, -+ (void *)hdr, update->hdr_len); -+ -+ return ret; -+ -+err: -+ g_free(trans); -+ g_free(update); -+ g_free(hdr); -+ g_free(new_node); -+ if (s->csv_batch_cmd_list) { -+ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); -+ s->csv_batch_cmd_list = NULL; -+ } -+ return ret; -+} -+ - static int - csv_command_batch(uint32_t cmd_id, uint64_t head_uaddr, int *fw_err) - { -@@ -2066,6 +2136,28 @@ csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) - return csv_send_queue_data(s, ptr, sz, addr); - } - -+int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* Only support for HYGON CSV */ -+ if (!is_hygon_cpu()) { -+ error_report("Only support enqueue received pages for HYGON CSV"); -+ return -EINVAL; -+ } -+ -+ /* -+ * If this is first buffer and SEV is not in recieiving state then -+ * use RECEIVE_START command to create a encryption context. -+ */ -+ if (!sev_check_state(s, SEV_STATE_RECEIVE_UPDATE) && -+ sev_receive_start(s, f)) { -+ return 1; -+ } -+ -+ return csv_receive_queue_data(s, f, ptr); -+} -+ - int - csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) - { -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 37ed17f32..6166be420 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -79,6 +79,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - - int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); -+int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr); - - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); --- -2.31.1 - diff --git a/1060-anolis-target-i386-csv-add-support-to-load-incoming-.patch b/1060-anolis-target-i386-csv-add-support-to-load-incoming-.patch deleted file mode 100644 index f54f872..0000000 --- a/1060-anolis-target-i386-csv-add-support-to-load-incoming-.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 8949b2ac9cc6d9a59a482ca76f81a417c9c38e6d Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 14:11:43 +0800 -Subject: [PATCH 23/29] anolis: target/i386: csv: add support to load incoming - encrypted pages queued in the CMD list - -The csv_load_queued_incoming_pages() provide the implementation to read the -incoming guest private pages from the socket queued in the CMD list and load -them into the guest memory. The routines uses the RECEIVE_START command to -create the incoming encryption context on the first call then uses the -COMMAND_BATCH carried with RECEIEVE_UPDATE_DATA commands to load the encrypted -pages into the guest memory. After migration is completed, we issue the -RECEIVE_FINISH command to transition the SEV guest to the runnable state -so that it can be executed. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 3 +++ - target/i386/sev.c | 32 +++++++++++++++++++++++ - target/i386/sev.h | 1 + - 3 files changed, 36 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 530b5057b..f6a30fab3 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -87,6 +87,9 @@ struct ConfidentialGuestMemoryEncryptionOps { - - /* Queue the incoming encrypted page into a list */ - int (*queue_incoming_page)(QEMUFile *f, uint8_t *ptr); -+ -+ /* Load the incoming encrypted pages queued in list into guest memory */ -+ int (*load_queued_incoming_pages)(QEMUFile *f); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/target/i386/sev.c b/target/i386/sev.c -index e235fb207..2f7d98be6 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -203,6 +203,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .queue_outgoing_page = csv_queue_outgoing_page, - .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, - .queue_incoming_page = csv_queue_incoming_page, -+ .load_queued_incoming_pages = csv_load_queued_incoming_pages, - }; - - static int -@@ -2122,6 +2123,24 @@ err: - return ret; - } - -+static int -+csv_receive_update_data_batch(SevGuestState *s) -+{ -+ int ret; -+ int fw_error; -+ -+ ret = csv_command_batch(KVM_SEV_RECEIVE_UPDATE_DATA, -+ (uint64_t)s->csv_batch_cmd_list->head, &fw_error); -+ if (ret) { -+ error_report("%s: csv_command_batch ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ } -+ -+ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); -+ s->csv_batch_cmd_list = NULL; -+ return ret; -+} -+ - int - csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) - { -@@ -2182,6 +2201,19 @@ csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) - return csv_send_update_data_batch(s, f, bytes_sent); - } - -+int csv_load_queued_incoming_pages(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* Only support for HYGON CSV */ -+ if (!is_hygon_cpu()) { -+ error_report("Only support load queued pages for HYGON CSV"); -+ return -EINVAL; -+ } -+ -+ return csv_receive_update_data_batch(s); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 6166be420..c53f96b04 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -80,6 +80,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr); -+int csv_load_queued_incoming_pages(QEMUFile *f); - - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); --- -2.31.1 - diff --git a/1061-anolis-migration-ram-Accelerate-the-transmission-of-.patch b/1061-anolis-migration-ram-Accelerate-the-transmission-of-.patch deleted file mode 100644 index a065a0e..0000000 --- a/1061-anolis-migration-ram-Accelerate-the-transmission-of-.patch +++ /dev/null @@ -1,229 +0,0 @@ -From 379463820571f9ca239e68f2f5f588634b96bbff Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 14:35:51 +0800 -Subject: [PATCH 24/29] anolis: migration/ram: Accelerate the transmission of - CSV guest's encrypted pages - -When memory encryption is enabled, the guest memory will be encrypted with -the guest specific key. The patch introduces an accelerate solution which -queued the pages into list and send them togather by COMMAND_BATCH. - -Signed-off-by: hanliyang ---- - configs/devices/i386-softmmu/default.mak | 1 + - hw/i386/Kconfig | 5 ++ - migration/ram.c | 106 +++++++++++++++++++++++ - target/i386/csv.h | 11 +++ - target/i386/sev.h | 1 + - 5 files changed, 124 insertions(+) - -diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak -index db83ffcab..e948e54e4 100644 ---- a/configs/devices/i386-softmmu/default.mak -+++ b/configs/devices/i386-softmmu/default.mak -@@ -24,6 +24,7 @@ - #CONFIG_VTD=n - #CONFIG_SGX=n - #CONFIG_CSV=n -+#CONFIG_HYGON_CSV_MIG_ACCEL=n - - # Boards: - # -diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig -index ed35d762b..8876b360b 100644 ---- a/hw/i386/Kconfig -+++ b/hw/i386/Kconfig -@@ -4,6 +4,7 @@ config X86_FW_OVMF - config SEV - bool - select X86_FW_OVMF -+ select HYGON_CSV_MIG_ACCEL - depends on KVM - - config SGX -@@ -14,6 +15,10 @@ config CSV - bool - depends on SEV - -+config HYGON_CSV_MIG_ACCEL -+ bool -+ depends on SEV -+ - config PC - bool - imply APPLESMC -diff --git a/migration/ram.c b/migration/ram.c -index 33e2c9d5f..7e2d4e7df 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -59,6 +59,7 @@ - - /* Defines RAM_SAVE_ENCRYPTED_PAGE and RAM_SAVE_SHARED_REGION_LIST */ - #include "target/i386/sev.h" -+#include "target/i386/csv.h" - #include "sysemu/kvm.h" - - #include "hw/boards.h" /* for machine_dump_guest_core() */ -@@ -2348,6 +2349,99 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, - return ram_save_page(rs, pss, last_stage); - } - -+#ifdef CONFIG_HYGON_CSV_MIG_ACCEL -+/** -+ * ram_save_encrypted_pages_in_batch - send the given encrypted pages to -+ * the stream. -+ */ -+static int -+ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss, bool last_stage) -+{ -+ int ret; -+ int tmppages = 0, pages = 0; -+ RAMBlock *block = pss->block; -+ ram_addr_t offset = pss->page << TARGET_PAGE_BITS; -+ ram_addr_t start_offset = 0; -+ uint32_t host_len = 0; -+ uint8_t *p; -+ uint64_t bytes_xmit; -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *)object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ do { -+ /* Check the pages is dirty and if it is send it */ -+ if (!migration_bitmap_clear_dirty(rs, block, pss->page)) { -+ pss->page++; -+ continue; -+ } -+ -+ /* Process the unencrypted page */ -+ if (!encrypted_test_list(rs, block, pss->page)) { -+ tmppages = ram_save_target_page(rs, pss, last_stage); -+ } else { -+ /* Caculate the offset and host virtual address of the page */ -+ offset = pss->page << TARGET_PAGE_BITS; -+ p = block->host + offset; -+ -+ /* Record the offset and host virtual address of the first -+ * page in this loop which will be used below. -+ */ -+ if (host_len == 0) { -+ start_offset = offset | RAM_SAVE_FLAG_ENCRYPTED_DATA; -+ } else { -+ offset |= (RAM_SAVE_FLAG_ENCRYPTED_DATA | RAM_SAVE_FLAG_CONTINUE); -+ } -+ -+ /* Queue the outgoing page if the page is not zero page. -+ * If the queued pages are up to the outgoing page window size, -+ * process them below. -+ */ -+ if (ops->queue_outgoing_page(p, TARGET_PAGE_SIZE, offset)) -+ return -1; -+ -+ tmppages = 1; -+ host_len += TARGET_PAGE_SIZE; -+ ram_counters.normal++; -+ } -+ -+ if (tmppages < 0) { -+ return tmppages; -+ } -+ -+ pages += tmppages; -+ -+ pss->page++; -+ } while (offset_in_ramblock(block, pss->page << TARGET_PAGE_BITS) && -+ host_len < CSV_OUTGOING_PAGE_WINDOW_SIZE); -+ -+ /* Check if there are any queued pages */ -+ if (host_len != 0) { -+ ram_counters.transferred += -+ save_page_header(rs, rs->f, block, start_offset); -+ /* if only one page queued, flag is BATCH_END, else flag is BATCH */ -+ if (host_len > TARGET_PAGE_SIZE) -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_PAGE_BATCH); -+ else -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_PAGE_BATCH_END); -+ ram_counters.transferred += 4; -+ /* Process the queued pages in batch */ -+ ret = ops->save_queued_outgoing_pages(rs->f, &bytes_xmit); -+ if (ret) { -+ return -1; -+ } -+ ram_counters.transferred += bytes_xmit; -+ } -+ -+ /* The offset we leave with is the last one we looked at */ -+ pss->page--; -+ -+ return pages; -+} -+#endif -+ - /** - * ram_save_host_page: save a whole host page - * -@@ -2382,6 +2476,18 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, - return 0; - } - -+#ifdef CONFIG_HYGON_CSV_MIG_ACCEL -+ /* -+ * If command_batch function is enabled and memory encryption is enabled -+ * then use command batch APIs to accelerate the sending process -+ * to write the outgoing buffer to the wire. The encryption APIs -+ * will re-encrypt the data with transport key so that data is prototect -+ * on the wire. -+ */ -+ if (memcrypt_enabled() && is_hygon_cpu() && !migration_in_postcopy()) -+ return ram_save_encrypted_pages_in_batch(rs, pss, last_stage); -+#endif -+ - do { - /* Check the pages is dirty and if it is send it */ - if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 4f5b2773c..e51cc8302 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -16,6 +16,8 @@ - - #include "qapi/qapi-commands-misc-target.h" - -+#ifdef CONFIG_SEV -+ - #include "cpu.h" - - #define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ -@@ -38,6 +40,15 @@ static __attribute__((unused)) bool is_hygon_cpu(void) - return false; - } - -+#else -+ -+static __attribute__((unused)) bool is_hygon_cpu(void) -+{ -+ return false; -+} -+ -+#endif -+ - #ifdef CONFIG_CSV - bool csv_enabled(void); - #else -diff --git a/target/i386/sev.h b/target/i386/sev.h -index c53f96b04..345dffac5 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -43,6 +43,7 @@ typedef struct SevKernelLoaderContext { - - #define RAM_SAVE_ENCRYPTED_PAGE_BATCH 0x4 - #define RAM_SAVE_ENCRYPTED_PAGE_BATCH_END 0x5 -+#define CSV_OUTGOING_PAGE_WINDOW_SIZE (4094 * TARGET_PAGE_SIZE) - - #ifdef CONFIG_SEV - bool sev_enabled(void); --- -2.31.1 - diff --git a/1062-anolis-migration-ram-Accelerate-the-loading-of-CSV-g.patch b/1062-anolis-migration-ram-Accelerate-the-loading-of-CSV-g.patch deleted file mode 100644 index 56c11eb..0000000 --- a/1062-anolis-migration-ram-Accelerate-the-loading-of-CSV-g.patch +++ /dev/null @@ -1,37 +0,0 @@ -From e9b70bcaf165cb163304ba68a1b1db078489d9e0 Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 14:49:45 +0800 -Subject: [PATCH 25/29] anolis: migration/ram: Accelerate the loading of CSV - guest's encrypted pages - -When memory encryption is enabled, the guest memory will be encrypted with -the guest specific key. The patch introduces an accelerate solution which -queued the pages into list and load them togather by COMMAND_BATCH. - -Signed-off-by: hanliyang ---- - migration/ram.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 7e2d4e7df..90f1bda83 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1387,6 +1387,14 @@ static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) - return ops->load_incoming_page(f, ptr); - } else if (flag == RAM_SAVE_SHARED_REGIONS_LIST) { - return ops->load_incoming_shared_regions_list(f); -+ } else if (flag == RAM_SAVE_ENCRYPTED_PAGE_BATCH) { -+ return ops->queue_incoming_page(f, ptr); -+ } else if (flag == RAM_SAVE_ENCRYPTED_PAGE_BATCH_END) { -+ if (ops->queue_incoming_page(f, ptr)) { -+ error_report("Failed to queue incoming data"); -+ return -EINVAL; -+ } -+ return ops->load_queued_incoming_pages(f); - } else { - error_report("unknown encrypted flag %x", flag); - return 1; --- -2.31.1 - diff --git a/1063-anolis-target-i386-csv-Add-support-for-migrate-VMSA-.patch b/1063-anolis-target-i386-csv-Add-support-for-migrate-VMSA-.patch deleted file mode 100644 index 166fb58..0000000 --- a/1063-anolis-target-i386-csv-Add-support-for-migrate-VMSA-.patch +++ /dev/null @@ -1,416 +0,0 @@ -From 133fe2e6a250623ccc9305fdacc1e8d990878fb4 Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Tue, 7 Jun 2022 15:19:32 +0800 -Subject: [PATCH 26/29] anolis: target/i386/csv: Add support for migrate VMSA - for CSV2 guest - -CSV2 can protect guest's cpu state through memory encryption. Each -vcpu has its corresponding memory, which is also called VMSA, and -is encrypted by guest's specific encrytion key. - -When CSV2 guest exit to host, the vcpu's state will be encrypted -and saved to VMSA, and the VMSA will be decrypted and loaded to cpu -when the guest's vcpu running at next time. - -If user wants to migrate one CSV2 guest to target machine, the VMSA -of the vcpus also should be migrated to target. CSV firmware provides -SEND_UPDATE_VMSA/RECEIVE_UPDATE_VMSA API through which VMSA can be -converted into secure data and transmitted to the remote end (for -example, network transmission). - -The migration of cpu state is identified by CPUState.cpu_index which -may not equals to vcpu id from KVM's perspective. - -When migrate the VMSA, the source QEMU will invoke SEND_UPDATE_VMSA to -generate data correspond to VMSA, after target QEMU received the data, -it will calc target vcpu id in the KVM by CPUState.cpu_index, and then -invoke RECEIVE_UPDATE_VMSA to restore VMSA correspond to vcpu. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 6 + - linux-headers/linux/kvm.h | 16 ++ - migration/ram.c | 30 ++++ - target/i386/sev.c | 196 ++++++++++++++++++++++ - target/i386/sev.h | 3 + - target/i386/trace-events | 2 + - 6 files changed, 253 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index f6a30fab3..a069bad9d 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -90,6 +90,12 @@ struct ConfidentialGuestMemoryEncryptionOps { - - /* Load the incoming encrypted pages queued in list into guest memory */ - int (*load_queued_incoming_pages)(QEMUFile *f); -+ -+ /* Write the encrypted cpu state */ -+ int (*save_outgoing_cpu_state)(QEMUFile *f); -+ -+ /* Load the encrypted cpu state */ -+ int (*load_incoming_cpu_state)(QEMUFile *f); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 951afc8b2..e5d282c75 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1904,6 +1904,14 @@ struct kvm_sev_send_update_data { - __u32 trans_len; - }; - -+struct kvm_sev_send_update_vmsa { -+ __u32 vcpu_id; -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ - struct kvm_sev_receive_start { - __u32 handle; - __u32 policy; -@@ -1922,6 +1930,14 @@ struct kvm_sev_receive_update_data { - __u32 trans_len; - }; - -+struct kvm_sev_receive_update_vmsa { -+ __u32 vcpu_id; -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ - /* CSV command */ - enum csv_cmd_id { - KVM_CSV_NR_MIN = 0xc0, -diff --git a/migration/ram.c b/migration/ram.c -index 90f1bda83..8c61eecb9 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1371,6 +1371,23 @@ static int ram_save_shared_region_list(RAMState *rs, QEMUFile *f) - return ops->save_outgoing_shared_regions_list(rs->f); - } - -+/** -+ * ram_save_encrypted_cpu_state: send the encrypted cpu state -+ */ -+static int ram_save_encrypted_cpu_state(RAMState *rs, QEMUFile *f) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ save_page_header(rs, rs->f, rs->last_seen_block, -+ RAM_SAVE_FLAG_ENCRYPTED_DATA); -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_CPU_STATE); -+ return ops->save_outgoing_cpu_state(rs->f); -+} -+ - static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) - { - MachineState *ms = MACHINE(qdev_get_machine()); -@@ -1395,6 +1412,8 @@ static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) - return -EINVAL; - } - return ops->load_queued_incoming_pages(f); -+ } else if (flag == RAM_SAVE_ENCRYPTED_CPU_STATE) { -+ return ops->load_incoming_cpu_state(f); - } else { - error_report("unknown encrypted flag %x", flag); - return 1; -@@ -3507,6 +3526,17 @@ static int ram_save_complete(QEMUFile *f, void *opaque) - if (memcrypt_enabled()) { - ret = ram_save_shared_region_list(rs, f); - } -+ -+ /* -+ * send the encrypted cpu state, for example, CSV2 guest's -+ * vmsa for each vcpu. -+ */ -+ if (!ret && memcrypt_enabled() && is_hygon_cpu()) { -+ ret = ram_save_encrypted_cpu_state(rs, f); -+ if (ret) { -+ error_report("Failed to save encrypted cpu state"); -+ } -+ } - } - - if (ret < 0) { -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 2f7d98be6..9cdf3e6bf 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -100,6 +100,10 @@ struct SevGuestState { - gchar *send_packet_hdr; - size_t send_packet_hdr_len; - -+ /* needed by live migration of HYGON CSV2 guest */ -+ gchar *send_vmsa_packet_hdr; -+ size_t send_vmsa_packet_hdr_len; -+ - uint32_t reset_cs; - uint32_t reset_ip; - bool reset_data_valid; -@@ -193,6 +197,9 @@ static const char *const sev_fw_errlist[] = { - #define SHARED_REGION_LIST_CONT 0x1 - #define SHARED_REGION_LIST_END 0x2 - -+#define ENCRYPTED_CPU_STATE_CONT 0x1 -+#define ENCRYPTED_CPU_STATE_END 0x2 -+ - static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = sev_save_outgoing_page, -@@ -204,6 +211,8 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, - .queue_incoming_page = csv_queue_incoming_page, - .load_queued_incoming_pages = csv_load_queued_incoming_pages, -+ .save_outgoing_cpu_state = csv_save_outgoing_cpu_state, -+ .load_incoming_cpu_state = csv_load_incoming_cpu_state, - }; - - static int -@@ -1020,6 +1029,9 @@ sev_send_finish(void) - } - - g_free(sev_guest->send_packet_hdr); -+ if (sev_es_enabled() && is_hygon_cpu()) { -+ g_free(sev_guest->send_vmsa_packet_hdr); -+ } - sev_set_guest_state(sev_guest, SEV_STATE_RUNNING); - } - -@@ -2214,6 +2226,190 @@ int csv_load_queued_incoming_pages(QEMUFile *f) - return csv_receive_update_data_batch(s); - } - -+static int -+sev_send_vmsa_get_packet_len(int *fw_err) -+{ -+ int ret; -+ struct kvm_sev_send_update_vmsa update = { 0, }; -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_UPDATE_VMSA, -+ &update, fw_err); -+ if (*fw_err != SEV_RET_INVALID_LEN) { -+ ret = -1; -+ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ goto err; -+ } -+ -+ ret = update.hdr_len; -+ -+err: -+ return ret; -+} -+ -+static int -+sev_send_update_vmsa(SevGuestState *s, QEMUFile *f, uint32_t cpu_id, -+ uint32_t cpu_index, uint32_t size) -+{ -+ int ret, fw_error; -+ guchar *trans = NULL; -+ struct kvm_sev_send_update_vmsa update = {}; -+ -+ /* -+ * If this is first call then query the packet header bytes and allocate -+ * the packet buffer. -+ */ -+ if (!s->send_vmsa_packet_hdr) { -+ s->send_vmsa_packet_hdr_len = sev_send_vmsa_get_packet_len(&fw_error); -+ if (s->send_vmsa_packet_hdr_len < 1) { -+ error_report("%s: SEND_UPDATE_VMSA fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ -+ s->send_vmsa_packet_hdr = g_new(gchar, s->send_vmsa_packet_hdr_len); -+ } -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, size); -+ -+ update.vcpu_id = cpu_id; -+ update.hdr_uaddr = (uintptr_t)s->send_vmsa_packet_hdr; -+ update.hdr_len = s->send_vmsa_packet_hdr_len; -+ update.trans_uaddr = (uintptr_t)trans; -+ update.trans_len = size; -+ -+ trace_kvm_sev_send_update_vmsa(cpu_id, cpu_index, trans, size); -+ -+ ret = sev_ioctl(s->sev_fd, KVM_SEV_SEND_UPDATE_VMSA, &update, &fw_error); -+ if (ret) { -+ error_report("%s: SEND_UPDATE_VMSA ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ /* -+ * Migration of vCPU's VMState according to the instance_id -+ * (i.e. CPUState.cpu_index) -+ */ -+ qemu_put_be32(f, sizeof(uint32_t)); -+ qemu_put_buffer(f, (uint8_t *)&cpu_index, sizeof(uint32_t)); -+ -+ qemu_put_be32(f, update.hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); -+ -+ qemu_put_be32(f, update.trans_len); -+ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+err: -+ g_free(trans); -+ return ret; -+} -+ -+int csv_save_outgoing_cpu_state(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ CPUState *cpu; -+ int ret = 0; -+ -+ /* Only support migrate VMSAs for HYGON CSV2 guest */ -+ if (!sev_es_enabled() || !is_hygon_cpu()) { -+ return 0; -+ } -+ -+ CPU_FOREACH(cpu) { -+ qemu_put_be32(f, ENCRYPTED_CPU_STATE_CONT); -+ ret = sev_send_update_vmsa(s, f, kvm_arch_vcpu_id(cpu), -+ cpu->cpu_index, TARGET_PAGE_SIZE); -+ if (ret) { -+ goto err; -+ } -+ } -+ -+ qemu_put_be32(f, ENCRYPTED_CPU_STATE_END); -+ -+err: -+ return ret; -+} -+ -+static int sev_receive_update_vmsa(QEMUFile *f) -+{ -+ int ret = 1, fw_error = 0; -+ CPUState *cpu; -+ uint32_t cpu_index, cpu_id = 0; -+ gchar *hdr = NULL, *trans = NULL; -+ struct kvm_sev_receive_update_vmsa update = {}; -+ -+ /* get cpu index buffer */ -+ assert(qemu_get_be32(f) == sizeof(uint32_t)); -+ qemu_get_buffer(f, (uint8_t *)&cpu_index, sizeof(uint32_t)); -+ -+ CPU_FOREACH(cpu) { -+ if (cpu->cpu_index == cpu_index) { -+ cpu_id = kvm_arch_vcpu_id(cpu); -+ break; -+ } -+ } -+ update.vcpu_id = cpu_id; -+ -+ /* get packet header */ -+ update.hdr_len = qemu_get_be32(f); -+ if (!check_blob_length(update.hdr_len)) { -+ return 1; -+ } -+ -+ hdr = g_new(gchar, update.hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); -+ update.hdr_uaddr = (uintptr_t)hdr; -+ -+ /* get transport buffer */ -+ update.trans_len = qemu_get_be32(f); -+ if (!check_blob_length(update.trans_len)) { -+ goto err; -+ } -+ -+ trans = g_new(gchar, update.trans_len); -+ update.trans_uaddr = (uintptr_t)trans; -+ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+ trace_kvm_sev_receive_update_vmsa(cpu_id, cpu_index, -+ trans, update.trans_len, hdr, update.hdr_len); -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_RECEIVE_UPDATE_VMSA, -+ &update, &fw_error); -+ if (ret) { -+ error_report("Error RECEIVE_UPDATE_VMSA ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ } -+ -+err: -+ g_free(trans); -+ g_free(hdr); -+ return ret; -+} -+ -+int csv_load_incoming_cpu_state(QEMUFile *f) -+{ -+ int status, ret = 0; -+ -+ /* Only support migrate VMSAs for HYGON CSV2 guest */ -+ if (!sev_es_enabled() || !is_hygon_cpu()) { -+ return 0; -+ } -+ -+ status = qemu_get_be32(f); -+ while (status == ENCRYPTED_CPU_STATE_CONT) { -+ ret = sev_receive_update_vmsa(f); -+ if (ret) { -+ break; -+ } -+ -+ status = qemu_get_be32(f); -+ } -+ -+ return ret; -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 345dffac5..8b38567c3 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -44,6 +44,7 @@ typedef struct SevKernelLoaderContext { - #define RAM_SAVE_ENCRYPTED_PAGE_BATCH 0x4 - #define RAM_SAVE_ENCRYPTED_PAGE_BATCH_END 0x5 - #define CSV_OUTGOING_PAGE_WINDOW_SIZE (4094 * TARGET_PAGE_SIZE) -+#define RAM_SAVE_ENCRYPTED_CPU_STATE 0x6 - - #ifdef CONFIG_SEV - bool sev_enabled(void); -@@ -82,6 +83,8 @@ int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr); - int csv_load_queued_incoming_pages(QEMUFile *f); -+int csv_save_outgoing_cpu_state(QEMUFile *f); -+int csv_load_incoming_cpu_state(QEMUFile *f); - - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); -diff --git a/target/i386/trace-events b/target/i386/trace-events -index e32b0319b..60a4609c0 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -17,6 +17,8 @@ kvm_sev_send_finish(void) "" - kvm_sev_receive_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p" - kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_len) "guest %p trans %p len %d hdr %p hdr_len %d" - kvm_sev_receive_finish(void) "" -+kvm_sev_send_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *dst, int len) "cpu_id %d cpu_index %d trans %p len %d" -+kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int len, void *hdr, int hdr_len) "cpu_id %d cpu_index %d trans %p len %d hdr %p hdr_len %d" - - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 --- -2.31.1 - diff --git a/1064-anolis-target-i386-get-set-migrate-GHCB-state.patch b/1064-anolis-target-i386-get-set-migrate-GHCB-state.patch deleted file mode 100644 index a58e394..0000000 --- a/1064-anolis-target-i386-get-set-migrate-GHCB-state.patch +++ /dev/null @@ -1,175 +0,0 @@ -From a95faafa015e094f7252ef35afb74933d07a9334 Mon Sep 17 00:00:00 2001 -From: panpingsheng -Date: Sat, 12 Jun 2021 15:15:29 +0800 -Subject: [PATCH 27/29] anolis: target/i386: get/set/migrate GHCB state - -GHCB state is necessary to CSV2 guest when migrating to target. - -Add GHCB related definition, it also adds corresponding part -to kvm_get/put, and vmstate. - -Signed-off-by: hanliyang ---- - include/sysemu/kvm.h | 1 + - linux-headers/linux/kvm.h | 1 + - target/i386/cpu.h | 4 ++++ - target/i386/kvm/kvm.c | 11 +++++++++++ - target/i386/machine.c | 24 ++++++++++++++++++++++++ - target/i386/sev.c | 10 ++++++++++ - 6 files changed, 51 insertions(+) - -diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h -index 7b22aeb6a..9f8099f48 100644 ---- a/include/sysemu/kvm.h -+++ b/include/sysemu/kvm.h -@@ -46,6 +46,7 @@ extern bool kvm_readonly_mem_allowed; - extern bool kvm_direct_msi_allowed; - extern bool kvm_ioeventfd_any_length_allowed; - extern bool kvm_msi_use_devid; -+extern bool kvm_has_msr_ghcb; - - #define kvm_enabled() (kvm_allowed) - /** -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index e5d282c75..4a177f81d 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1154,6 +1154,7 @@ struct kvm_ppc_resize_hpt { - #define KVM_CAP_S390_PROTECTED_DUMP 217 - #define KVM_CAP_S390_ZPCI_OP 221 - #define KVM_CAP_S390_CPU_TOPOLOGY 222 -+#define KVM_CAP_SEV_ES_GHCB 500 - - #define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) - -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 5d2ddd81b..5c476a029 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -505,6 +505,8 @@ typedef enum X86Seg { - - #define MSR_VM_HSAVE_PA 0xc0010117 - -+#define MSR_AMD64_SEV_ES_GHCB 0xc0010130 -+ - #define MSR_IA32_XFD 0x000001c4 - #define MSR_IA32_XFD_ERR 0x000001c5 - -@@ -1732,6 +1734,8 @@ typedef struct CPUX86State { - TPRAccess tpr_access_type; - - unsigned nr_dies; -+ -+ uint64_t ghcb_gpa; - } CPUX86State; - - struct kvm_msrs; -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index f0b61ec3c..fb85cc698 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -3346,6 +3346,10 @@ static int kvm_put_msrs(X86CPU *cpu, int level) - } - } - -+ if (kvm_has_msr_ghcb) { -+ kvm_msr_entry_add(cpu, MSR_AMD64_SEV_ES_GHCB, env->ghcb_gpa); -+ } -+ - return kvm_buf_set_msrs(cpu); - } - -@@ -3686,6 +3690,10 @@ static int kvm_get_msrs(X86CPU *cpu) - kvm_msr_entry_add(cpu, MSR_IA32_XFD_ERR, 0); - } - -+ if (kvm_has_msr_ghcb) { -+ kvm_msr_entry_add(cpu, MSR_AMD64_SEV_ES_GHCB, 0); -+ } -+ - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf); - if (ret < 0) { - return ret; -@@ -3991,6 +3999,9 @@ static int kvm_get_msrs(X86CPU *cpu) - case MSR_IA32_XFD_ERR: - env->msr_xfd_err = msrs[i].data; - break; -+ case MSR_AMD64_SEV_ES_GHCB: -+ env->ghcb_gpa = msrs[i].data; -+ break; - } - } - -diff --git a/target/i386/machine.c b/target/i386/machine.c -index 3977e9d8f..8aa54432d 100644 ---- a/target/i386/machine.c -+++ b/target/i386/machine.c -@@ -1497,6 +1497,27 @@ static const VMStateDescription vmstate_amx_xtile = { - }; - #endif - -+#if defined(CONFIG_KVM) && defined(TARGET_X86_64) -+static bool msr_ghcb_gpa_needed(void *opaque) -+{ -+ X86CPU *cpu = opaque; -+ CPUX86State *env = &cpu->env; -+ -+ return env->ghcb_gpa != 0; -+} -+ -+static const VMStateDescription vmstate_msr_ghcb_gpa = { -+ .name = "cpu/svm_msr_ghcb_gpa", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .needed = msr_ghcb_gpa_needed, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT64(env.ghcb_gpa, X86CPU), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+#endif -+ - const VMStateDescription vmstate_x86_cpu = { - .name = "cpu", - .version_id = 12, -@@ -1638,6 +1659,9 @@ const VMStateDescription vmstate_x86_cpu = { - &vmstate_msr_xfd, - #ifdef TARGET_X86_64 - &vmstate_amx_xtile, -+#endif -+#if defined(CONFIG_KVM) && defined(TARGET_X86_64) -+ &vmstate_msr_ghcb_gpa, - #endif - NULL - } -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 9cdf3e6bf..26b6e84d3 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -215,6 +215,8 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .load_incoming_cpu_state = csv_load_incoming_cpu_state, - }; - -+bool kvm_has_msr_ghcb; -+ - static int - sev_ioctl(int fd, int cmd, void *data, int *error) - { -@@ -1174,6 +1176,14 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; - QTAILQ_INIT(&sev->shared_regions_list); - -+ /* Determine whether support MSR_AMD64_SEV_ES_GHCB */ -+ if (sev_es_enabled()) { -+ kvm_has_msr_ghcb = -+ kvm_vm_check_extension(kvm_state, KVM_CAP_SEV_ES_GHCB); -+ } else { -+ kvm_has_msr_ghcb = false; -+ } -+ - cgs->ready = true; - - return 0; --- -2.31.1 - diff --git a/1065-anolis-target-i386-kvm-Return-resettable-when-emulat.patch b/1065-anolis-target-i386-kvm-Return-resettable-when-emulat.patch deleted file mode 100644 index 966d6ff..0000000 --- a/1065-anolis-target-i386-kvm-Return-resettable-when-emulat.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 84ea1a98ae7cb888eba8f9be9f51955a4402355c Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Sun, 19 Jun 2022 16:49:45 +0800 -Subject: [PATCH 28/29] anolis: target/i386/kvm: Return resettable when emulate - HYGON CSV2 guest - -SEV-ES guest will be terminated by QEMU when receive reboot request. -In order to support reboot for CSV2 guest, report resettable in -kvm_arch_cpu_check_are_resettable(). - -Signed-off-by: hanliyang ---- - target/i386/kvm/kvm.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index fb85cc698..19c622bb0 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -30,6 +30,7 @@ - #include "sysemu/runstate.h" - #include "kvm_i386.h" - #include "sev.h" -+#include "csv.h" - #include "hyperv.h" - #include "hyperv-proto.h" - -@@ -5363,7 +5364,7 @@ bool kvm_has_waitpkg(void) - - bool kvm_arch_cpu_check_are_resettable(void) - { -- return !sev_es_enabled(); -+ return !(sev_es_enabled() && !is_hygon_cpu()) && !csv_enabled(); - } - - #define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 --- -2.31.1 - diff --git a/1066-anolis-kvm-Add-support-for-CSV2-reboot.patch b/1066-anolis-kvm-Add-support-for-CSV2-reboot.patch deleted file mode 100644 index 3c246b0..0000000 --- a/1066-anolis-kvm-Add-support-for-CSV2-reboot.patch +++ /dev/null @@ -1,170 +0,0 @@ -From a165dedbb9121f948738e5265198410487aa7acf Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Thu, 15 Apr 2021 08:32:24 -0400 -Subject: [PATCH 29/29] anolis: kvm: Add support for CSV2 reboot - -Linux will set vcpu.arch.guest_state_protected to true after execute -LAUNCH_UPDATE_VMSA successfully, and then KVM will prevent any changes -to VMCB State Save Area. - -In order to support CSV2 guest reboot, calls cpus_control_pre_system_reset() -to set vcpu.arch.guest_state_protected to false, and calls -cpus_control_post_system_reset() to restore VMSA of guest's vcpu with -data generated by LAUNCH_UPDATE_VMSA. - -In addition, for memory encrypted guest, additional works may be -required during system reset, such as flushing the cache. The function -cpus_control_post_system_reset() hints linux to flush caches of guest -memory. - -Signed-off-by: hanliyang ---- - accel/kvm/kvm-accel-ops.c | 3 +++ - accel/kvm/kvm-all.c | 10 ++++++++++ - accel/kvm/kvm-cpus.h | 3 +++ - include/sysemu/accel-ops.h | 3 +++ - include/sysemu/cpus.h | 2 ++ - linux-headers/linux/kvm.h | 4 ++++ - softmmu/cpus.c | 14 ++++++++++++++ - softmmu/runstate.c | 4 ++++ - 8 files changed, 43 insertions(+) - -diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c -index 7516c67a3..9602f9609 100644 ---- a/accel/kvm/kvm-accel-ops.c -+++ b/accel/kvm/kvm-accel-ops.c -@@ -83,6 +83,9 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, void *data) - ops->synchronize_post_init = kvm_cpu_synchronize_post_init; - ops->synchronize_state = kvm_cpu_synchronize_state; - ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm; -+ -+ ops->control_pre_system_reset = kvm_cpus_control_pre_system_reset; -+ ops->control_post_system_reset = kvm_cpus_control_post_system_reset; - } - - static const TypeInfo kvm_accel_ops_type = { -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 6d63f0ab0..10af4170d 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -2848,6 +2848,16 @@ void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu) - run_on_cpu(cpu, do_kvm_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL); - } - -+void kvm_cpus_control_pre_system_reset(void) -+{ -+ kvm_vm_ioctl(kvm_state, KVM_CONTROL_VCPU_PRE_SYSTEM_RESET, NULL); -+} -+ -+void kvm_cpus_control_post_system_reset(void) -+{ -+ kvm_vm_ioctl(kvm_state, KVM_CONTROL_VCPU_POST_SYSTEM_RESET, NULL); -+} -+ - #ifdef KVM_HAVE_MCE_INJECTION - static __thread void *pending_sigbus_addr; - static __thread int pending_sigbus_code; -diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h -index bf0bd1bee..8ba363e0b 100644 ---- a/accel/kvm/kvm-cpus.h -+++ b/accel/kvm/kvm-cpus.h -@@ -19,4 +19,7 @@ void kvm_cpu_synchronize_post_reset(CPUState *cpu); - void kvm_cpu_synchronize_post_init(CPUState *cpu); - void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu); - -+void kvm_cpus_control_pre_system_reset(void); -+void kvm_cpus_control_post_system_reset(void); -+ - #endif /* KVM_CPUS_H */ -diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h -index 032f6979d..43893c1a4 100644 ---- a/include/sysemu/accel-ops.h -+++ b/include/sysemu/accel-ops.h -@@ -40,6 +40,9 @@ struct AccelOpsClass { - - int64_t (*get_virtual_clock)(void); - int64_t (*get_elapsed_ticks)(void); -+ -+ void (*control_pre_system_reset)(void); -+ void (*control_post_system_reset)(void); - }; - - #endif /* ACCEL_OPS_H */ -diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h -index 868f1192d..70d6e8ad3 100644 ---- a/include/sysemu/cpus.h -+++ b/include/sysemu/cpus.h -@@ -42,6 +42,8 @@ extern int icount_align_option; - void qemu_cpu_kick_self(void); - - bool cpus_are_resettable(void); -+void cpus_control_pre_system_reset(void); -+void cpus_control_post_system_reset(void); - - void cpu_synchronize_all_states(void); - void cpu_synchronize_all_post_reset(void); -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 4a177f81d..d5278df1c 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1528,6 +1528,10 @@ struct kvm_s390_ucas_mapping { - #define KVM_GET_DEVICE_ATTR _IOW(KVMIO, 0xe2, struct kvm_device_attr) - #define KVM_HAS_DEVICE_ATTR _IOW(KVMIO, 0xe3, struct kvm_device_attr) - -+/* ioctls for control vcpu setup during system reset */ -+#define KVM_CONTROL_VCPU_PRE_SYSTEM_RESET _IO(KVMIO, 0xe8) -+#define KVM_CONTROL_VCPU_POST_SYSTEM_RESET _IO(KVMIO, 0xe9) -+ - /* - * ioctls for vcpu fds - */ -diff --git a/softmmu/cpus.c b/softmmu/cpus.c -index 071085f84..319a72d92 100644 ---- a/softmmu/cpus.c -+++ b/softmmu/cpus.c -@@ -200,6 +200,20 @@ bool cpus_are_resettable(void) - return cpu_check_are_resettable(); - } - -+void cpus_control_pre_system_reset(void) -+{ -+ if (cpus_accel->control_pre_system_reset) { -+ cpus_accel->control_pre_system_reset(); -+ } -+} -+ -+void cpus_control_post_system_reset(void) -+{ -+ if (cpus_accel->control_post_system_reset) { -+ cpus_accel->control_post_system_reset(); -+ } -+} -+ - int64_t cpus_get_virtual_clock(void) - { - /* -diff --git a/softmmu/runstate.c b/softmmu/runstate.c -index 10d9b7365..4b9c9f9e0 100644 ---- a/softmmu/runstate.c -+++ b/softmmu/runstate.c -@@ -437,6 +437,8 @@ void qemu_system_reset(ShutdownCause reason) - - mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; - -+ cpus_control_pre_system_reset(); -+ - cpu_synchronize_all_states(); - - if (mc && mc->reset) { -@@ -448,6 +450,8 @@ void qemu_system_reset(ShutdownCause reason) - qapi_event_send_reset(shutdown_caused_by_guest(reason), reason); - } - cpu_synchronize_all_post_reset(); -+ -+ cpus_control_post_system_reset(); - } - - /* --- -2.31.1 - diff --git a/1067-anolis-vfio-only-map-shared-region-for-CSV-virtual-m.patch b/1067-anolis-vfio-only-map-shared-region-for-CSV-virtual-m.patch deleted file mode 100644 index 6e1d418..0000000 --- a/1067-anolis-vfio-only-map-shared-region-for-CSV-virtual-m.patch +++ /dev/null @@ -1,384 +0,0 @@ -From 3b532188e4eac7fd291cf66970126a18af024364 Mon Sep 17 00:00:00 2001 -From: liuyafei -Date: Mon, 22 May 2023 20:37:40 +0800 -Subject: [PATCH 1067/1072] anolis: vfio: only map shared region for CSV - virtual machine - -qemu vfio listener map/unmap all of the virtual machine's memory. -It does not work for CSV virtual machine, as only shared memory -should be accessed by device. - -Change-Id: I3f281c28166a36f2bed8ea193523715af9ff3271 ---- - hw/vfio/common.c | 40 +++++++++- - include/exec/memory.h | 11 +++ - softmmu/memory.c | 18 +++++ - target/i386/csv-sysemu-stub.c | 10 +++ - target/i386/csv.c | 134 ++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 12 +++ - target/i386/kvm/kvm.c | 2 + - 7 files changed, 225 insertions(+), 2 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 080046e3f5..7cc03a7ef9 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -41,6 +41,9 @@ - #include "qapi/error.h" - #include "migration/migration.h" - -+#include "target/i386/sev.h" -+#include "target/i386/csv.h" -+ - VFIOGroupList vfio_group_list = - QLIST_HEAD_INITIALIZER(vfio_group_list); - static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = -@@ -1251,6 +1254,30 @@ static void vfio_listener_log_global_stop(MemoryListener *listener) - vfio_set_dirty_page_tracking(container, false); - } - -+static SharedRegionListener *g_shl; -+static void shared_memory_listener_register(MemoryListener *listener, AddressSpace *as) -+{ -+ SharedRegionListener *shl; -+ -+ shl = g_new0(SharedRegionListener, 1); -+ -+ shl->listener = listener; -+ shl->as = as; -+ -+ shared_region_register_listener(shl); -+ g_shl = shl; -+} -+ -+static void shared_memory_listener_unregister(void) -+{ -+ SharedRegionListener *shl = g_shl; -+ -+ shared_region_unregister_listener(shl); -+ -+ g_free(shl); -+ g_shl = NULL; -+} -+ - static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, - uint64_t size, ram_addr_t ram_addr) - { -@@ -1453,7 +1480,12 @@ static const MemoryListener vfio_memory_listener = { - - static void vfio_listener_release(VFIOContainer *container) - { -- memory_listener_unregister(&container->listener); -+ if (csv_enabled()) { -+ shared_memory_listener_unregister(); -+ } else { -+ memory_listener_unregister(&container->listener); -+ } -+ - if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - memory_listener_unregister(&container->prereg_listener); - } -@@ -2183,7 +2215,11 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - - container->listener = vfio_memory_listener; - -- memory_listener_register(&container->listener, container->space->as); -+ if (csv_enabled()) { -+ shared_memory_listener_register(&container->listener, container->space->as); -+ } else { -+ memory_listener_register(&container->listener, container->space->as); -+ } - - if (container->error) { - ret = -1; -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 20f1b27377..d4bd90dfcc 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -710,6 +710,17 @@ void ram_discard_manager_register_listener(RamDiscardManager *rdm, - void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl); - -+typedef struct SharedRegionListener SharedRegionListener; -+struct SharedRegionListener { -+ MemoryListener *listener; -+ AddressSpace *as; -+ QTAILQ_ENTRY(SharedRegionListener) next; -+}; -+ -+void shared_region_register_listener(SharedRegionListener *shl); -+void shared_region_unregister_listener(SharedRegionListener *shl); -+void *shared_region_listeners_get(void); -+ - typedef struct CoalescedMemoryRange CoalescedMemoryRange; - typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd; - -diff --git a/softmmu/memory.c b/softmmu/memory.c -index 7340e19ff5..b435bb4aa3 100644 ---- a/softmmu/memory.c -+++ b/softmmu/memory.c -@@ -47,6 +47,9 @@ static QTAILQ_HEAD(, MemoryListener) memory_listeners - static QTAILQ_HEAD(, AddressSpace) address_spaces - = QTAILQ_HEAD_INITIALIZER(address_spaces); - -+static QTAILQ_HEAD(, SharedRegionListener) shared_region_listeners -+ = QTAILQ_HEAD_INITIALIZER(shared_region_listeners); -+ - static GHashTable *flat_views; - - typedef struct AddrRange AddrRange; -@@ -2111,6 +2114,21 @@ void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, - rdmc->unregister_listener(rdm, rdl); - } - -+void shared_region_register_listener(SharedRegionListener *shl) -+{ -+ QTAILQ_INSERT_TAIL(&shared_region_listeners, shl, next); -+} -+ -+void shared_region_unregister_listener(SharedRegionListener *shl) -+{ -+ QTAILQ_REMOVE(&shared_region_listeners, shl, next); -+} -+ -+void *shared_region_listeners_get(void) -+{ -+ return &shared_region_listeners; -+} -+ - void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) - { - uint8_t mask = 1 << client; -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index a5ce986e3c..96ca055270 100644 ---- a/target/i386/csv-sysemu-stub.c -+++ b/target/i386/csv-sysemu-stub.c -@@ -29,3 +29,13 @@ int csv_launch_encrypt_vmcb(void) - { - g_assert_not_reached(); - } -+ -+int csv_shared_region_dma_map(uint64_t start, uint64_t end) -+{ -+ return 0; -+} -+ -+void csv_shared_region_dma_unmap(uint64_t start, uint64_t end) -+{ -+ -+} -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 161cad39ae..6d05382fb2 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -24,6 +24,7 @@ - #include "cpu.h" - #include "sev.h" - #include "csv.h" -+#include "exec/address-spaces.h" - - CsvGuestState csv_guest = { 0 }; - -@@ -63,6 +64,8 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - csv_guest.state = state; - csv_guest.sev_ioctl = ops->sev_ioctl; - csv_guest.fw_error_to_str = ops->fw_error_to_str; -+ QTAILQ_INIT(&csv_guest.dma_map_regions_list); -+ qemu_mutex_init(&csv_guest.dma_map_regions_list_mutex); - } - return 0; - } -@@ -163,3 +166,134 @@ csv_launch_encrypt_vmcb(void) - err: - return ret; - } -+ -+int csv_shared_region_dma_map(uint64_t start, uint64_t end) -+{ -+ MemoryRegionSection section; -+ AddressSpace *as; -+ QTAILQ_HEAD(, SharedRegionListener) *shared_region_listeners; -+ SharedRegionListener *shl; -+ MemoryListener *listener; -+ uint64_t size; -+ CsvGuestState *s = &csv_guest; -+ struct dma_map_region *region, *pos; -+ int ret = 0; -+ -+ if (!csv_enabled()) -+ return 0; -+ -+ if (end <= start) -+ return 0; -+ -+ shared_region_listeners = shared_region_listeners_get(); -+ if (QTAILQ_EMPTY(shared_region_listeners)) -+ return 0; -+ -+ size = end - start; -+ -+ qemu_mutex_lock(&s->dma_map_regions_list_mutex); -+ QTAILQ_FOREACH(pos, &s->dma_map_regions_list, list) { -+ if (start >= (pos->start + pos->size)) { -+ continue; -+ } else if ((start + size) <= pos->start) { -+ break; -+ } else { -+ goto end; -+ } -+ } -+ QTAILQ_FOREACH(shl, shared_region_listeners, next) { -+ listener = shl->listener; -+ as = shl->as; -+ section = memory_region_find(as->root, start, size); -+ if (!section.mr) { -+ goto end; -+ } -+ -+ if (!memory_region_is_ram(section.mr)) { -+ memory_region_unref(section.mr); -+ goto end; -+ } -+ -+ if (listener->region_add) { -+ listener->region_add(listener, §ion); -+ } -+ memory_region_unref(section.mr); -+ } -+ -+ region = g_malloc0(sizeof(*region)); -+ if (!region) { -+ ret = -1; -+ goto end; -+ } -+ region->start = start; -+ region->size = size; -+ -+ if (pos) { -+ QTAILQ_INSERT_BEFORE(pos, region, list); -+ } else { -+ QTAILQ_INSERT_TAIL(&s->dma_map_regions_list, region, list); -+ } -+ -+end: -+ qemu_mutex_unlock(&s->dma_map_regions_list_mutex); -+ return ret; -+} -+ -+void csv_shared_region_dma_unmap(uint64_t start, uint64_t end) -+{ -+ MemoryRegionSection section; -+ AddressSpace *as; -+ QTAILQ_HEAD(, SharedRegionListener) *shared_region_listeners; -+ SharedRegionListener *shl; -+ MemoryListener *listener; -+ uint64_t size; -+ CsvGuestState *s = &csv_guest; -+ struct dma_map_region *pos, *next_pos; -+ -+ if (!csv_enabled()) -+ return; -+ -+ if (end <= start) -+ return; -+ -+ shared_region_listeners = shared_region_listeners_get(); -+ if (QTAILQ_EMPTY(shared_region_listeners)) -+ return; -+ -+ size = end - start; -+ -+ qemu_mutex_lock(&s->dma_map_regions_list_mutex); -+ QTAILQ_FOREACH_SAFE(pos, &s->dma_map_regions_list, list, next_pos) { -+ uint64_t l, r; -+ uint64_t curr_end = pos->start + pos->size; -+ -+ l = MAX(start, pos->start); -+ r = MIN(start + size, pos->start + pos->size); -+ if (l < r) { -+ if ((start <= pos->start) && (start + size >= pos->start + pos->size)) { -+ QTAILQ_FOREACH(shl, shared_region_listeners, next) { -+ listener = shl->listener; -+ as = shl->as; -+ section = memory_region_find(as->root, pos->start, pos->size); -+ if (!section.mr) { -+ goto end; -+ } -+ if (listener->region_del) { -+ listener->region_del(listener, §ion); -+ } -+ memory_region_unref(section.mr); -+ } -+ -+ QTAILQ_REMOVE(&s->dma_map_regions_list, pos, list); -+ g_free(pos); -+ } -+ break; -+ } -+ if ((start + size) <= curr_end) { -+ break; -+ } -+ } -+end: -+ qemu_mutex_unlock(&s->dma_map_regions_list_mutex); -+ return; -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index e51cc83022..6412c0c70b 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -15,6 +15,8 @@ - #define QEMU_CSV_H - - #include "qapi/qapi-commands-misc-target.h" -+#include "qemu/thread.h" -+#include "qemu/queue.h" - - #ifdef CONFIG_SEV - -@@ -55,12 +57,19 @@ bool csv_enabled(void); - #define csv_enabled() 0 - #endif - -+struct dma_map_region { -+ uint64_t start, size; -+ QTAILQ_ENTRY(dma_map_region) list; -+}; -+ - struct CsvGuestState { - uint32_t policy; - int sev_fd; - void *state; - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); - const char *(*fw_error_to_str)(int code); -+ QTAILQ_HEAD(, dma_map_region) dma_map_regions_list; -+ QemuMutex dma_map_regions_list_mutex; - }; - - typedef struct CsvGuestState CsvGuestState; -@@ -71,4 +80,7 @@ extern int csv_launch_encrypt_vmcb(void); - - int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - -+int csv_shared_region_dma_map(uint64_t start, uint64_t end); -+void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); -+ - #endif -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 6192bcd36e..090800257f 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -4626,8 +4626,10 @@ static int kvm_handle_exit_hypercall(X86CPU *cpu, struct kvm_run *run) - - if (enc) { - sev_remove_shared_regions_list(gfn_start, gfn_end); -+ csv_shared_region_dma_unmap(gpa, gfn_end << TARGET_PAGE_BITS); - } else { - sev_add_shared_regions_list(gfn_start, gfn_end); -+ csv_shared_region_dma_map(gpa, gfn_end << TARGET_PAGE_BITS); - } - } - return 0; --- -2.17.1 - diff --git a/1068-anolis-linux-headers-update-kernel-headers-to-includ.patch b/1068-anolis-linux-headers-update-kernel-headers-to-includ.patch deleted file mode 100644 index 209ebd9..0000000 --- a/1068-anolis-linux-headers-update-kernel-headers-to-includ.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 69976084e81798c275286b5bd3641d4b58896b72 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 09:25:19 +0800 -Subject: [PATCH 1068/1072] anolis: linux-headers: update kernel headers to - include CSV migration cmds - -Four new migration commands are added to support CSV migration. - -KVM_CSV_SEND_ENCRYPT_DATA/KVM_CSV_RECEIVE_ENCRYPT_DATA cmds are -used to migrate guest's pages. - -KVM_CSV_SEND_ENCRYPT_CONTEXT/KVM_CSV_RECEIVE_ENCRYPT_CONTEXT cmds -are used to migration guest's runtime context. - -Change-Id: Ib3b733c7b5713aa6a6648c65e03cf8c9618ff1af -Signed-off-by: Xin Jiang ---- - linux-headers/linux/kvm.h | 38 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 38 insertions(+) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 1a2c3ea87d..cbf4fe4ecb 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1842,6 +1842,12 @@ enum csv_cmd_id { - KVM_CSV_INIT = KVM_CSV_NR_MIN, - KVM_CSV_LAUNCH_ENCRYPT_DATA, - KVM_CSV_LAUNCH_ENCRYPT_VMCB, -+ KVM_CSV_SEND_ENCRYPT_DATA, -+ KVM_CSV_SEND_ENCRYPT_CONTEXT, -+ KVM_CSV_RECEIVE_ENCRYPT_DATA, -+ KVM_CSV_RECEIVE_ENCRYPT_CONTEXT, -+ -+ KVM_CSV_NR_MAX, - }; - - struct kvm_csv_launch_encrypt_data { -@@ -1865,6 +1871,38 @@ struct kvm_csv_command_batch { - __u64 csv_batch_list_uaddr; - }; - -+struct kvm_csv_send_encrypt_data { -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 guest_addr_data; -+ __u32 guest_addr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ -+struct kvm_csv_send_encrypt_context { -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ -+struct kvm_csv_receive_encrypt_data { -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 guest_addr_data; -+ __u32 guest_addr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ -+struct kvm_csv_receive_encrypt_context { -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) --- -2.17.1 - diff --git a/1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch b/1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch deleted file mode 100644 index 1d941ca..0000000 --- a/1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch +++ /dev/null @@ -1,453 +0,0 @@ -From 967c7ad199c55223cc03d0217c6f256d3d418be2 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 09:37:56 +0800 -Subject: [PATCH 1069/1072] anolis: csv/i386: add support to migrate the - outgoing page - -The csv_send_encrypt_data() provides the method to encrypt the -guest's private pages during migration. The routine is similar to -CSV2's. Usually, it starts with a SEND_START command to create the -migration context. Then SEND_ENCRYPT_DATA command is performed to -encrypt guest pages. After migration is completed, a SEND_FINISH -command is performed to the firmware. - -Change-Id: I6781119890036636d8f5c0a19c6647fa8a33a37d ---- - migration/ram.c | 83 ++++++++++++++++++ - target/i386/csv.c | 185 +++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 22 +++++ - target/i386/sev.c | 13 ++- - target/i386/sev.h | 1 + - target/i386/trace-events | 1 + - 6 files changed, 304 insertions(+), 1 deletion(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 1dcd5c8553..c962496684 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -2452,6 +2452,86 @@ ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss, bool last - } - #endif - -+/** -+ * ram_save_csv_pages - send the given csv VM pages to the stream -+ */ -+static int ram_save_csv_pages(RAMState *rs, PageSearchStatus *pss, -+ bool last_stage) -+{ -+ int ret; -+ int tmppages = 0, pages = 0; -+ RAMBlock *block = pss->block; -+ ram_addr_t offset = 0; -+ hwaddr paddr = RAM_ADDR_INVALID; -+ uint32_t host_len = 0; -+ uint8_t *p; -+ uint64_t bytes_xmit; -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ if (!csv_enabled()) -+ return 0; -+ -+ do { -+ /* Check the pages is dirty and if it is send it */ -+ if (!migration_bitmap_clear_dirty(rs, block, pss->page)) { -+ pss->page++; -+ continue; -+ } -+ -+ ret = kvm_physical_memory_addr_from_host(kvm_state, -+ block->host + (pss->page << TARGET_PAGE_BITS), &paddr); -+ /* Process ROM or MMIO */ -+ if (paddr == RAM_ADDR_INVALID || memory_region_is_rom(block->mr)) -+ tmppages = ram_save_target_page(rs, pss, last_stage); -+ else { -+ /* Caculate the offset and host virtual address of the page */ -+ offset = pss->page << TARGET_PAGE_BITS; -+ p = block->host + offset; -+ -+ if (ops->queue_outgoing_page(p, TARGET_PAGE_SIZE, offset)) -+ return -1; -+ -+ tmppages = 1; -+ host_len += TARGET_PAGE_SIZE; -+ ram_counters.normal++; -+ } -+ -+ if (tmppages < 0) { -+ return tmppages; -+ } -+ -+ pages += tmppages; -+ -+ pss->page++; -+ } while (offset_in_ramblock(block, pss->page << TARGET_PAGE_BITS) && -+ host_len < CSV3_OUTGOING_PAGE_WINDOW_SIZE); -+ -+ /* Check if there are any queued pages */ -+ if (host_len != 0) { -+ /* Always set offset as 0 for csv. */ -+ ram_counters.transferred += -+ save_page_header(rs, rs->f, block, 0 | RAM_SAVE_FLAG_ENCRYPTED_DATA); -+ -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_PAGE); -+ ram_counters.transferred += 4; -+ /* Process the queued pages in batch */ -+ ret = ops->save_queued_outgoing_pages(rs->f, &bytes_xmit); -+ if (ret) { -+ return -1; -+ } -+ ram_counters.transferred += bytes_xmit; -+ } -+ -+ /* The offset we leave with is the last one we looked at */ -+ pss->page--; -+ -+ return pages; -+} -+ - /** - * ram_save_host_page: save a whole host page - * -@@ -2486,6 +2566,9 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, - return 0; - } - -+ if (csv_enabled()) -+ return ram_save_csv_pages(rs, pss, last_stage); -+ - #ifdef CONFIG_HYGON_CSV_MIG_ACCEL - /* - * If command_batch function is enabled and memory encryption is enabled -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 6d05382fb2..c5a2bc9924 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -13,6 +13,7 @@ - - #include "qemu/osdep.h" - -+#include - #include - #include "qapi/error.h" - -@@ -20,12 +21,30 @@ - #include - #endif - -+#include "migration/blocker.h" -+#include "migration/qemu-file.h" -+#include "migration/misc.h" -+#include "monitor/monitor.h" -+#include "sysemu/kvm.h" -+ - #include "trace.h" - #include "cpu.h" - #include "sev.h" - #include "csv.h" - #include "exec/address-spaces.h" - -+struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = { -+ .save_setup = sev_save_setup, -+ .save_outgoing_page = NULL, -+ .is_gfn_in_unshared_region = NULL, -+ .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, -+ .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, -+ .queue_outgoing_page = csv3_queue_outgoing_page, -+ .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, -+}; -+ -+#define CSV_OUTGOING_PAGE_NUM (CSV3_OUTGOING_PAGE_WINDOW_SIZE/TARGET_PAGE_SIZE) -+ - CsvGuestState csv_guest = { 0 }; - - #define GUEST_POLICY_CSV_BIT (1 << 6) -@@ -66,6 +85,7 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - csv_guest.fw_error_to_str = ops->fw_error_to_str; - QTAILQ_INIT(&csv_guest.dma_map_regions_list); - qemu_mutex_init(&csv_guest.dma_map_regions_list_mutex); -+ csv_guest.sev_send_start = ops->sev_send_start; - } - return 0; - } -@@ -297,3 +317,168 @@ end: - qemu_mutex_unlock(&s->dma_map_regions_list_mutex); - return; - } -+ -+static inline hwaddr csv_hva_to_gfn(uint8_t *ptr) -+{ -+ ram_addr_t offset = RAM_ADDR_INVALID; -+ -+ kvm_physical_memory_addr_from_host(kvm_state, ptr, &offset); -+ -+ return offset >> TARGET_PAGE_BITS; -+} -+ -+static int -+csv_send_start(QEMUFile *f, uint64_t *bytes_sent) -+{ -+ if (csv_guest.sev_send_start) -+ return csv_guest.sev_send_start(f, bytes_sent); -+ else -+ return -1; -+} -+ -+static int -+csv_send_get_packet_len(int *fw_err) -+{ -+ int ret; -+ struct kvm_csv_send_encrypt_data update = {0}; -+ -+ update.hdr_len = 0; -+ update.trans_len = 0; -+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_DATA, &update, fw_err); -+ if (*fw_err != SEV_RET_INVALID_LEN) { -+ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ ret = 0; -+ goto err; -+ } -+ -+ if (update.hdr_len <= INT_MAX) -+ ret = update.hdr_len; -+ else -+ ret = 0; -+ -+err: -+ return ret; -+} -+ -+static int -+csv_send_encrypt_data(CsvGuestState *s, QEMUFile *f, uint8_t *ptr, uint32_t size, -+ uint64_t *bytes_sent) -+{ -+ int ret, fw_error = 0; -+ guchar *trans; -+ uint32_t guest_addr_entry_num; -+ uint32_t i; -+ struct kvm_csv_send_encrypt_data update = { }; -+ -+ /* -+ * If this is first call then query the packet header bytes and allocate -+ * the packet buffer. -+ */ -+ if (!s->send_packet_hdr) { -+ s->send_packet_hdr_len = csv_send_get_packet_len(&fw_error); -+ if (s->send_packet_hdr_len < 1) { -+ error_report("%s: SEND_UPDATE fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ -+ s->send_packet_hdr = g_new(gchar, s->send_packet_hdr_len); -+ } -+ -+ if (!s->guest_addr_len || !s->guest_addr_data) { -+ error_report("%s: invalid host address or size", __func__); -+ return 1; -+ } else { -+ guest_addr_entry_num = s->guest_addr_len / sizeof(struct guest_addr_entry); -+ } -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, guest_addr_entry_num * TARGET_PAGE_SIZE); -+ -+ update.hdr_uaddr = (uintptr_t)s->send_packet_hdr; -+ update.hdr_len = s->send_packet_hdr_len; -+ update.guest_addr_data = (uintptr_t)s->guest_addr_data; -+ update.guest_addr_len = s->guest_addr_len; -+ update.trans_uaddr = (uintptr_t)trans; -+ update.trans_len = guest_addr_entry_num * TARGET_PAGE_SIZE; -+ -+ trace_kvm_csv_send_encrypt_data(trans, update.trans_len); -+ -+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_DATA, &update, &fw_error); -+ if (ret) { -+ error_report("%s: SEND_ENCRYPT_DATA ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ for (i = 0; i < guest_addr_entry_num; i++) { -+ if (s->guest_addr_data[i].share) -+ memcpy(trans + i * TARGET_PAGE_SIZE, (guchar *)s->guest_hva_data[i].hva, -+ TARGET_PAGE_SIZE); -+ } -+ -+ qemu_put_be32(f, update.hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); -+ *bytes_sent = 4 + update.hdr_len; -+ -+ qemu_put_be32(f, update.guest_addr_len); -+ qemu_put_buffer(f, (uint8_t *)update.guest_addr_data, update.guest_addr_len); -+ *bytes_sent = 4 + update.guest_addr_len; -+ -+ qemu_put_be32(f, update.trans_len); -+ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ *bytes_sent += (4 + update.trans_len); -+ -+err: -+ s->guest_addr_len = 0; -+ g_free(trans); -+ return ret; -+} -+ -+int -+csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) -+{ -+ CsvGuestState *s = &csv_guest; -+ uint32_t i = 0; -+ -+ (void) addr; -+ -+ if (!s->guest_addr_data) { -+ s->guest_hva_data = g_new0(struct guest_hva_entry, CSV_OUTGOING_PAGE_NUM); -+ s->guest_addr_data = g_new0(struct guest_addr_entry, CSV_OUTGOING_PAGE_NUM); -+ s->guest_addr_len = 0; -+ } -+ -+ if (s->guest_addr_len >= sizeof(struct guest_addr_entry) * CSV_OUTGOING_PAGE_NUM) { -+ error_report("Failed to queue outgoing page"); -+ return 1; -+ } -+ -+ i = s->guest_addr_len / sizeof(struct guest_addr_entry); -+ s->guest_hva_data[i].hva = (uintptr_t)ptr; -+ s->guest_addr_data[i].share = 0; -+ s->guest_addr_data[i].reserved = 0; -+ s->guest_addr_data[i].gfn = csv_hva_to_gfn(ptr); -+ s->guest_addr_len += sizeof(struct guest_addr_entry); -+ -+ return 0; -+} -+ -+int -+csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) -+{ -+ CsvGuestState *s = &csv_guest; -+ -+ /* -+ * If this is a first buffer then create outgoing encryption context -+ * and write our PDH, policy and session data. -+ */ -+ if (!csv_check_state(SEV_STATE_SEND_UPDATE) && -+ csv_send_start(f, bytes_sent)) { -+ error_report("Failed to create outgoing context"); -+ return 1; -+ } -+ -+ return csv_send_encrypt_data(s, f, NULL, 0, bytes_sent); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 6412c0c70b..273d69d12c 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -62,6 +62,18 @@ struct dma_map_region { - QTAILQ_ENTRY(dma_map_region) list; - }; - -+#define CSV3_OUTGOING_PAGE_WINDOW_SIZE (512 * TARGET_PAGE_SIZE) -+ -+struct guest_addr_entry { -+ uint64_t share: 1; -+ uint64_t reserved: 11; -+ uint64_t gfn: 52; -+}; -+ -+struct guest_hva_entry { -+ uint64_t hva; -+}; -+ - struct CsvGuestState { - uint32_t policy; - int sev_fd; -@@ -70,6 +82,13 @@ struct CsvGuestState { - const char *(*fw_error_to_str)(int code); - QTAILQ_HEAD(, dma_map_region) dma_map_regions_list; - QemuMutex dma_map_regions_list_mutex; -+ gchar *send_packet_hdr; -+ size_t send_packet_hdr_len; -+ struct guest_hva_entry *guest_hva_data; -+ struct guest_addr_entry *guest_addr_data; -+ size_t guest_addr_len; -+ -+ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); - }; - - typedef struct CsvGuestState CsvGuestState; -@@ -77,10 +96,13 @@ typedef struct CsvGuestState CsvGuestState; - extern struct CsvGuestState csv_guest; - extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); - extern int csv_launch_encrypt_vmcb(void); -+extern struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops; - - int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - - int csv_shared_region_dma_map(uint64_t start, uint64_t end); - void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); -+int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); -+int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - - #endif -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 26b6e84d3f..31af1ecdf3 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -1173,7 +1173,10 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - qemu_add_vm_change_state_handler(sev_vm_state_change, sev); - add_migration_state_change_notifier(&sev_migration_state_notify); - -- cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; -+ if (csv_enabled()) -+ cgs_class->memory_encryption_ops = &csv_memory_encryption_ops; -+ else -+ cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; - QTAILQ_INIT(&sev->shared_regions_list); - - /* Determine whether support MSR_AMD64_SEV_ES_GHCB */ -@@ -2552,9 +2555,17 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) - return ret; - } - -+static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) -+{ -+ SevGuestState *s = sev_guest; -+ -+ return sev_send_start(s, f, bytes_sent); -+} -+ - struct sev_ops sev_ops = { - .sev_ioctl = sev_ioctl, - .fw_error_to_str = fw_error_to_str, -+ .sev_send_start = _sev_send_start, - }; - - static void -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 8b38567c3d..6d1a918413 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -89,6 +89,7 @@ int csv_load_incoming_cpu_state(QEMUFile *f); - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); - const char *(*fw_error_to_str)(int code); -+ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); - }; - - #endif -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 60a4609c0f..8db3e36385 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -22,3 +22,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int - - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 -+kvm_csv_send_encrypt_data(void *dst, int len) "trans %p len %d" --- -2.17.1 - diff --git a/1070-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch b/1070-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch deleted file mode 100644 index 39a15d4..0000000 --- a/1070-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch +++ /dev/null @@ -1,204 +0,0 @@ -From e6b96ff4918864bfb3ace811d46cdee74b7a7d91 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 09:45:45 +0800 -Subject: [PATCH 1070/1072] anolis: csv/i386: add support to migrate the - incoming page - -The csv_receive_encrypt_data() provides the method to read incoming -guest private pages from socket and load them into guest memory. -The routine is similar to CSV2's. Usually, it starts with a RECEIVE -START command to create the migration context. Then RECEIVE ENCRYPT -DATA command is performed to let the firmware load incoming pages -into guest memory. After migration is completed, a RECEIVE FINISH -command is performed to the firmware. - -Change-Id: I53bc350e379fa747c7b3c3b3be9f2fef0bf1af9f ---- - target/i386/csv.c | 87 ++++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 2 + - target/i386/sev.c | 8 ++++ - target/i386/sev.h | 1 + - target/i386/trace-events | 1 + - 5 files changed, 99 insertions(+) - -diff --git a/target/i386/csv.c b/target/i386/csv.c -index c5a2bc9924..00ff7d20a5 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -36,11 +36,14 @@ - struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = NULL, -+ .load_incoming_page = csv3_load_incoming_page, - .is_gfn_in_unshared_region = NULL, - .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - .queue_outgoing_page = csv3_queue_outgoing_page, - .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, -+ .queue_incoming_page = NULL, -+ .load_queued_incoming_pages = NULL, - }; - - #define CSV_OUTGOING_PAGE_NUM (CSV3_OUTGOING_PAGE_WINDOW_SIZE/TARGET_PAGE_SIZE) -@@ -86,6 +89,7 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - QTAILQ_INIT(&csv_guest.dma_map_regions_list); - qemu_mutex_init(&csv_guest.dma_map_regions_list_mutex); - csv_guest.sev_send_start = ops->sev_send_start; -+ csv_guest.sev_receive_start = ops->sev_receive_start; - } - return 0; - } -@@ -482,3 +486,86 @@ csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) - - return csv_send_encrypt_data(s, f, NULL, 0, bytes_sent); - } -+ -+static int -+csv_receive_start(QEMUFile *f) -+{ -+ if (csv_guest.sev_receive_start) -+ return csv_guest.sev_receive_start(f); -+ else -+ return -1; -+} -+ -+static int csv_receive_encrypt_data(QEMUFile *f, uint8_t *ptr) -+{ -+ int ret = 1, fw_error = 0; -+ uint32_t i, guest_addr_entry_num; -+ gchar *hdr = NULL, *trans = NULL; -+ struct guest_addr_entry *guest_addr_data; -+ struct kvm_csv_receive_encrypt_data update = {}; -+ void *hva = NULL; -+ MemoryRegion *mr = NULL; -+ -+ /* get packet header */ -+ update.hdr_len = qemu_get_be32(f); -+ -+ hdr = g_new(gchar, update.hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); -+ update.hdr_uaddr = (uintptr_t)hdr; -+ -+ /* get guest addr data */ -+ update.guest_addr_len = qemu_get_be32(f); -+ -+ guest_addr_data = (struct guest_addr_entry *)g_new(gchar, update.guest_addr_len); -+ qemu_get_buffer(f, (uint8_t *)guest_addr_data, update.guest_addr_len); -+ update.guest_addr_data = (uintptr_t)guest_addr_data; -+ -+ /* get transport buffer */ -+ update.trans_len = qemu_get_be32(f); -+ -+ trans = g_new(gchar, update.trans_len); -+ update.trans_uaddr = (uintptr_t)trans; -+ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+ /* update share memory. */ -+ guest_addr_entry_num = update.guest_addr_len / sizeof(struct guest_addr_entry); -+ for (i = 0; i < guest_addr_entry_num; i++) { -+ if (guest_addr_data[i].share) { -+ hva = gpa2hva(&mr, -+ ((uint64_t)guest_addr_data[i].gfn << TARGET_PAGE_BITS), -+ TARGET_PAGE_SIZE, -+ NULL); -+ if (hva) -+ memcpy(hva, trans + i * TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); -+ } -+ } -+ -+ trace_kvm_csv_receive_encrypt_data(trans, update.trans_len, hdr, update.hdr_len); -+ -+ ret = csv_ioctl(KVM_CSV_RECEIVE_ENCRYPT_DATA, &update, &fw_error); -+ if (ret) { -+ error_report("Error RECEIVE_ENCRYPT_DATA ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+err: -+ g_free(trans); -+ g_free(guest_addr_data); -+ g_free(hdr); -+ return ret; -+} -+ -+int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr) -+{ -+ /* -+ * If this is first buffer and SEV is not in recieiving state then -+ * use RECEIVE_START command to create a encryption context. -+ */ -+ if (!csv_check_state(SEV_STATE_RECEIVE_UPDATE) && -+ csv_receive_start(f)) { -+ return 1; -+ } -+ -+ return csv_receive_encrypt_data(f, ptr); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 273d69d12c..c8639cfa9a 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -89,6 +89,7 @@ struct CsvGuestState { - size_t guest_addr_len; - - int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); -+ int (*sev_receive_start)(QEMUFile *f); - }; - - typedef struct CsvGuestState CsvGuestState; -@@ -102,6 +103,7 @@ int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - - int csv_shared_region_dma_map(uint64_t start, uint64_t end); - void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); -+int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); - int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 31af1ecdf3..40e52985ac 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -2562,10 +2562,18 @@ static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) - return sev_send_start(s, f, bytes_sent); - } - -+static int _sev_receive_start(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ -+ return sev_receive_start(s, f); -+} -+ - struct sev_ops sev_ops = { - .sev_ioctl = sev_ioctl, - .fw_error_to_str = fw_error_to_str, - .sev_send_start = _sev_send_start, -+ .sev_receive_start = _sev_receive_start, - }; - - static void -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 6d1a918413..9e5c6506c8 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -90,6 +90,7 @@ struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); - const char *(*fw_error_to_str)(int code); - int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); -+ int (*sev_receive_start)(QEMUFile *f); - }; - - #endif -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 8db3e36385..1854356fc5 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -23,3 +23,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 - kvm_csv_send_encrypt_data(void *dst, int len) "trans %p len %d" -+kvm_csv_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" --- -2.17.1 - diff --git a/1071-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch b/1071-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch deleted file mode 100644 index 629f713..0000000 --- a/1071-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch +++ /dev/null @@ -1,137 +0,0 @@ -From cd3f19da06a1691a790221a06a2899427e2140cd Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 09:52:31 +0800 -Subject: [PATCH 1071/1072] anolis: csv/i386: add support to migrate the - outgoing context - -CSV needs to migrate guest cpu's context pages. Prior to migration -of the context, it should query transfer buffer length and header -data length by SEND ENCRYPT CONTEXT command. New migration flag -RAM_SAVE_ENCRYPTED_CSV_CONTEXT is defined for CSV. - -Change-Id: I1989e76bd5c91c78074fb31eff075deacfa16078 ---- - target/i386/csv.c | 79 ++++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 1 + - target/i386/trace-events | 1 + - 3 files changed, 81 insertions(+) - -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 00ff7d20a5..271c48867e 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -44,6 +44,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = { - .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, - .queue_incoming_page = NULL, - .load_queued_incoming_pages = NULL, -+ .save_outgoing_cpu_state = csv3_save_outgoing_context, - }; - - #define CSV_OUTGOING_PAGE_NUM (CSV3_OUTGOING_PAGE_WINDOW_SIZE/TARGET_PAGE_SIZE) -@@ -569,3 +570,81 @@ int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr) - - return csv_receive_encrypt_data(f, ptr); - } -+ -+static int -+csv_send_get_context_len(int *fw_err, int *context_len, int *hdr_len) -+{ -+ int ret = 0; -+ struct kvm_csv_send_encrypt_context update = {}; -+ -+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_CONTEXT, &update, fw_err); -+ if (*fw_err != SEV_RET_INVALID_LEN) { -+ error_report("%s: failed to get context length ret=%d fw_error=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ ret = -1; -+ goto err; -+ } -+ -+ if (update.trans_len <= INT_MAX && update.hdr_len <= INT_MAX) { -+ *context_len = update.trans_len; -+ *hdr_len = update.hdr_len; -+ } -+ ret = 0; -+err: -+ return ret; -+} -+ -+static int -+csv_send_encrypt_context(CsvGuestState *s, QEMUFile *f) -+{ -+ int ret, fw_error = 0; -+ int context_len = 0; -+ int hdr_len = 0; -+ guchar *trans; -+ guchar *hdr; -+ struct kvm_csv_send_encrypt_context update = { }; -+ -+ ret = csv_send_get_context_len(&fw_error, &context_len, &hdr_len); -+ if (context_len < 1 || hdr_len < 1) { -+ error_report("%s: fail to get context length fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, context_len); -+ hdr = g_new(guchar, hdr_len); -+ -+ update.hdr_uaddr = (uintptr_t)hdr; -+ update.hdr_len = hdr_len; -+ update.trans_uaddr = (uintptr_t)trans; -+ update.trans_len = context_len; -+ -+ trace_kvm_csv_send_encrypt_context(trans, update.trans_len); -+ -+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_CONTEXT, &update, &fw_error); -+ if (ret) { -+ error_report("%s: SEND_ENCRYPT_CONTEXT ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ qemu_put_be32(f, update.hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); -+ -+ qemu_put_be32(f, update.trans_len); -+ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+err: -+ g_free(trans); -+ g_free(hdr); -+ return ret; -+} -+ -+int csv3_save_outgoing_context(QEMUFile *f) -+{ -+ CsvGuestState *s = &csv_guest; -+ -+ /* send csv context. */ -+ return csv_send_encrypt_context(s, f); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index c8639cfa9a..9def1611d8 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -103,6 +103,7 @@ int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - - int csv_shared_region_dma_map(uint64_t start, uint64_t end); - void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); -+int csv3_save_outgoing_context(QEMUFile *f); - int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); - int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 1854356fc5..08a782ce15 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -23,4 +23,5 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 - kvm_csv_send_encrypt_data(void *dst, int len) "trans %p len %d" -+kvm_csv_send_encrypt_context(void *dst, int len) "trans %p len %d" - kvm_csv_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" --- -2.17.1 - diff --git a/1072-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch b/1072-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch deleted file mode 100644 index 1c6084b..0000000 --- a/1072-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 40741ce0d0bb68d789d84407c77d2282ecd4f67f Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 10:00:46 +0800 -Subject: [PATCH 1072/1072] anolis: csv/i386: add support to migrate the - incoming context - -The csv_load_incoming_context() provides the method to read incoming -guest's context from socket. It loads them into guest private memory. -This is the last step during migration and RECEIVE FINISH command is -performed by then to complete the whole migration. - -Change-Id: I7290e0e9527bb819eee5813038110d981908a880 ---- - target/i386/csv.c | 45 ++++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 1 + - target/i386/trace-events | 1 + - 3 files changed, 47 insertions(+) - -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 271c48867e..b0ca16980d 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -45,6 +45,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = { - .queue_incoming_page = NULL, - .load_queued_incoming_pages = NULL, - .save_outgoing_cpu_state = csv3_save_outgoing_context, -+ .load_incoming_cpu_state = csv3_load_incoming_context, - }; - - #define CSV_OUTGOING_PAGE_NUM (CSV3_OUTGOING_PAGE_WINDOW_SIZE/TARGET_PAGE_SIZE) -@@ -641,6 +642,42 @@ err: - return ret; - } - -+static int -+csv_receive_encrypt_context(CsvGuestState *s, QEMUFile *f) -+{ -+ int ret = 1, fw_error = 0; -+ gchar *hdr = NULL, *trans = NULL; -+ struct kvm_csv_receive_encrypt_context update = {}; -+ -+ /* get packet header */ -+ update.hdr_len = qemu_get_be32(f); -+ -+ hdr = g_new(gchar, update.hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); -+ update.hdr_uaddr = (uintptr_t)hdr; -+ -+ /* get transport buffer */ -+ update.trans_len = qemu_get_be32(f); -+ -+ trans = g_new(gchar, update.trans_len); -+ update.trans_uaddr = (uintptr_t)trans; -+ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+ trace_kvm_csv_receive_encrypt_context(trans, update.trans_len, hdr, update.hdr_len); -+ -+ ret = csv_ioctl(KVM_CSV_RECEIVE_ENCRYPT_CONTEXT, &update, &fw_error); -+ if (ret) { -+ error_report("Error RECEIVE_ENCRYPT_CONTEXT ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+err: -+ g_free(trans); -+ g_free(hdr); -+ return ret; -+} -+ - int csv3_save_outgoing_context(QEMUFile *f) - { - CsvGuestState *s = &csv_guest; -@@ -648,3 +685,11 @@ int csv3_save_outgoing_context(QEMUFile *f) - /* send csv context. */ - return csv_send_encrypt_context(s, f); - } -+ -+int csv3_load_incoming_context(QEMUFile *f) -+{ -+ CsvGuestState *s = &csv_guest; -+ -+ /* receive csv context. */ -+ return csv_receive_encrypt_context(s, f); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 9def1611d8..2e0506313d 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -104,6 +104,7 @@ int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - int csv_shared_region_dma_map(uint64_t start, uint64_t end); - void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); - int csv3_save_outgoing_context(QEMUFile *f); -+int csv3_load_incoming_context(QEMUFile *f); - int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); - int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 08a782ce15..47ab390de6 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -25,3 +25,4 @@ kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PR - kvm_csv_send_encrypt_data(void *dst, int len) "trans %p len %d" - kvm_csv_send_encrypt_context(void *dst, int len) "trans %p len %d" - kvm_csv_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" -+kvm_csv_receive_encrypt_context(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" --- -2.17.1 - diff --git a/1073-anolis-target-i386-sev-Add-support-for-reuse-ASID-fo.patch b/1073-anolis-target-i386-sev-Add-support-for-reuse-ASID-fo.patch deleted file mode 100644 index 7e6f98e..0000000 --- a/1073-anolis-target-i386-sev-Add-support-for-reuse-ASID-fo.patch +++ /dev/null @@ -1,192 +0,0 @@ -From 9cd331388ce95e3d7365fceab30016756eae2483 Mon Sep 17 00:00:00 2001 -From: appleLin -Date: Wed, 3 Aug 2022 21:02:41 +0800 -Subject: [PATCH] anolis: target/i386/sev: Add support for reuse ASID for - different CSV guests - -In you want to reuse one ASID for many CSV guests, you should provide a -label (i.e. userid) and the length of the label when launch CSV guest. -The CSV guests which were provided the same userid will share the same -ASID. - -Signed-off-by: hanliyang ---- - linux-headers/linux/kvm.h | 5 +++++ - qapi/qom.json | 5 ++++- - qemu-options.hx | 5 ++++- - target/i386/csv.c | 2 -- - target/i386/csv.h | 3 +++ - target/i386/sev.c | 47 ++++++++++++++++++++++++++++++++++++++- - 6 files changed, 62 insertions(+), 5 deletions(-) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 5fe2f8d04..3875127a3 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -2011,6 +2011,11 @@ struct kvm_csv_receive_encrypt_context { - __u32 trans_len; - }; - -+struct kvm_csv_init { -+ __u64 userid_addr; -+ __u32 len; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) -diff --git a/qapi/qom.json b/qapi/qom.json -index eeb5395ff..387c0a142 100644 ---- a/qapi/qom.json -+++ b/qapi/qom.json -@@ -773,6 +773,8 @@ - # designated guest firmware page for measured boot - # with -kernel (default: false) (since 6.2) - # -+# @user-id: the user id of the guest owner, only support on Hygon CPUs -+# - # Since: 2.12 - ## - { 'struct': 'SevGuestProperties', -@@ -783,7 +785,8 @@ - '*handle': 'uint32', - '*cbitpos': 'uint32', - 'reduced-phys-bits': 'uint32', -- '*kernel-hashes': 'bool' } } -+ '*kernel-hashes': 'bool', -+ '*user-id': 'str' } } - - ## - # @ObjectType: -diff --git a/qemu-options.hx b/qemu-options.hx -index 8997969d5..115e1835f 100644 ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -5189,7 +5189,7 @@ SRST - -object secret,id=sec0,keyid=secmaster0,format=base64,\\ - data=$SECRET,iv=$(dh_cert_file = g_strdup(value); - } - -+static char * -+sev_guest_get_user_id(Object *obj, Error **errp) -+{ -+ SevGuestState *s = SEV_GUEST(obj); -+ -+ return g_strdup(s->user_id); -+} -+ -+static void -+sev_guest_set_user_id(Object *obj, const char *value, Error **errp) -+{ -+ SevGuestState *s = SEV_GUEST(obj); -+ -+ s->user_id = g_strdup(value); -+} -+ - static char * - sev_guest_get_sev_device(Object *obj, Error **errp) - { -@@ -436,6 +453,11 @@ sev_guest_class_init(ObjectClass *oc, void *data) - sev_guest_set_kernel_hashes); - object_class_property_set_description(oc, "kernel-hashes", - "add kernel hashes to guest firmware for measured Linux boot"); -+ object_class_property_add_str(oc, "user-id", -+ sev_guest_get_user_id, -+ sev_guest_set_user_id); -+ object_class_property_set_description(oc, "user-id", -+ "user id of the guest owner"); - } - - static void -@@ -1137,7 +1159,30 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - } - - trace_kvm_sev_init(); -- ret = sev_ioctl(sev->sev_fd, cmd, NULL, &fw_error); -+ -+ /* Only support reuse asid for CSV/CSV2 guest */ -+ if (is_hygon_cpu() && -+ (sev_guest->policy & GUEST_POLICY_REUSE_ASID) && -+ !(sev_guest->policy & GUEST_POLICY_CSV_BIT)) { -+ char *user_id = NULL; -+ struct kvm_csv_init *init_cmd_buf = NULL; -+ -+ user_id = object_property_get_str(OBJECT(sev), "user-id", NULL); -+ if (user_id && strlen(user_id)) { -+ init_cmd_buf = g_new0(struct kvm_csv_init, 1); -+ init_cmd_buf->len = strlen(user_id); -+ init_cmd_buf->userid_addr = (__u64)user_id; -+ } -+ ret = sev_ioctl(sev->sev_fd, cmd, init_cmd_buf, &fw_error); -+ -+ if (user_id) { -+ g_free(user_id); -+ g_free(init_cmd_buf); -+ } -+ } else { -+ ret = sev_ioctl(sev->sev_fd, cmd, NULL, &fw_error); -+ } -+ - if (ret) { - error_setg(errp, "%s: failed to initialize ret=%d fw_error=%d '%s'", - __func__, ret, fw_error, fw_error_to_str(fw_error)); --- -2.31.1 - diff --git a/1074-newfeature-support-vpsp.patch b/1074-newfeature-support-vpsp.patch deleted file mode 100644 index 2efaa12..0000000 --- a/1074-newfeature-support-vpsp.patch +++ /dev/null @@ -1,190 +0,0 @@ -From fd593b7516631ed0dce757cdce4d10b28971c553 Mon Sep 17 00:00:00 2001 -From: xiongmengbiao -Date: Wed, 6 Mar 2024 17:43:57 +0800 -Subject: [PATCH] [newfeature]: support vpsp - -simulate a psp misc device for support tkm's key isolation - -Signed-off-by: xiongmengbiao ---- - hw/misc/Kconfig | 4 ++ - hw/misc/meson.build | 1 + - hw/misc/psp.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 146 insertions(+) - create mode 100644 hw/misc/psp.c - -diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig -index 507058d8b..d1d05442d 100644 ---- a/hw/misc/Kconfig -+++ b/hw/misc/Kconfig -@@ -171,4 +171,8 @@ config SIFIVE_U_PRCI - config VIRT_CTRL - bool - -+config PSP_DEV -+ bool -+ default y -+ - source macio/Kconfig -diff --git a/hw/misc/meson.build b/hw/misc/meson.build -index 3f41a3a5b..39e583631 100644 ---- a/hw/misc/meson.build -+++ b/hw/misc/meson.build -@@ -10,6 +10,7 @@ softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) - softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c')) - softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c')) - softmmu_ss.add(when: 'CONFIG_PVPANIC_COMMON', if_true: files('pvpanic.c')) -+softmmu_ss.add(when: 'CONFIG_PSP_DEV', if_true: files('psp.c')) - - # ARM devices - softmmu_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c')) -diff --git a/hw/misc/psp.c b/hw/misc/psp.c -new file mode 100644 -index 000000000..1cfbab859 ---- /dev/null -+++ b/hw/misc/psp.c -@@ -0,0 +1,141 @@ -+/* -+ * hygon psp device emulation -+ * -+ * Copyright 2024 HYGON Corp. -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or (at -+ * your option) any later version. See the COPYING file in the top-level -+ * directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu/compiler.h" -+#include "qemu/error-report.h" -+#include "qapi/error.h" -+#include "migration/vmstate.h" -+#include "hw/qdev-properties.h" -+#include "sysemu/runstate.h" -+#include -+ -+#define TYPE_PSP_DEV "psp" -+OBJECT_DECLARE_SIMPLE_TYPE(PSPDevState, PSP_DEV) -+ -+struct PSPDevState { -+ /* Private */ -+ DeviceState pdev; -+ -+ /* Public */ -+ Notifier shutdown_notifier; -+ int dev_fd; -+ uint8_t enabled; -+ -+ /** -+ * vid is used to identify a virtual machine in qemu. -+ * When a virtual machine accesses a tkm key, -+ * the TKM module uses different key spaces based on different vids. -+ */ -+ uint32_t vid; -+}; -+ -+#define PSP_DEV_PATH "/dev/hygon_psp_config" -+#define HYGON_PSP_IOC_TYPE 'H' -+#define PSP_IOC_MUTEX_ENABLE _IOWR(HYGON_PSP_IOC_TYPE, 1, NULL) -+#define PSP_IOC_MUTEX_DISABLE _IOWR(HYGON_PSP_IOC_TYPE, 2, NULL) -+#define PSP_IOC_VPSP_OPT _IOWR(HYGON_PSP_IOC_TYPE, 3, NULL) -+ -+enum VPSP_DEV_CTRL_OPCODE { -+ VPSP_OP_VID_ADD, -+ VPSP_OP_VID_DEL, -+}; -+ -+struct psp_dev_ctrl { -+ unsigned char op; -+ union { -+ unsigned int vid; -+ unsigned char reserved[128]; -+ } data; -+}; -+ -+static void psp_dev_destroy(PSPDevState *state) -+{ -+ struct psp_dev_ctrl ctrl = { 0 }; -+ if (state && state->dev_fd) { -+ if (state->enabled) { -+ ctrl.op = VPSP_OP_VID_DEL; -+ if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { -+ error_report("VPSP_OP_VID_DEL: %d", -errno); -+ } else { -+ state->enabled = false; -+ } -+ } -+ qemu_close(state->dev_fd); -+ state->dev_fd = 0; -+ } -+} -+ -+/** -+ * Guest OS performs shut down operations through 'shutdown' and 'powerdown' event. -+ * The 'powerdown' event will also trigger 'shutdown' in the end, -+ * so only attention to the 'shutdown' event. -+ * -+ * When Guest OS trigger 'reboot' or 'reset' event, to do nothing. -+*/ -+static void psp_dev_shutdown_notify(Notifier *notifier, void *data) -+{ -+ PSPDevState *state = container_of(notifier, PSPDevState, shutdown_notifier); -+ psp_dev_destroy(state); -+} -+ -+static void psp_dev_realize(DeviceState *dev, Error **errp) -+{ -+ struct psp_dev_ctrl ctrl = { 0 }; -+ PSPDevState *state = PSP_DEV(dev); -+ -+ state->dev_fd = qemu_open_old(PSP_DEV_PATH, O_RDWR); -+ if (state->dev_fd < 0) { -+ error_setg(errp, "fail to open %s, errno %d.", PSP_DEV_PATH, errno); -+ goto end; -+ } -+ -+ ctrl.op = VPSP_OP_VID_ADD; -+ ctrl.data.vid = state->vid; -+ if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { -+ error_setg(errp, "psp_dev_realize VPSP_OP_VID_ADD vid %d, return %d", ctrl.data.vid, -errno); -+ goto end; -+ } -+ -+ state->enabled = true; -+ state->shutdown_notifier.notify = psp_dev_shutdown_notify; -+ qemu_register_shutdown_notifier(&state->shutdown_notifier); -+end: -+ return; -+} -+ -+static struct Property psp_dev_properties[] = { -+ DEFINE_PROP_UINT32("vid", PSPDevState, vid, 0), -+ DEFINE_PROP_END_OF_LIST(), -+}; -+ -+static void psp_dev_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ -+ dc->desc = "PSP Device"; -+ dc->realize = psp_dev_realize; -+ set_bit(DEVICE_CATEGORY_MISC, dc->categories); -+ device_class_set_props(dc, psp_dev_properties); -+} -+ -+static const TypeInfo psp_dev_info = { -+ .name = TYPE_PSP_DEV, -+ .parent = TYPE_DEVICE, -+ .instance_size = sizeof(PSPDevState), -+ .class_init = psp_dev_class_init, -+}; -+ -+static void psp_dev_register_types(void) -+{ -+ type_register_static(&psp_dev_info); -+} -+ -+type_init(psp_dev_register_types) --- -2.36.6 - diff --git a/1075-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch b/1075-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch deleted file mode 100644 index abbf1da..0000000 --- a/1075-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 858884a2a18df9bcb07176fc14a6ea5ee872f8dc Mon Sep 17 00:00:00 2001 -From: Yanjing Zhou -Date: Tue, 11 Jun 2024 14:28:12 +0800 -Subject: [PATCH 1/2] target/i386: Add Hygon Dhyana-v3 CPU model - -Add the following feature bits for Dhyana CPU model: -perfctr-core, clzero, xsaveerptr, aes, pclmulqdq, sha-ni - -Disable xsaves feature bit for Erratum 1386 - -Signed-off-by: Yanjing Zhou ---- - target/i386/cpu.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index aa9e63680..43a57be0b 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -4057,6 +4057,20 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ } - }, - }, -+ { .version = 3, -+ .props = (PropValue[]) { -+ { "xsaves", "off" }, -+ { "perfctr-core", "on" }, -+ { "clzero", "on" }, -+ { "xsaveerptr", "on" }, -+ { "aes", "on" }, -+ { "pclmulqdq", "on" }, -+ { "sha-ni", "on" }, -+ { "model-id", -+ "Hygon Dhyana-v3 processor" }, -+ { /* end of list */ } -+ }, -+ }, - { /* end of list */ } - } - }, --- -2.39.3 - diff --git a/1076-target-i386-Add-new-Hygon-Dharma-CPU-model.patch b/1076-target-i386-Add-new-Hygon-Dharma-CPU-model.patch deleted file mode 100644 index d12c1a5..0000000 --- a/1076-target-i386-Add-new-Hygon-Dharma-CPU-model.patch +++ /dev/null @@ -1,133 +0,0 @@ -From b3dfdd0e3cf7795fb66b094ffd821e193b9a773a Mon Sep 17 00:00:00 2001 -From: Yanjing Zhou -Date: Tue, 11 Jun 2024 14:29:34 +0800 -Subject: [PATCH 2/2] target/i386: Add new Hygon 'Dharma' CPU model - -Add the following feature bits compare to Dhyana CPU model: -stibp, ibrs, umip, ssbd - -Signed-off-by: Yanjing Zhou ---- - target/i386/cpu.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 99 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 43a57be0b..07b65da92 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1731,6 +1731,56 @@ static const CPUCaches epyc_milan_cache_info = { - }, - }; - -+static const CPUCaches dharma_cache_info = { -+ .l1d_cache = &(CPUCacheInfo) { -+ .type = DATA_CACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 64, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .l1i_cache = &(CPUCacheInfo) { -+ .type = INSTRUCTION_CACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 64, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .l2_cache = &(CPUCacheInfo) { -+ .type = UNIFIED_CACHE, -+ .level = 2, -+ .size = 512 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 1024, -+ .lines_per_tag = 1, -+ }, -+ .l3_cache = &(CPUCacheInfo) { -+ .type = UNIFIED_CACHE, -+ .level = 3, -+ .size = 16 * MiB, -+ .line_size = 64, -+ .associativity = 16, -+ .partitions = 1, -+ .sets = 16384, -+ .lines_per_tag = 1, -+ .self_init = true, -+ .inclusive = true, -+ .complex_indexing = true, -+ }, -+}; -+ - /* The following VMX features are not supported by KVM and are left out in the - * CPU definitions: - * -@@ -4191,6 +4241,55 @@ static const X86CPUDefinition builtin_x86_defs[] = { - .model_id = "AMD EPYC-Milan Processor", - .cache_info = &epyc_milan_cache_info, - }, -+ { -+ .name = "Dharma", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_HYGON, -+ .family = 24, -+ .model = 4, -+ .stepping = 0, -+ .features[FEAT_1_EDX] = -+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | -+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | -+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | -+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | -+ CPUID_VME | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | -+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | -+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | -+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | -+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | -+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | -+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | -+ CPUID_EXT3_TOPOEXT | CPUID_EXT3_PERFCORE, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_CLZERO | CPUID_8000_0008_EBX_XSAVEERPTR | -+ CPUID_8000_0008_EBX_IBPB | CPUID_8000_0008_EBX_IBRS | -+ CPUID_8000_0008_EBX_STIBP | CPUID_8000_0008_EBX_AMD_SSBD, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | -+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | -+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | -+ CPUID_7_0_EBX_SHA_NI, -+ .features[FEAT_7_0_ECX] = CPUID_7_0_ECX_UMIP, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_SVM] = -+ CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE, -+ .xlevel = 0x8000001E, -+ .model_id = "Hygon Dharma Processor", -+ .cache_info = &dharma_cache_info, -+ }, - }; - - /* --- -2.39.3 - diff --git a/1077-target-i386-add-FSRM-to-TCG.patch b/1077-target-i386-add-FSRM-to-TCG.patch deleted file mode 100644 index bf309ac..0000000 --- a/1077-target-i386-add-FSRM-to-TCG.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: Paolo Bonzini -Date: Mon, 27 Feb 2023 10:57:09 +0100 -Subject: [PATCH] target/i386: add FSRM to TCG - -commit c0728d4e3d23356691e4182eac54c67e1ca26618 upstream. - -Fast short REP MOVS can be added to TCG, since a trivial translation -of string operation is a good option for short lengths. - -Intel-SIG: commit c0728d4e3d23 target/i386: add FSRM to TCG. -Add SPR/GNR/SRA new ISAs backporting - -Reviewed-by: Xiaoyao Li -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 7d779c6a8..e54a60d3c 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -661,7 +661,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | \ - /* CPUID_7_0_ECX_OSPKE is dynamic */ \ - CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) --#define TCG_7_0_EDX_FEATURES 0 -+#define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM - #define TCG_7_1_EAX_FEATURES 0 - #define TCG_APM_FEATURES 0 - #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT --- -2.25.1 diff --git a/1078-target-i386-add-FZRM-FSRS-FSRC.patch b/1078-target-i386-add-FZRM-FSRS-FSRC.patch deleted file mode 100644 index 5b872b3..0000000 --- a/1078-target-i386-add-FZRM-FSRS-FSRC.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Paolo Bonzini -Date: Mon, 27 Feb 2023 10:55:46 +0100 -Subject: [PATCH] target/i386: add FZRM, FSRS, FSRC - -commit 58794f644e43ef8e60ed05395c58099311c1fcd1 upstream. - -These are three more markers for string operation optimizations. -They can all be added to TCG, whose string operations are more or -less as fast as they can be for short lengths. - -Intel-SIG: commit 58794f644e43 target/i386: add FZRM, FSRS, FSRC. -Add SPR/GNR/SRA new ISAs backporting - -Reviewed-by: Xiaoyao Li -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 7 ++++--- - target/i386/cpu.h | 7 +++++++ - 2 files changed, 11 insertions(+), 3 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index e54a60d3c..04cb9292b 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -662,7 +662,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - /* CPUID_7_0_ECX_OSPKE is dynamic */ \ - CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) - #define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM --#define TCG_7_1_EAX_FEATURES 0 -+#define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ -+ CPUID_7_1_EAX_FSRC) - #define TCG_APM_FEATURES 0 - #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT - #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) -@@ -872,8 +873,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .feat_names = { - NULL, NULL, NULL, NULL, - "avx-vnni", "avx512-bf16", NULL, NULL, -- NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, NULL, "fzrm", "fsrs", -+ "fsrc", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 1415a33fb..98f885ace 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -879,6 +879,13 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) - /* AVX512 BFloat16 Instruction */ - #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) -+/* Fast Zero REP MOVS */ -+#define CPUID_7_1_EAX_FZRM (1U << 10) -+/* Fast Short REP STOS */ -+#define CPUID_7_1_EAX_FSRS (1U << 11) -+/* Fast Short REP CMPS/SCAS */ -+#define CPUID_7_1_EAX_FSRC (1U << 12) -+ - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) - --- -2.25.1 diff --git a/1079-i386-Add-new-CPU-model-SapphireRapids.patch b/1079-i386-Add-new-CPU-model-SapphireRapids.patch deleted file mode 100644 index 6176a1a..0000000 --- a/1079-i386-Add-new-CPU-model-SapphireRapids.patch +++ /dev/null @@ -1,226 +0,0 @@ -From: "Wang, Lei" -Date: Thu, 11 Aug 2022 22:57:51 -0700 -Subject: [PATCH] i386: Add new CPU model SapphireRapids - -commit 7eb061b06e97af9a8da7f31b839d78997ae737fc upstream. - -The new CPU model mostly inherits features from Icelake-Server, while -adding new features: - - AMX (Advance Matrix eXtensions) - - Bus Lock Debug Exception -and new instructions: - - AVX VNNI (Vector Neural Network Instruction): - - VPDPBUS: Multiply and Add Unsigned and Signed Bytes - - VPDPBUSDS: Multiply and Add Unsigned and Signed Bytes with Saturation - - VPDPWSSD: Multiply and Add Signed Word Integers - - VPDPWSSDS: Multiply and Add Signed Integers with Saturation - - FP16: Replicates existing AVX512 computational SP (FP32) instructions - using FP16 instead of FP32 for ~2X performance gain - - SERIALIZE: Provide software with a simple way to force the processor to - complete all modifications, faster, allowed in all privilege levels and - not causing an unconditional VM exit - - TSX Suspend Load Address Tracking: Allows programmers to choose which - memory accesses do not need to be tracked in the TSX read set - - AVX512_BF16: Vector Neural Network Instructions supporting BFLOAT16 - inputs and conversion instructions from IEEE single precision - - fast zero-length MOVSB (KVM doesn't support yet) - - fast short STOSB (KVM doesn't support yet) - - fast short CMPSB, SCASB (KVM doesn't support yet) - -Features that may be added in future versions: - - CET (virtualization support hasn't been merged) - -Intel-SIG: commit 7eb061b06e97 i386: Add new CPU model SapphireRapids. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Wang, Lei -Reviewed-by: Robert Hoo -Message-Id: <20220812055751.14553-1-lei4.wang@intel.com> -Reviewed-by: Xiaoyao Li -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 133 +++++++++++++++++++++++++++++++++++++++++++++- - target/i386/cpu.h | 4 ++ - 2 files changed, 135 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 04cb9292b..30d19b794 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3546,6 +3546,135 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ } - } - }, -+ { -+ .name = "SapphireRapids", -+ .level = 0x20, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 143, -+ .stepping = 4, -+ /* -+ * please keep the ascending order so that we can have a clear view of -+ * bit position of each feature. -+ */ -+ .features[FEAT_1_EDX] = -+ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | -+ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | -+ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | -+ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | -+ CPUID_SSE | CPUID_SSE2, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | -+ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | -+ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | -+ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | -+ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_WBNOINVD, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_HLE | -+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | -+ CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RTM | -+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | -+ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | -+ CPUID_7_0_EBX_AVX512IFMA | CPUID_7_0_EBX_CLFLUSHOPT | -+ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | -+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, -+ .features[FEAT_7_0_ECX] = -+ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | -+ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | -+ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | -+ CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | -+ CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57 | -+ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | -+ CPUID_7_0_EDX_TSX_LDTRK | CPUID_7_0_EDX_AMX_BF16 | -+ CPUID_7_0_EDX_AVX512_FP16 | CPUID_7_0_EDX_AMX_TILE | -+ CPUID_7_0_EDX_AMX_INT8 | CPUID_7_0_EDX_SPEC_CTRL | -+ CPUID_7_0_EDX_ARCH_CAPABILITIES | CPUID_7_0_EDX_SPEC_CTRL_SSBD, -+ .features[FEAT_ARCH_CAPABILITIES] = -+ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | -+ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | -+ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES | CPUID_D_1_EAX_XFD, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_7_1_EAX] = -+ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16 | -+ CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_FSRC, -+ .features[FEAT_VMX_BASIC] = -+ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = -+ MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_PAGE_WALK_LENGTH_5 | -+ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | -+ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | -+ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = -+ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | -+ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | -+ VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = -+ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | -+ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | -+ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | -+ VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | -+ VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | -+ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | -+ VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | -+ VMX_SECONDARY_EXEC_XSAVES, -+ .features[FEAT_VMX_VMFUNC] = -+ MSR_VMX_VMFUNC_EPT_SWITCHING, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon Processor (SapphireRapids)", -+ .versions = (X86CPUVersionDefinition[]) { -+ { .version = 1 }, -+ { /* end of list */ }, -+ }, -+ }, - { - .name = "Denverton", - .level = 21, -@@ -5616,7 +5745,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - break; - } - case 0x1D: { -- /* AMX TILE */ -+ /* AMX TILE, for now hardcoded for Sapphire Rapids*/ - *eax = 0; - *ebx = 0; - *ecx = 0; -@@ -5637,7 +5766,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - break; - } - case 0x1E: { -- /* AMX TMUL */ -+ /* AMX TMUL, for now hardcoded for Sapphire Rapids */ - *eax = 0; - *ebx = 0; - *ecx = 0; -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 98f885ace..d156ccd17 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -858,10 +858,14 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_0_EDX_SERIALIZE (1U << 14) - /* TSX Suspend Load Address Tracking instruction */ - #define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) -+/* AMX_BF16 instruction */ -+#define CPUID_7_0_EDX_AMX_BF16 (1U << 22) - /* AVX512_FP16 instruction */ - #define CPUID_7_0_EDX_AVX512_FP16 (1U << 23) - /* AMX tile (two-dimensional register) */ - #define CPUID_7_0_EDX_AMX_TILE (1U << 24) -+/* AMX_INT8 instruction */ -+#define CPUID_7_0_EDX_AMX_INT8 (1U << 25) - /* Speculation Control */ - #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) - /* Single Thread Indirect Branch Predictors */ --- -2.25.1 diff --git a/1080-target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch b/1080-target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch deleted file mode 100644 index de83c11..0000000 --- a/1080-target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch +++ /dev/null @@ -1,59 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:08 +0800 -Subject: [PATCH] target/i386: Add support for CMPCCXADD in CPUID enumeration - -commit a9ce107fd0f2017af84255a9cf6542fa3eb3e214 upstream. - -CMPccXADD is a new set of instructions in the latest Intel platform -Sierra Forest. This new instruction set includes a semaphore operation -that can compare and add the operands if condition is met, which can -improve database performance. - -The bit definition: -CPUID.(EAX=7,ECX=1):EAX[bit 7] - -Add CPUID definition for CMPCCXADD. - -Intel-SIG: commit a9ce107fd0f2 target/i386: Add support for CMPCCXADD in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-2-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 30d19b794..6a8e07904 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -872,7 +872,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { - NULL, NULL, NULL, NULL, -- "avx-vnni", "avx512-bf16", NULL, NULL, -+ "avx-vnni", "avx512-bf16", NULL, "cmpccxadd", - NULL, NULL, "fzrm", "fsrs", - "fsrc", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index d156ccd17..f8f5c1d85 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -883,6 +883,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) - /* AVX512 BFloat16 Instruction */ - #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) -+/* CMPCCXADD Instructions */ -+#define CPUID_7_1_EAX_CMPCCXADD (1U << 7) - /* Fast Zero REP MOVS */ - #define CPUID_7_1_EAX_FZRM (1U << 10) - /* Fast Short REP STOS */ --- -2.25.1 diff --git a/1081-target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch b/1081-target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch deleted file mode 100644 index b4d6ebc..0000000 --- a/1081-target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch +++ /dev/null @@ -1,60 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:09 +0800 -Subject: [PATCH] target/i386: Add support for AMX-FP16 in CPUID enumeration - -commit 99ed8445ea27742a4df40f51a3a5fbd6f8e76fa5 upstream. - -Latest Intel platform Granite Rapids has introduced a new instruction - -AMX-FP16, which performs dot-products of two FP16 tiles and accumulates -the results into a packed single precision tile. AMX-FP16 adds FP16 -capability and allows a FP16 GPU trained model to run faster without -loss of accuracy or added SW overhead. - -The bit definition: -CPUID.(EAX=7,ECX=1):EAX[bit 21] - -Add CPUID definition for AMX-FP16. - -Intel-SIG: commit 99ed8445ea27 target/i386: Add support for AMX-FP16 in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-3-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 6a8e07904..074dcb573 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -876,7 +876,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - NULL, NULL, "fzrm", "fsrs", - "fsrc", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, "amx-fp16", NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - }, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index f8f5c1d85..62f61cefb 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -891,6 +891,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EAX_FSRS (1U << 11) - /* Fast Short REP CMPS/SCAS */ - #define CPUID_7_1_EAX_FSRC (1U << 12) -+/* Support Tile Computational Operations on FP16 Numbers */ -+#define CPUID_7_1_EAX_AMX_FP16 (1U << 21) - - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) --- -2.25.1 diff --git a/1082-target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch b/1082-target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch deleted file mode 100644 index 1234f5d..0000000 --- a/1082-target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch +++ /dev/null @@ -1,58 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:10 +0800 -Subject: [PATCH] target/i386: Add support for AVX-IFMA in CPUID enumeration - -commit a957a88416ecbec51e147cba9fe89b93f6646b3b upstream. - -AVX-IFMA is a new instruction in the latest Intel platform Sierra -Forest. This instruction packed multiplies unsigned 52-bit integers and -adds the low/high 52-bit products to Qword Accumulators. - -The bit definition: -CPUID.(EAX=7,ECX=1):EAX[bit 23] - -Add CPUID definition for AVX-IFMA. - -Intel-SIG: commit a957a88416ec target/i386: Add support for AVX-IFMA in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-4-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 074dcb573..556810da8 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -876,7 +876,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - NULL, NULL, "fzrm", "fsrs", - "fsrc", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, "amx-fp16", NULL, NULL, -+ NULL, "amx-fp16", NULL, "avx-ifma", - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - }, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 62f61cefb..4f5e1f35d 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -893,6 +893,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EAX_FSRC (1U << 12) - /* Support Tile Computational Operations on FP16 Numbers */ - #define CPUID_7_1_EAX_AMX_FP16 (1U << 21) -+/* Support for VPMADD52[H,L]UQ */ -+#define CPUID_7_1_EAX_AVX_IFMA (1U << 23) - - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) --- -2.25.1 diff --git a/1083-target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch b/1083-target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch deleted file mode 100644 index 066813d..0000000 --- a/1083-target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch +++ /dev/null @@ -1,108 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:11 +0800 -Subject: [PATCH] target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration - -commit eaaa197d5b112ea2758b54df58881a2626de3af5 upstream. - -AVX-VNNI-INT8 is a new set of instructions in the latest Intel platform -Sierra Forest, aims for the platform to have superior AI capabilities. -This instruction multiplies the individual bytes of two unsigned or -unsigned source operands, then adds and accumulates the results into the -destination dword element size operand. - -The bit definition: -CPUID.(EAX=7,ECX=1):EDX[bit 4] - -AVX-VNNI-INT8 is on a new feature bits leaf. Add a CPUID feature word -FEAT_7_1_EDX for this leaf. - -Add CPUID definition for AVX-VNNI-INT8. - -Intel-SIG: commit eaaa197d5b11 target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-5-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 22 +++++++++++++++++++++- - target/i386/cpu.h | 4 ++++ - 2 files changed, 25 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 556810da8..cd7ee2473 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -664,6 +664,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - #define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM - #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ - CPUID_7_1_EAX_FSRC) -+#define TCG_7_1_EDX_FEATURES 0 - #define TCG_APM_FEATURES 0 - #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT - #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) -@@ -887,6 +888,25 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - }, - .tcg_features = TCG_7_1_EAX_FEATURES, - }, -+ [FEAT_7_1_EDX] = { -+ .type = CPUID_FEATURE_WORD, -+ .feat_names = { -+ NULL, NULL, NULL, NULL, -+ "avx-vnni-int8", NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .cpuid = { -+ .eax = 7, -+ .needs_ecx = true, .ecx = 1, -+ .reg = R_EDX, -+ }, -+ .tcg_features = TCG_7_1_EDX_FEATURES, -+ }, - [FEAT_8000_0007_EDX] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { -@@ -5525,9 +5545,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - } - } else if (count == 1) { - *eax = env->features[FEAT_7_1_EAX]; -+ *edx = env->features[FEAT_7_1_EDX]; - *ebx = 0; - *ecx = 0; -- *edx = 0; - } else { - *eax = 0; - *ebx = 0; -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 4f5e1f35d..79e456d47 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -602,6 +602,7 @@ typedef enum FeatureWord { - FEAT_SGX_12_0_EAX, /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */ - FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ - FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ -+ FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */ - FEATURE_WORDS, - } FeatureWord; - -@@ -896,6 +897,9 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - /* Support for VPMADD52[H,L]UQ */ - #define CPUID_7_1_EAX_AVX_IFMA (1U << 23) - -+/* Support for VPDPB[SU,UU,SS]D[,S] */ -+#define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) -+ - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) - --- -2.25.1 diff --git a/1084-target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch b/1084-target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch deleted file mode 100644 index 3672e8b..0000000 --- a/1084-target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch +++ /dev/null @@ -1,59 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:12 +0800 -Subject: [PATCH] target/i386: Add support for AVX-NE-CONVERT in CPUID enumeration - -commit ecd2e6ca037d7bf3673c5478590d686d5cd6135a upstream. - -AVX-NE-CONVERT is a new set of instructions which can convert low -precision floating point like BF16/FP16 to high precision floating point -FP32, as well as convert FP32 elements to BF16. This instruction allows -the platform to have improved AI capabilities and better compatibility. - -The bit definition: -CPUID.(EAX=7,ECX=1):EDX[bit 5] - -Add CPUID definition for AVX-NE-CONVERT. - -Intel-SIG: commit ecd2e6ca037d target/i386: Add support for AVX-NE-CONVERT in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-6-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index cd7ee2473..eb5e0b0b7 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -892,7 +892,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { - NULL, NULL, NULL, NULL, -- "avx-vnni-int8", NULL, NULL, NULL, -+ "avx-vnni-int8", "avx-ne-convert", NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 79e456d47..4757479ac 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -899,6 +899,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - - /* Support for VPDPB[SU,UU,SS]D[,S] */ - #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) -+/* AVX NE CONVERT Instructions */ -+#define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) - - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) --- -2.25.1 diff --git a/1085-target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch b/1085-target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch deleted file mode 100644 index 38b6f03..0000000 --- a/1085-target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch +++ /dev/null @@ -1,58 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:13 +0800 -Subject: [PATCH] target/i386: Add support for PREFETCHIT0/1 in CPUID enumeration - -commit d1a1111514333e46a98b136235f71eef90d610fa upstream. - -Latest Intel platform Granite Rapids has introduced a new instruction - -PREFETCHIT0/1, which moves code to memory (cache) closer to the -processor depending on specific hints. - -The bit definition: -CPUID.(EAX=7,ECX=1):EDX[bit 14] - -Add CPUID definition for PREFETCHIT0/1. - -Intel-SIG: commit d1a111151433 target/i386: Add support for PREFETCHIT0/1 in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-7-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index eb5e0b0b7..7738d29e8 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -894,7 +894,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - NULL, NULL, NULL, NULL, - "avx-vnni-int8", "avx-ne-convert", NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, NULL, "prefetchiti", NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 4757479ac..435f458cf 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -901,6 +901,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) - /* AVX NE CONVERT Instructions */ - #define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) -+/* PREFETCHIT0/1 Instructions */ -+#define CPUID_7_1_EDX_PREFETCHITI (1U << 14) - - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) --- -2.25.1 diff --git a/1086-target-i386-Adjust-feature-level-according-to-FEAT_7.patch b/1086-target-i386-Adjust-feature-level-according-to-FEAT_7.patch deleted file mode 100644 index d4990f0..0000000 --- a/1086-target-i386-Adjust-feature-level-according-to-FEAT_7.patch +++ /dev/null @@ -1,43 +0,0 @@ -From: Tao Su -Date: Thu, 6 Jul 2023 13:49:44 +0800 -Subject: [PATCH] target/i386: Adjust feature level according to FEAT_7_1_EDX - -commit 8731336e90dea3dd04948127e775c9f087f97a4c upstream. - -If FEAT_7_1_EAX is 0 and FEAT_7_1_EDX is non-zero, as is the case -with a Granite Rapids host and -'-cpu host,-avx-vnni,-avx512-bf16,-fzrm,-fsrs,-fsrc,-amx-fp16', we can't -get CPUID_7_1 leaf even though CPUID_7_1_EDX has non-zero value. - -Update cpuid_level_func7 according to CPUID_7_1_EDX, otherwise -guest may report wrong maximum number sub-leaves in leaf 07H. - -Fixes: eaaa197d5b11 ("target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration") -Intel-SIG: commit 8731336e90de target/i386: Adjust feature level according to FEAT_7_1_EDX. -Add SPR/GNR/SRA new ISAs backporting - -Cc: qemu-stable@nongnu.org -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-ID: <20230706054949.66556-2-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 7738d29e8..32937b0d0 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -6369,6 +6369,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX); - x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX); -+ x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX); --- -2.25.1 diff --git a/1087-target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch b/1087-target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch deleted file mode 100644 index 69cacca..0000000 --- a/1087-target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch +++ /dev/null @@ -1,40 +0,0 @@ -From: Tao Su -Date: Thu, 6 Jul 2023 13:49:47 +0800 -Subject: [PATCH] target/i386: Add new bit definitions of MSR_IA32_ARCH_CAPABILITIES - -commit 6c43ec3b206956a8a3008accafe9eb2dfd885190 upstream. - -Currently, bit 13, 14, 15 and 24 of MSR_IA32_ARCH_CAPABILITIES are -disclosed for fixing security issues, so add those bit definitions. - -Intel-SIG: commit 6c43ec3b2069 target/i386: Add new bit definitions of MSR_IA32_ARCH_CAPABILITIES. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Tao Su -Reviewed-by: Igor Mammedov -Message-ID: <20230706054949.66556-5-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.h | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 435f458cf..c65133ab6 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -977,7 +977,11 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define MSR_ARCH_CAP_PSCHANGE_MC_NO (1U << 6) - #define MSR_ARCH_CAP_TSX_CTRL_MSR (1U << 7) - #define MSR_ARCH_CAP_TAA_NO (1U << 8) -+#define MSR_ARCH_CAP_SBDR_SSDP_NO (1U << 13) -+#define MSR_ARCH_CAP_FBSDP_NO (1U << 14) -+#define MSR_ARCH_CAP_PSDP_NO (1U << 15) - #define MSR_ARCH_CAP_FB_CLEAR (1U << 17) -+#define MSR_ARCH_CAP_PBRSB_NO (1U << 24) - - #define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) - --- -2.25.1 diff --git a/1088-target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch b/1088-target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch deleted file mode 100644 index 0fcfd8e..0000000 --- a/1088-target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch +++ /dev/null @@ -1,110 +0,0 @@ -From: Tao Su -Date: Thu, 6 Jul 2023 13:49:45 +0800 -Subject: [PATCH] target/i386: Add support for MCDT_NO in CPUID enumeration - -commit 9dd8b71091f47bac395f543779269c14d8d93c60 upstream. - -CPUID.(EAX=7,ECX=2):EDX[bit 5] enumerates MCDT_NO. Processors enumerate -this bit as 1 do not exhibit MXCSR Configuration Dependent Timing (MCDT) -behavior and do not need to be mitigated to avoid data-dependent behavior -for certain instructions. - -Since MCDT_NO is in a new sub-leaf, add a new CPUID feature word -FEAT_7_2_EDX. Also update cpuid_level_func7 by FEAT_7_2_EDX. - -Intel-SIG: commit 9dd8b71091f4 target/i386: Add support for MCDT_NO in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-ID: <20230706054949.66556-3-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 26 ++++++++++++++++++++++++++ - target/i386/cpu.h | 4 ++++ - 2 files changed, 30 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 32937b0d0..0547dda2e 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -665,6 +665,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ - CPUID_7_1_EAX_FSRC) - #define TCG_7_1_EDX_FEATURES 0 -+#define TCG_7_2_EDX_FEATURES 0 - #define TCG_APM_FEATURES 0 - #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT - #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) -@@ -907,6 +908,25 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - }, - .tcg_features = TCG_7_1_EDX_FEATURES, - }, -+ [FEAT_7_2_EDX] = { -+ .type = CPUID_FEATURE_WORD, -+ .feat_names = { -+ NULL, NULL, NULL, NULL, -+ NULL, "mcdt-no", NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .cpuid = { -+ .eax = 7, -+ .needs_ecx = true, .ecx = 2, -+ .reg = R_EDX, -+ }, -+ .tcg_features = TCG_7_2_EDX_FEATURES, -+ }, - [FEAT_8000_0007_EDX] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { -@@ -5548,6 +5568,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - *edx = env->features[FEAT_7_1_EDX]; - *ebx = 0; - *ecx = 0; -+ } else if (count == 2) { -+ *edx = env->features[FEAT_7_2_EDX]; -+ *eax = 0; -+ *ebx = 0; -+ *ecx = 0; - } else { - *eax = 0; - *ebx = 0; -@@ -6370,6 +6395,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX); - x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EDX); -+ x86_cpu_adjust_feat_level(cpu, FEAT_7_2_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX); -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index c65133ab6..26572b846 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -603,6 +603,7 @@ typedef enum FeatureWord { - FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ - FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ - FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */ -+ FEAT_7_2_EDX, /* CPUID[EAX=7,ECX=2].EDX */ - FEATURE_WORDS, - } FeatureWord; - -@@ -904,6 +905,9 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - /* PREFETCHIT0/1 Instructions */ - #define CPUID_7_1_EDX_PREFETCHITI (1U << 14) - -+/* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ -+#define CPUID_7_2_EDX_MCDT_NO (1U << 5) -+ - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) - --- -2.25.1 diff --git a/1089-target-i386-Add-new-CPU-model-GraniteRapids.patch b/1089-target-i386-Add-new-CPU-model-GraniteRapids.patch deleted file mode 100644 index 938ced8..0000000 --- a/1089-target-i386-Add-new-CPU-model-GraniteRapids.patch +++ /dev/null @@ -1,181 +0,0 @@ -From: Tao Su -Date: Thu, 6 Jul 2023 13:49:49 +0800 -Subject: [PATCH] target/i386: Add new CPU model GraniteRapids - -commit 6d5e9694ef374159072984c0958c3eaab6dd1d52 upstream. - -The GraniteRapids CPU model mainly adds the following new features -based on SapphireRapids: -- PREFETCHITI CPUID.(EAX=7,ECX=1):EDX[bit 14] -- AMX-FP16 CPUID.(EAX=7,ECX=1):EAX[bit 21] - -And adds the following security fix for corresponding vulnerabilities: -- MCDT_NO CPUID.(EAX=7,ECX=2):EDX[bit 5] -- SBDR_SSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 13] -- FBSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 14] -- PSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 15] -- PBRSB_NO MSR_IA32_ARCH_CAPABILITIES[bit 24] - -Intel-SIG: commit 6d5e9694ef37 target/i386: Add new CPU model GraniteRapids. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Tao Su -Tested-by: Xuelian Guo -Reviewed-by: Xiaoyao Li -Message-ID: <20230706054949.66556-7-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 136 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 0547dda2e..b7cdca7cc 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3966,6 +3966,142 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ }, - }, - }, -+ { -+ .name = "GraniteRapids", -+ .level = 0x20, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 173, -+ .stepping = 0, -+ /* -+ * please keep the ascending order so that we can have a clear view of -+ * bit position of each feature. -+ */ -+ .features[FEAT_1_EDX] = -+ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | -+ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | -+ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | -+ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | -+ CPUID_SSE | CPUID_SSE2, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | -+ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | -+ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | -+ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | -+ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_WBNOINVD, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_HLE | -+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | -+ CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RTM | -+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | -+ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | -+ CPUID_7_0_EBX_AVX512IFMA | CPUID_7_0_EBX_CLFLUSHOPT | -+ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | -+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, -+ .features[FEAT_7_0_ECX] = -+ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | -+ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | -+ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | -+ CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | -+ CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57 | -+ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | -+ CPUID_7_0_EDX_TSX_LDTRK | CPUID_7_0_EDX_AMX_BF16 | -+ CPUID_7_0_EDX_AVX512_FP16 | CPUID_7_0_EDX_AMX_TILE | -+ CPUID_7_0_EDX_AMX_INT8 | CPUID_7_0_EDX_SPEC_CTRL | -+ CPUID_7_0_EDX_ARCH_CAPABILITIES | CPUID_7_0_EDX_SPEC_CTRL_SSBD, -+ .features[FEAT_ARCH_CAPABILITIES] = -+ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | -+ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | -+ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO | -+ MSR_ARCH_CAP_SBDR_SSDP_NO | MSR_ARCH_CAP_FBSDP_NO | -+ MSR_ARCH_CAP_PSDP_NO | MSR_ARCH_CAP_PBRSB_NO, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES | CPUID_D_1_EAX_XFD, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_7_1_EAX] = -+ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16 | -+ CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_FSRC | -+ CPUID_7_1_EAX_AMX_FP16, -+ .features[FEAT_7_1_EDX] = -+ CPUID_7_1_EDX_PREFETCHITI, -+ .features[FEAT_7_2_EDX] = -+ CPUID_7_2_EDX_MCDT_NO, -+ .features[FEAT_VMX_BASIC] = -+ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = -+ MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_PAGE_WALK_LENGTH_5 | -+ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | -+ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | -+ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = -+ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | -+ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | -+ VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = -+ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | -+ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | -+ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | -+ VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | -+ VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | -+ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | -+ VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | -+ VMX_SECONDARY_EXEC_XSAVES, -+ .features[FEAT_VMX_VMFUNC] = -+ MSR_VMX_VMFUNC_EPT_SWITCHING, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon Processor (GraniteRapids)", -+ .versions = (X86CPUVersionDefinition[]) { -+ { .version = 1 }, -+ { /* end of list */ }, -+ }, -+ }, - { - .name = "KnightsMill", - .level = 0xd, --- -2.25.1 diff --git a/1090-target-i386-Add-support-for-AMX-COMPLEX-in-CPUID-enu.patch b/1090-target-i386-Add-support-for-AMX-COMPLEX-in-CPUID-enu.patch deleted file mode 100644 index 5d175da..0000000 --- a/1090-target-i386-Add-support-for-AMX-COMPLEX-in-CPUID-enu.patch +++ /dev/null @@ -1,57 +0,0 @@ -From: Tao Su -Date: Wed, 30 Aug 2023 15:43:24 +0800 -Subject: [PATCH] target/i386: Add support for AMX-COMPLEX in CPUID enumeration - -commit 3e76bafb28c8292be5c4a32cab873b3a82cbcc87 upstream. - -Latest Intel platform GraniteRapids-D introduces AMX-COMPLEX, which adds -two instructions to perform matrix multiplication of two tiles containing -complex elements and accumulate the results into a packed single precision -tile. - -AMX-COMPLEX is enumerated via CPUID.(EAX=7,ECX=1):EDX[bit 8]. Add the CPUID -definition for AMX-COMPLEX, AMX-COMPLEX will be enabled automatically when -using '-cpu host' and KVM advertises AMX-COMPLEX to userspace. - -Intel-SIG: commit 3e76bafb28c8 target/i386: Add support for AMX-COMPLEX in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-ID: <20230830074324.84059-1-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index b7cdca7cc..4a33baade 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -894,7 +894,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .feat_names = { - NULL, NULL, NULL, NULL, - "avx-vnni-int8", "avx-ne-convert", NULL, NULL, -- NULL, NULL, NULL, NULL, -+ "amx-complex", NULL, NULL, NULL, - NULL, NULL, "prefetchiti", NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 26572b846..e84cb8265 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -902,6 +902,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) - /* AVX NE CONVERT Instructions */ - #define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) -+/* AMX COMPLEX Instructions */ -+#define CPUID_7_1_EDX_AMX_COMPLEX (1U << 8) - /* PREFETCHIT0/1 Instructions */ - #define CPUID_7_1_EDX_PREFETCHITI (1U << 14) - --- -2.25.1 diff --git a/1091-target-i386-Add-new-CPU-model-SierraForest.patch b/1091-target-i386-Add-new-CPU-model-SierraForest.patch deleted file mode 100644 index 8ab9a09..0000000 --- a/1091-target-i386-Add-new-CPU-model-SierraForest.patch +++ /dev/null @@ -1,207 +0,0 @@ -From: Tao Su -Date: Wed, 20 Mar 2024 10:10:44 +0800 -Subject: [PATCH] target/i386: Add new CPU model SierraForest - -commit 6e82d3b6220777667968a04c87e1667f164ebe88 upstream. - -According to table 1-2 in Intel Architecture Instruction Set Extensions and -Future Features (rev 051) [1], SierraForest has the following new features -which have already been virtualized: - -- CMPCCXADD CPUID.(EAX=7,ECX=1):EAX[bit 7] -- AVX-IFMA CPUID.(EAX=7,ECX=1):EAX[bit 23] -- AVX-VNNI-INT8 CPUID.(EAX=7,ECX=1):EDX[bit 4] -- AVX-NE-CONVERT CPUID.(EAX=7,ECX=1):EDX[bit 5] - -Add above features to new CPU model SierraForest. Comparing with GraniteRapids -CPU model, SierraForest bare-metal removes the following features: - -- HLE CPUID.(EAX=7,ECX=0):EBX[bit 4] -- RTM CPUID.(EAX=7,ECX=0):EBX[bit 11] -- AVX512F CPUID.(EAX=7,ECX=0):EBX[bit 16] -- AVX512DQ CPUID.(EAX=7,ECX=0):EBX[bit 17] -- AVX512_IFMA CPUID.(EAX=7,ECX=0):EBX[bit 21] -- AVX512CD CPUID.(EAX=7,ECX=0):EBX[bit 28] -- AVX512BW CPUID.(EAX=7,ECX=0):EBX[bit 30] -- AVX512VL CPUID.(EAX=7,ECX=0):EBX[bit 31] -- AVX512_VBMI CPUID.(EAX=7,ECX=0):ECX[bit 1] -- AVX512_VBMI2 CPUID.(EAX=7,ECX=0):ECX[bit 6] -- AVX512_VNNI CPUID.(EAX=7,ECX=0):ECX[bit 11] -- AVX512_BITALG CPUID.(EAX=7,ECX=0):ECX[bit 12] -- AVX512_VPOPCNTDQ CPUID.(EAX=7,ECX=0):ECX[bit 14] -- LA57 CPUID.(EAX=7,ECX=0):ECX[bit 16] -- TSXLDTRK CPUID.(EAX=7,ECX=0):EDX[bit 16] -- AMX-BF16 CPUID.(EAX=7,ECX=0):EDX[bit 22] -- AVX512_FP16 CPUID.(EAX=7,ECX=0):EDX[bit 23] -- AMX-TILE CPUID.(EAX=7,ECX=0):EDX[bit 24] -- AMX-INT8 CPUID.(EAX=7,ECX=0):EDX[bit 25] -- AVX512_BF16 CPUID.(EAX=7,ECX=1):EAX[bit 5] -- fast zero-length MOVSB CPUID.(EAX=7,ECX=1):EAX[bit 10] -- fast short CMPSB, SCASB CPUID.(EAX=7,ECX=1):EAX[bit 12] -- AMX-FP16 CPUID.(EAX=7,ECX=1):EAX[bit 21] -- PREFETCHI CPUID.(EAX=7,ECX=1):EDX[bit 14] -- XFD CPUID.(EAX=0xD,ECX=1):EAX[bit 4] -- EPT_PAGE_WALK_LENGTH_5 VMX_EPT_VPID_CAP(0x48c)[bit 7] - -Add all features of GraniteRapids CPU model except above features to -SierraForest CPU model. - -SierraForest doesn’t support TSX and RTM but supports TAA_NO. When RTM is -not enabled in host, KVM will not report TAA_NO. So, just don't include -TAA_NO in SierraForest CPU model. - -[1] https://cdrdv2.intel.com/v1/dl/getContent/671368 - -Intel-SIG: commit 6e82d3b62207 target/i386: Add new CPU model SierraForest. -Add SPR/GNR/SRA new ISAs backporting - -Reviewed-by: Zhao Liu -Reviewed-by: Xiaoyao Li -Signed-off-by: Tao Su -Message-ID: <20240320021044.508263-1-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 126 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 4a33baade..00157dae9 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3715,6 +3715,132 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ }, - }, - }, -+ { -+ .name = "SierraForest", -+ .level = 0x23, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 175, -+ .stepping = 0, -+ /* -+ * please keep the ascending order so that we can have a clear view of -+ * bit position of each feature. -+ */ -+ .features[FEAT_1_EDX] = -+ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | -+ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | -+ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | -+ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | -+ CPUID_SSE | CPUID_SSE2, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | -+ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | -+ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | -+ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | -+ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_WBNOINVD, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | -+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | -+ CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | -+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB | -+ CPUID_7_0_EBX_SHA_NI, -+ .features[FEAT_7_0_ECX] = -+ CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_GFNI | -+ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | -+ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | -+ CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_ARCH_CAPABILITIES | -+ CPUID_7_0_EDX_SPEC_CTRL_SSBD, -+ .features[FEAT_ARCH_CAPABILITIES] = -+ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | -+ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | -+ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_SBDR_SSDP_NO | -+ MSR_ARCH_CAP_FBSDP_NO | MSR_ARCH_CAP_PSDP_NO | -+ MSR_ARCH_CAP_PBRSB_NO, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_7_1_EAX] = -+ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_CMPCCXADD | -+ CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_AVX_IFMA, -+ .features[FEAT_7_1_EDX] = -+ CPUID_7_1_EDX_AVX_VNNI_INT8 | CPUID_7_1_EDX_AVX_NE_CONVERT, -+ .features[FEAT_7_2_EDX] = -+ CPUID_7_2_EDX_MCDT_NO, -+ .features[FEAT_VMX_BASIC] = -+ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = -+ MSR_VMX_EPT_EXECONLY | MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | -+ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | -+ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | -+ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = -+ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | -+ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | -+ VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = -+ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | -+ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | -+ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | -+ VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | -+ VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | -+ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | -+ VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | -+ VMX_SECONDARY_EXEC_XSAVES, -+ .features[FEAT_VMX_VMFUNC] = -+ MSR_VMX_VMFUNC_EPT_SWITCHING, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon Processor (SierraForest)", -+ .versions = (X86CPUVersionDefinition[]) { -+ { .version = 1 }, -+ { /* end of list */ }, -+ }, -+ }, - { - .name = "Denverton", - .level = 21, --- -2.25.1 diff --git a/1092-target-i386-Export-RFDS-bit-to-guests.patch b/1092-target-i386-Export-RFDS-bit-to-guests.patch deleted file mode 100644 index 87d9465..0000000 --- a/1092-target-i386-Export-RFDS-bit-to-guests.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: Pawan Gupta -Date: Wed, 13 Mar 2024 07:53:23 -0700 -Subject: [PATCH] target/i386: Export RFDS bit to guests - -commit 41bdd9812863c150284a9339a048ed88c40f4df7 upstream. - -Register File Data Sampling (RFDS) is a CPU side-channel vulnerability -that may expose stale register value. CPUs that set RFDS_NO bit in MSR -IA32_ARCH_CAPABILITIES indicate that they are not vulnerable to RFDS. -Similarly, RFDS_CLEAR indicates that CPU is affected by RFDS, and has -the microcode to help mitigate RFDS. - -Make RFDS_CLEAR and RFDS_NO bits available to guests. - -Intel-SIG: commit 41bdd9812863 target/i386: Export RFDS bit to guests. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Pawan Gupta -Reviewed-by: Xiaoyao Li -Reviewed-by: Zhao Liu -Message-ID: <9a38877857392b5c2deae7e7db1b170d15510314.1710341348.git.pawan.kumar.gupta@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 00157dae9..80c3b58d1 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1025,8 +1025,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - NULL, NULL, NULL, NULL, - NULL, "fb-clear", NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, "rfds-no", -+ "rfds-clear", NULL, NULL, NULL, - }, - .msr = { - .index = MSR_IA32_ARCH_CAPABILITIES, --- -2.25.1 diff --git a/1093-target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch b/1093-target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch deleted file mode 100644 index 48bd838..0000000 --- a/1093-target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch +++ /dev/null @@ -1,50 +0,0 @@ -From: Lei Wang -Date: Thu, 6 Jul 2023 13:49:48 +0800 -Subject: [PATCH] target/i386: Add few security fix bits in ARCH_CAPABILITIES into SapphireRapids CPU model - -commit 3baf7ae63505eb1652d1e52d65798307fead8539 upstream. - -SapphireRapids has bit 13, 14 and 15 of MSR_IA32_ARCH_CAPABILITIES -enabled, which are related to some security fixes. - -Add version 2 of SapphireRapids CPU model with those bits enabled also. - -Intel-SIG: commit 3baf7ae63505 target/i386: Add few security fix bits in ARCH_CAPABILITIES into SapphireRapids CPU model. -6.2-SPR new model support - -Signed-off-by: Lei Wang -Signed-off-by: Tao Su -Message-ID: <20230706054949.66556-6-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 0a3c76854..8a045e065 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3762,8 +3762,17 @@ static const X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Xeon Processor (SapphireRapids)", - .versions = (X86CPUVersionDefinition[]) { - { .version = 1 }, -- { /* end of list */ }, -- }, -+ { -+ .version = 2, -+ .props = (PropValue[]) { -+ { "sbdr-ssdp-no", "on" }, -+ { "fbsdp-no", "on" }, -+ { "psdp-no", "on" }, -+ { /* end of list */ } -+ } -+ }, -+ { /* end of list */ } -+ } - }, - { - .name = "SierraForest", --- -2.25.1 diff --git a/1094-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch b/1094-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch deleted file mode 100644 index a035ee1..0000000 --- a/1094-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: Lei Wang -Date: Wed, 24 Apr 2024 03:29:12 -0400 -Subject: [PATCH] target/i386: Introduce SapphireRapids-v3 to add missing features - -commit b10b2481738304db13d28252e86c10555121a5b3 upstream. - -Add the missing features(ss, tsc-adjust, cldemote, movdiri, movdir64b) in -the SapphireRapids-v3 CPU model. - -Intel-SIG: commit b10b24817383 target/i386: Introduce SapphireRapids-v3 to add missing features. -6.2-SPR new model support - -Signed-off-by: Lei Wang -Message-ID: <20240424072912.43188-1-lei4.wang@intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index f4b5c95c5..baa1a8207 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3730,6 +3730,17 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ } - } - }, -+ { -+ .version = 3, -+ .props = (PropValue[]) { -+ { "ss", "on" }, -+ { "tsc-adjust", "on" }, -+ { "cldemote", "on" }, -+ { "movdiri", "on" }, -+ { "movdir64b", "on" }, -+ { /* end of list */ } -+ } -+ }, - { /* end of list */ } - } - }, --- -2.25.1 diff --git a/1095-ebpf-replace-deprecated-bpf_program__set_socket_filt.patch b/1095-ebpf-replace-deprecated-bpf_program__set_socket_filt.patch deleted file mode 100644 index 574626b..0000000 --- a/1095-ebpf-replace-deprecated-bpf_program__set_socket_filt.patch +++ /dev/null @@ -1,37 +0,0 @@ -From: Haochen Tong -Date: Sat, 28 May 2022 03:06:58 +0800 -Subject: [PATCH] ebpf: replace deprecated bpf_program__set_socket_filter - -commit a495eba03c31c96d6a0817b13598ce2219326691 upstream. - -bpf_program__set_ functions have been deprecated since libbpf 0.8. -Replace with the equivalent bpf_program__set_type call to avoid a -deprecation warning. - -Intel-SIG: commit a495eba03c31 ebpf: replace deprecated bpf_program__set_socket_filter. -6.2-SPR new model support - -Signed-off-by: Haochen Tong -Reviewed-by: Zhang Chen -Signed-off-by: Jason Wang -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - ebpf/ebpf_rss.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c -index 118c68da83..cee658c158 100644 ---- a/ebpf/ebpf_rss.c -+++ b/ebpf/ebpf_rss.c -@@ -49,7 +49,7 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx) - goto error; - } - -- bpf_program__set_socket_filter(rss_bpf_ctx->progs.tun_rss_steering_prog); -+ bpf_program__set_type(rss_bpf_ctx->progs.tun_rss_steering_prog, BPF_PROG_TYPE_SOCKET_FILTER); - - if (rss_bpf__load(rss_bpf_ctx)) { - trace_ebpf_error("eBPF RSS", "can not load RSS program"); --- -2.25.1 diff --git a/1096-target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch b/1096-target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch deleted file mode 100644 index 0387342..0000000 --- a/1096-target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: Pawan Gupta -Date: Fri, 23 Jun 2023 13:26:25 -0700 -Subject: [PATCH] target/i386: Export MSR_ARCH_CAPABILITIES bits to guests - -commit 5bef742cc4f0e21c80a31611af7881ba811e507f upstream. - -On Intel CPUs there are certain bits in MSR_ARCH_CAPABILITIES that -indicates if the CPU is not affected by a vulnerability. Without these -bits guests may try to deploy the mitigation even if the CPU is not -affected. - -Export the bits to guests that indicate immunity to hardware -vulnerabilities. - -Intel-SIG: commit 5bef742cc4f0 target/i386: Export MSR_ARCH_CAPABILITIES bits to guests. -6.2-SPR new model support - -Signed-off-by: Pawan Gupta -Message-ID: <63d85cc76d4cdc51e6c732478b81d8f13be11e5a.1687551881.git.pawan.kumar.gupta@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 11f52c79b..62149367b 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1022,10 +1022,10 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - "rdctl-no", "ibrs-all", "rsba", "skip-l1dfl-vmentry", - "ssb-no", "mds-no", "pschange-mc-no", "tsx-ctrl", - "taa-no", NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, "sbdr-ssdp-no", "fbsdp-no", "psdp-no", - NULL, "fb-clear", NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, "rfds-no", -+ "pbrsb-no", NULL, NULL, "rfds-no", - "rfds-clear", NULL, NULL, NULL, - }, - .msr = { --- -2.25.1 diff --git a/81-kvm-anolis.rules b/81-kvm-rhel.rules similarity index 100% rename from 81-kvm-anolis.rules rename to 81-kvm-rhel.rules diff --git a/Add-lbt-support-for-kvm.patch b/Add-lbt-support-for-kvm.patch deleted file mode 100644 index 660785f..0000000 --- a/Add-lbt-support-for-kvm.patch +++ /dev/null @@ -1,154 +0,0 @@ -From b7760c4fd70de74df6014394c5d27d498fed3e31 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 08:00:52 -0400 -Subject: [PATCH 22/28] Add lbt support for kvm - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 4 ++-- - linux-headers/asm-loongarch64/kvm.h | 10 ++++++++- - target/loongarch64/cpu.h | 10 +++++++++ - target/loongarch64/kvm.c | 35 +++++++++++++++++++++++++++++ - 4 files changed, 56 insertions(+), 3 deletions(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 8fc79546d..2affc5048 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -348,8 +348,8 @@ struct kvm_cpucfg ls3a5k_cpucfgs = { - CPUCFG1_IOCSRBRD, - .cpucfg[LOONGARCH_CPUCFG2] = CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP | - CPUCFG2_FPVERS | CPUCFG2_LSX | CPUCFG2_LASX | CPUCFG2_COMPLEX | -- CPUCFG2_CRYPTO | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | CPUCFG2_LSPW | -- CPUCFG2_LAM, -+ CPUCFG2_CRYPTO | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | CPUCFG2_X86BT | -+ CPUCFG2_ARMBT | CPUCFG2_MIPSBT | CPUCFG2_LSPW | CPUCFG2_LAM, - .cpucfg[LOONGARCH_CPUCFG3] = CPUCFG3_CCDMA | CPUCFG3_SFB | CPUCFG3_UCACC | - CPUCFG3_LLEXC | CPUCFG3_SCDLY | CPUCFG3_LLDBAR | CPUCFG3_ITLBT | - CPUCFG3_ICACHET | CPUCFG3_SPW_LVL | CPUCFG3_SPW_HG_HF | CPUCFG3_RVA | -diff --git a/linux-headers/asm-loongarch64/kvm.h b/linux-headers/asm-loongarch64/kvm.h -index 799af7594..3687a358f 100644 ---- a/linux-headers/asm-loongarch64/kvm.h -+++ b/linux-headers/asm-loongarch64/kvm.h -@@ -77,6 +77,7 @@ struct kvm_fpu { - * Register set = 2: KVM specific registers (see definitions below). - * - * Register set = 3: FPU / MSA registers (see definitions below). -+ * Register set = 4: LBT registers (see definitions below). - * - * Other sets registers may be added in the future. Each set would - * have its own identifier in bits[31..16]. -@@ -86,7 +87,7 @@ struct kvm_fpu { - #define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x0000000000010000ULL) - #define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x0000000000020000ULL) - #define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x0000000000030000ULL) -- -+#define KVM_REG_LOONGARCH_LBT (KVM_REG_LOONGARCH | 0x0000000000040000ULL) - - /* - * KVM_REG_LOONGARCH_GP - General purpose registers from kvm_regs. -@@ -168,6 +169,13 @@ struct kvm_fpu { - - #define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4) - -+#define KVM_REG_LBT_SCR0 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 1) -+#define KVM_REG_LBT_SCR1 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 2) -+#define KVM_REG_LBT_SCR2 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 3) -+#define KVM_REG_LBT_SCR3 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 4) -+#define KVM_REG_LBT_FLAGS (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 5) -+#define KVM_REG_LBT_FTOP (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 6) -+ - struct kvm_iocsr_entry { - __u32 addr; - __u32 pad; -diff --git a/target/loongarch64/cpu.h b/target/loongarch64/cpu.h -index 078556a22..ab88658e4 100644 ---- a/target/loongarch64/cpu.h -+++ b/target/loongarch64/cpu.h -@@ -55,6 +55,7 @@ typedef struct CPULOONGARCHFPUContext { - uint32_t fcsr0; - uint32_t fcsr0_rw_bitmask; - uint32_t vcsr16; -+ uint64_t ftop; - } CPULOONGARCHFPUContext; - - /* fp control and status register definition */ -@@ -167,6 +168,15 @@ struct CPULOONGARCHState { - struct { - uint64_t guest_addr; - } st; -+ struct { -+ /* scratch registers */ -+ unsigned long scr0; -+ unsigned long scr1; -+ unsigned long scr2; -+ unsigned long scr3; -+ /* loongarch eflag */ -+ unsigned long eflag; -+ } lbt; - }; - - -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -index b6711da91..0eaabe394 100644 ---- a/target/loongarch64/kvm.c -+++ b/target/loongarch64/kvm.c -@@ -1295,6 +1295,39 @@ int kvm_loongarch_get_pvtime(LOONGARCHCPU *cpu) - return 0; - } - -+ -+static int kvm_loongarch_put_lbt_registers(CPUState *cs) -+{ -+ int ret = 0; -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR0, &env->lbt.scr0); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR1, &env->lbt.scr1); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR2, &env->lbt.scr2); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR3, &env->lbt.scr3); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_FLAGS, &env->lbt.eflag); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_FTOP, &env->active_fpu.ftop); -+ -+ return ret; -+} -+ -+static int kvm_loongarch_get_lbt_registers(CPUState *cs) -+{ -+ int ret = 0; -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR0, &env->lbt.scr0); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR1, &env->lbt.scr1); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR2, &env->lbt.scr2); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR3, &env->lbt.scr3); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_FLAGS, &env->lbt.eflag); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_FTOP, &env->active_fpu.ftop); -+ -+ return ret; -+} -+ - int kvm_arch_put_registers(CPUState *cs, int level) - { - LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -@@ -1326,6 +1359,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) - return ret; - } - -+ kvm_loongarch_put_lbt_registers(cs); - return ret; - } - -@@ -1352,6 +1386,7 @@ int kvm_arch_get_registers(CPUState *cs) - - kvm_loongarch_get_csr_registers(cs); - kvm_loongarch_get_fpu_registers(cs); -+ kvm_loongarch_get_lbt_registers(cs); - - return ret; - } --- -2.43.5 - diff --git a/Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch b/Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch deleted file mode 100644 index 330b37d..0000000 --- a/Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 3e8ddd1af3c46387ed45319dd0dc3c0a673b989f Mon Sep 17 00:00:00 2001 -From: Tianrui Zhao -Date: Mon, 19 Jun 2023 09:38:16 +0800 -Subject: [PATCH 25/28] Add loongarch into QEMU_ARCH_VIRTIO_PCI to support qdev - alias - -Signed-off-by: Tianrui Zhao ---- - softmmu/qdev-monitor.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c -index 01f3834db..ece96121d 100644 ---- a/softmmu/qdev-monitor.c -+++ b/softmmu/qdev-monitor.c -@@ -60,7 +60,8 @@ typedef struct QDevAlias - QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \ - QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \ - QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \ -- QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA) -+ QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \ -+ QEMU_ARCH_LOONGARCH64) - #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X) - #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K) - --- -2.43.5 - diff --git a/Add-usb-storage-config-for-loongarch.patch b/Add-usb-storage-config-for-loongarch.patch deleted file mode 100644 index 0529515..0000000 --- a/Add-usb-storage-config-for-loongarch.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 1f41256389e5d8862d08b2253d752569727f1e79 Mon Sep 17 00:00:00 2001 -From: Tianrui Zhao -Date: Mon, 19 Jun 2023 09:34:02 +0800 -Subject: [PATCH 24/28] Add usb-storage config for loongarch - -Signed-off-by: Tianrui Zhao ---- - configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -index 696ee9b72..15fc2d00f 100644 ---- a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -+++ b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -@@ -147,6 +147,8 @@ CONFIG_USB_EHCI=y - CONFIG_USB_EHCI_PCI=y - CONFIG_USB_EHCI_SYSBUS=y - CONFIG_USB_STORAGE_BOT=y -+CONFIG_USB_STORAGE_CORE=y -+CONFIG_USB_STORAGE_CLASSIC=y - CONFIG_TPM_EMULATOR=y - CONFIG_TPM_TIS=y - CONFIG_PLATFORM_BUS=y --- -2.43.5 - diff --git a/Fix-LoongArch-KVM-header-macros.patch b/Fix-LoongArch-KVM-header-macros.patch deleted file mode 100644 index 57ea9d8..0000000 --- a/Fix-LoongArch-KVM-header-macros.patch +++ /dev/null @@ -1,32 +0,0 @@ -From d090e30797ef1acc5f0f5488a60040606f60ff44 Mon Sep 17 00:00:00 2001 -From: Tianrui Zhao -Date: Tue, 20 Jun 2023 16:34:43 +0800 -Subject: [PATCH 27/28] Fix LoongArch KVM header macros - -Signed-off-by: Tianrui Zhao ---- - linux-headers/linux/kvm.h | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index f5589b068..0e50d3749 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -2126,10 +2126,10 @@ struct kvm_loongarch_vcpu_state { - __u64 core_ext_ioisr[4]; - }; - --#define KVM_CAP_LOONGARCH_FPU 800 --#define KVM_CAP_LOONGARCH_LSX 801 --#define KVM_CAP_LOONGARCH_VZ 802 --#define KVM_REG_LOONGARCH 0x9000000000000000ULL -+#define KVM_CAP_LOONGARCH_FPU 165 -+#define KVM_CAP_LOONGARCH_LSX 166 -+#define KVM_CAP_LOONGARCH_VZ 167 -+#define KVM_REG_LOONGARCH 0x8000000000000000ULL - #define KVM_LARCH_GET_VCPU_STATE _IOR(KVMIO, 0xc0, struct kvm_loongarch_vcpu_state) - #define KVM_LARCH_SET_VCPU_STATE _IOW(KVMIO, 0xc1, struct kvm_loongarch_vcpu_state) - #define KVM_LARCH_GET_CPUCFG _IOR(KVMIO, 0xc2, struct kvm_cpucfg) --- -2.43.5 - diff --git a/Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch b/Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch deleted file mode 100644 index 9d6896c..0000000 --- a/Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ff15ca716d827e6364e51f1ee9d7bc6440d55c20 Mon Sep 17 00:00:00 2001 -From: Tianrui Zhao -Date: Mon, 19 Jun 2023 16:38:29 +0800 -Subject: [PATCH 26/28] Fix host architecture macro of LoongArch to - HOST_LOONGARCH64 - -Signed-off-by: Tianrui Zhao ---- - accel/kvm/kvm-all.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 48034d427..6d63f0ab0 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -2503,7 +2503,7 @@ static int kvm_init(MachineState *ms) - soft_vcpus_limit = kvm_recommended_vcpus(s); - hard_vcpus_limit = kvm_max_vcpus(s); - --#if defined(HOST_PPC64) || defined(HOST_LOONGARCH) -+#if defined(HOST_PPC64) || defined(HOST_LOONGARCH64) - /* - * On POWER, the kernel advertises a soft limit based on the - * number of CPU threads on the host. We want to allow exceeding --- -2.43.5 - diff --git a/Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch b/Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch deleted file mode 100644 index 09a842d..0000000 --- a/Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch +++ /dev/null @@ -1,31 +0,0 @@ -From d24d2e0d530e6354d4f9a4b213983779136f4ab7 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:38:26 -0400 -Subject: [PATCH 16/28] Fix irq routing and fpu option to compat with kernel - v6.4 - -Fix set irq routing and enable fpu for kvm to compat -with kernel v6.4 - -Signed-off-by: lixianglai ---- - target/loongarch64/kvm.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -index 6885ec6c9..b6711da91 100644 ---- a/target/loongarch64/kvm.c -+++ b/target/loongarch64/kvm.c -@@ -107,6 +107,9 @@ int kvm_arch_init_vcpu(CPUState *cs) - CPULOONGARCHState *env = &cpu->env; - int ret = 0; - -+ kvm_vcpu_enable_cap(cs, KVM_CAP_LOONGARCH_FPU, 0, 0); -+ kvm_vcpu_enable_cap(cs, KVM_CAP_LOONGARCH_LSX, 0, 0); -+ - cpu->cpuStateEntry = qemu_add_vm_change_state_handler(kvm_loongarch_update_state, cs); - cpu->kvm_csr_buf = g_malloc0(CSR_BUF_SIZE + CSR_BUF_SIZE); - --- -2.43.5 - diff --git a/Fix-smp.cores-value.patch b/Fix-smp.cores-value.patch deleted file mode 100644 index 9517ef9..0000000 --- a/Fix-smp.cores-value.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 902dc77676bc6ada74ddbdb57d00821435550bdb Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:55:12 -0400 -Subject: [PATCH 21/28] Fix smp.cores value - -The smp.cores should use the default value passed from -qemu start command, and the argument is cores_per_socket. - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index b1501e0ea..8fc79546d 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -1211,14 +1211,7 @@ static void loongarch_build_smbios(LoongarchMachineState *lsms) - uint8_t *smbios_tables, *smbios_anchor; - size_t smbios_tables_len, smbios_anchor_len; - const char *product = "QEMU Virtual Machine"; -- int nb_numa_nodes, smp_cpus; - -- smp_cpus = ms->smp.cpus; -- nb_numa_nodes = ms->numa_state->num_nodes; -- if (nb_numa_nodes == 0) { -- nb_numa_nodes = 1; -- } -- ms->smp.cores = smp_cpus / nb_numa_nodes; - if (!lsms->fw_cfg) { - return; - } --- -2.43.5 - diff --git a/Fixed-the-issue-where-qemu-specifies-the-boot-order.patch b/Fixed-the-issue-where-qemu-specifies-the-boot-order.patch deleted file mode 100644 index b86a981..0000000 --- a/Fixed-the-issue-where-qemu-specifies-the-boot-order.patch +++ /dev/null @@ -1,140 +0,0 @@ -From d280c3a4a6ea0b3b9bf03bd4d4bd36b7e763287e Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Wed, 23 Aug 2023 07:10:25 -0400 -Subject: [PATCH 28/28] Fixed the issue where qemu specifies the boot order - -Fixed the issue that the device path of bootorder -in the generated fw_cfg was abnormal because the -PCIeHost device did not initialize the memory space -of sysbus, which caused the QEMU boot order to not -take effect. - -Change-Id: Ifde4c8b8432c5c8748c1b38a3c33bafef4f24083 -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 14 -------------- - hw/loongarch/ls7a_nb.c | 28 ++++++++++++++++++++++++++-- - include/hw/loongarch/larch.h | 6 ++++++ - include/hw/loongarch/ls7a.h | 2 ++ - 4 files changed, 34 insertions(+), 16 deletions(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 2affc5048..1a4e982b7 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -86,12 +86,6 @@ - - #define TARGET_REALPAGE_MASK (TARGET_PAGE_MASK << 2) - --#ifdef CONFIG_KVM --#define LS_ISA_IO_SIZE 0x02000000 --#else --#define LS_ISA_IO_SIZE 0x00010000 --#endif -- - #ifdef CONFIG_KVM - #define align(x) (((x) + 63) & ~63) - #else -@@ -1618,8 +1612,6 @@ static void ls3a5k_init(MachineState *args) - ram_addr_t ram_size = args->ram_size; - MemoryRegion *address_space_mem = get_system_memory(); - ram_addr_t offset = 0; -- MemoryRegion *isa_io = g_new(MemoryRegion, 1); -- MemoryRegion *isa_mem = g_new(MemoryRegion, 1); - MachineState *machine = args; - MachineClass *mc = MACHINE_GET_CLASS(machine); - LoongarchMachineState *lsms = LoongarchMACHINE(machine); -@@ -1799,12 +1791,6 @@ static void ls3a5k_init(MachineState *args) - &machine->device_memory->mr); - } - -- memory_region_init_alias(isa_io, NULL, "isa-io", -- get_system_io(), 0, LS_ISA_IO_SIZE); -- memory_region_init(isa_mem, NULL, "isa-mem", PCIE_MEMORY_SIZE); -- memory_region_add_subregion(get_system_memory(), lsmc->isa_io_base, isa_io); -- memory_region_add_subregion(get_system_memory(), PCIE_MEMORY_BASE, isa_mem); -- - if (!strcmp(lsmc->bridge_name, "ls7a")) { - /*Initialize the 7A IO interrupt subsystem*/ - DeviceState *ls7a_dev; -diff --git a/hw/loongarch/ls7a_nb.c b/hw/loongarch/ls7a_nb.c -index 5a231e6f0..f11b855a7 100644 ---- a/hw/loongarch/ls7a_nb.c -+++ b/hw/loongarch/ls7a_nb.c -@@ -162,17 +162,41 @@ static PCIBus *pci_ls7a_init(MachineState *machine, DeviceState *dev, - { - LoongarchMachineState *lsms = LoongarchMACHINE(machine); - LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ LS7APCIEHost *pciehost = LS7A_PCIE_HOST_BRIDGE(dev); - PCIExpressHost *e; -+ SysBusDevice *sysbus; - PCIHostState *phb; -+ MemoryRegion *mmio_alias; - - e = PCIE_HOST_BRIDGE(dev); -+ sysbus = SYS_BUS_DEVICE(e); - phb = PCI_HOST_BRIDGE(e); -+ -+ sysbus_init_mmio(sysbus, &e->mmio); -+ -+ memory_region_init(&pciehost->io_mmio, OBJECT(pciehost), -+ "pciehost-mmio", UINT64_MAX); -+ sysbus_init_mmio(sysbus, &pciehost->io_mmio); -+ mmio_alias = g_new0(MemoryRegion, 1); -+ memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", -+ &pciehost->io_mmio, PCIE_MEMORY_BASE, -+ PCIE_MEMORY_SIZE); -+ memory_region_add_subregion(get_system_memory(), -+ PCIE_MEMORY_BASE, mmio_alias); -+ -+ memory_region_init(&pciehost->io_ioport, OBJECT(pciehost), -+ "pciehost-ioport", LS_ISA_IO_SIZE); -+ sysbus_init_mmio(sysbus, &pciehost->io_ioport); -+ -+ sysbus_mmio_map(sysbus, 2, LS3A5K_ISA_IO_BASE); -+ -+ - phb->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq, - pci_ls7a_map_irq, pic, -- get_system_memory(), get_system_io(), -+ &pciehost->io_mmio, &pciehost->io_ioport, - (1 << 3), 128, TYPE_PCIE_BUS); -+ /*update pcie config memory*/ - pcie_host_mmcfg_update(e, true, lsmc->pciecfg_base, LS_PCIECFG_SIZE); -- DPRINTF("------ %d\n", __LINE__); - - pci_bus_set_route_irq_fn(phb->bus, ls7a_route_intx_pin_to_irq); - -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -index b8f28e330..3f4fdd946 100644 ---- a/include/hw/loongarch/larch.h -+++ b/include/hw/loongarch/larch.h -@@ -40,6 +40,12 @@ - #define LOONGARCH_HOTPLUG_MEM_ALIGN (1ULL << 28) - #define LOONGARCH_MAX_RAM_SLOTS 10 - -+#ifdef CONFIG_KVM -+#define LS_ISA_IO_SIZE 0x02000000 -+#else -+#define LS_ISA_IO_SIZE 0x00010000 -+#endif -+ - /* Memory types: */ - #define SYSTEM_RAM 1 - #define SYSTEM_RAM_RESERVED 2 -diff --git a/include/hw/loongarch/ls7a.h b/include/hw/loongarch/ls7a.h -index 63a070296..05edee603 100644 ---- a/include/hw/loongarch/ls7a.h -+++ b/include/hw/loongarch/ls7a.h -@@ -121,6 +121,8 @@ - typedef struct LS7APCIState LS7APCIState; - typedef struct LS7APCIEHost { - PCIExpressHost parent_obj; -+ MemoryRegion io_ioport; -+ MemoryRegion io_mmio; - LS7APCIState *pci_dev; - } LS7APCIEHost; - --- -2.43.5 - diff --git a/Modify-smbios-option-lack-and-Modify-the-maximum-num.patch b/Modify-smbios-option-lack-and-Modify-the-maximum-num.patch deleted file mode 100644 index 10eb346..0000000 --- a/Modify-smbios-option-lack-and-Modify-the-maximum-num.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 3839b5ecff1bb68ed03e0cb901acfd331668d4fd Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 05:48:46 -0400 -Subject: [PATCH 10/28] Modify smbios option lack and Modify the maximum number - of CPUs supported by the virtual machine. - -Add smbios option support for loongarch. -The number of virtual CPUs can be greater than the number of CPUs of the host machine. - -Signed-off-by: lixianglai ---- - accel/kvm/kvm-all.c | 2 +- - qemu-options.hx | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 3b7bc3982..48034d427 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -2503,7 +2503,7 @@ static int kvm_init(MachineState *ms) - soft_vcpus_limit = kvm_recommended_vcpus(s); - hard_vcpus_limit = kvm_max_vcpus(s); - --#ifdef HOST_PPC64 -+#if defined(HOST_PPC64) || defined(HOST_LOONGARCH) - /* - * On POWER, the kernel advertises a soft limit based on the - * number of CPU threads on the host. We want to allow exceeding -diff --git a/qemu-options.hx b/qemu-options.hx -index 981248e28..1b3f2df49 100644 ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -2480,7 +2480,7 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, - " specify SMBIOS type 17 fields\n" - "-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]\n" - " specify SMBIOS type 41 fields\n", -- QEMU_ARCH_I386 | QEMU_ARCH_ARM) -+ QEMU_ARCH_I386 | QEMU_ARCH_ARM | QEMU_ARCH_LOONGARCH64) - SRST - ``-smbios file=binary`` - Load SMBIOS entry from binary file. --- -2.43.5 - diff --git a/Modify-the-ioctl-command-of-kvm.patch b/Modify-the-ioctl-command-of-kvm.patch deleted file mode 100644 index 6b41fb1..0000000 --- a/Modify-the-ioctl-command-of-kvm.patch +++ /dev/null @@ -1,32 +0,0 @@ -From c593589f83c7655dcd8b9c144bf6061933d4ed40 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 08:44:26 -0400 -Subject: [PATCH 23/28] Modify the ioctl command of kvm. - -Signed-off-by: lixianglai ---- - linux-headers/linux/kvm.h | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 0e50d3749..f5589b068 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -2126,10 +2126,10 @@ struct kvm_loongarch_vcpu_state { - __u64 core_ext_ioisr[4]; - }; - --#define KVM_CAP_LOONGARCH_FPU 165 --#define KVM_CAP_LOONGARCH_LSX 166 --#define KVM_CAP_LOONGARCH_VZ 167 --#define KVM_REG_LOONGARCH 0x8000000000000000ULL -+#define KVM_CAP_LOONGARCH_FPU 800 -+#define KVM_CAP_LOONGARCH_LSX 801 -+#define KVM_CAP_LOONGARCH_VZ 802 -+#define KVM_REG_LOONGARCH 0x9000000000000000ULL - #define KVM_LARCH_GET_VCPU_STATE _IOR(KVMIO, 0xc0, struct kvm_loongarch_vcpu_state) - #define KVM_LARCH_SET_VCPU_STATE _IOW(KVMIO, 0xc1, struct kvm_loongarch_vcpu_state) - #define KVM_LARCH_GET_CPUCFG _IOR(KVMIO, 0xc2, struct kvm_cpucfg) --- -2.43.5 - diff --git a/Support-TPM.patch b/Support-TPM.patch deleted file mode 100644 index 8bfa530..0000000 --- a/Support-TPM.patch +++ /dev/null @@ -1,518 +0,0 @@ -From 8eea4ea57942c83f0e1d9d4073004409505fda59 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:16:34 -0400 -Subject: [PATCH 13/28] Support TPM. - -Signed-off-by: lixianglai ---- - hw/loongarch/acpi-build.c | 44 +++++++ - hw/loongarch/larch_3a.c | 53 ++++++++- - hw/loongarch/larch_hotplug.c | 16 ++- - hw/loongarch/meson.build | 1 + - hw/loongarch/sysbus-fdt.c | 183 ++++++++++++++++++++++++++++++ - include/hw/loongarch/larch.h | 1 + - include/hw/loongarch/ls7a.h | 5 + - include/hw/loongarch/sysbus-fdt.h | 37 ++++++ - 8 files changed, 333 insertions(+), 7 deletions(-) - create mode 100644 hw/loongarch/sysbus-fdt.c - create mode 100644 include/hw/loongarch/sysbus-fdt.h - -diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c -index 6ba637be5..682e016be 100644 ---- a/hw/loongarch/acpi-build.c -+++ b/hw/loongarch/acpi-build.c -@@ -58,6 +58,7 @@ - #include "hw/acpi/aml-build.h" - #include "hw/loongarch/larch.h" - #include "hw/loongarch/ls7a.h" -+#include "hw/platform-bus.h" - - #include "hw/acpi/ipmi.h" - #include "hw/acpi/ls7a.h" -@@ -474,7 +475,40 @@ static void build_ls7a_uart_device_aml(Aml *table) - aml_append(scope, dev); - aml_append(table, scope); - } -+#ifdef CONFIG_TPM -+static void acpi_dsdt_add_tpm(Aml *scope, LoongarchMachineState *vms) -+{ -+ PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); -+ hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS; -+ SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find()); -+ MemoryRegion *sbdev_mr; -+ hwaddr tpm_base; -+ -+ if (!sbdev) { -+ return; -+ } -+ -+ tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); -+ assert(tpm_base != -1); - -+ tpm_base += pbus_base; -+ -+ sbdev_mr = sysbus_mmio_get_region(sbdev, 0); -+ -+ Aml *dev = aml_device("TPM0"); -+ aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); -+ aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device"))); -+ aml_append(dev, aml_name_decl("_UID", aml_int(0))); -+ -+ Aml *crs = aml_resource_template(); -+ aml_append(crs, -+ aml_memory32_fixed(tpm_base, -+ (uint32_t)memory_region_size(sbdev_mr), -+ AML_READ_WRITE)); -+ aml_append(dev, aml_name_decl("_CRS", crs)); -+ aml_append(scope, dev); -+} -+#endif - static void - build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) - { -@@ -500,6 +534,10 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) - aml_append(dev, aml_name_decl("_UID", aml_int(1))); - aml_append(dev, build_ls7a_osc_method()); - aml_append(sb_scope, dev); -+ -+#ifdef CONFIG_TPM -+ acpi_dsdt_add_tpm(sb_scope, lsms); -+#endif - aml_append(dsdt, sb_scope); - - build_ls7a_pci0_int(dsdt); -@@ -633,6 +671,12 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) - lsms->oem_table_id); - } - -+ if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) { -+ acpi_add_table(table_offsets, tables_blob); -+ build_tpm2(tables_blob, tables->linker, tables->tcpalog, -+ lsms->oem_id, lsms->oem_table_id); -+ } -+ - /* Build mcfg */ - acpi_add_table(table_offsets, tables_blob); - { -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 3194a822c..6c2602050 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -52,6 +52,7 @@ - #include "hw/rtc/mc146818rtc.h" - #include "hw/irq.h" - #include "net/net.h" -+#include "hw/platform-bus.h" - #include "hw/timer/i8254.h" - #include "hw/loongarch/larch.h" - #include "hw/loongarch/ls7a.h" -@@ -65,6 +66,8 @@ - #include "sysemu/device_tree.h" - #include "qapi/visitor.h" - #include "qapi/qapi-visit-common.h" -+#include "sysemu/tpm.h" -+#include "hw/loongarch/sysbus-fdt.h" - - #include - -@@ -1235,6 +1238,19 @@ void loongarch_machine_done(Notifier *notifier, void *data) - { - LoongarchMachineState *lsms = container_of(notifier, - LoongarchMachineState, machine_done); -+ -+ platform_bus_add_all_fdt_nodes(lsms->fdt, NULL, -+ VIRT_PLATFORM_BUS_BASEADDRESS, -+ VIRT_PLATFORM_BUS_SIZE, -+ VIRT_PLATFORM_BUS_IRQ); -+ -+ qemu_fdt_dumpdtb(lsms->fdt, lsms->fdt_size); -+ /* load fdt */ -+ MemoryRegion *fdt_rom = g_new(MemoryRegion, 1); -+ memory_region_init_rom(fdt_rom, NULL, "fdt", LS_FDT_SIZE, &error_fatal); -+ memory_region_add_subregion(get_system_memory(), LS_FDT_BASE, fdt_rom); -+ rom_add_blob_fixed("fdt", lsms->fdt, lsms->fdt_size, LS_FDT_BASE); -+ - loongarch_acpi_setup(); - loongarch_build_smbios(lsms); - } -@@ -1562,7 +1578,31 @@ static void fdt_add_pcie_node(const LoongarchMachineState *lsms) - 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, - 2, base_mmio, 2, size_mmio); - g_free(nodename); -- qemu_fdt_dumpdtb(lsms->fdt, lsms->fdt_size); -+} -+ -+static void create_platform_bus(LoongarchMachineState *s, qemu_irq *pic) -+{ -+ DeviceState *dev; -+ SysBusDevice *sysbus; -+ int i; -+ MemoryRegion *sysmem = get_system_memory(); -+ -+ dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); -+ dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); -+ qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS); -+ qdev_prop_set_uint32(dev, "mmio_size", VIRT_PLATFORM_BUS_SIZE); -+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); -+ s->platform_bus_dev = dev; -+ -+ sysbus = SYS_BUS_DEVICE(dev); -+ for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) { -+ int irq = VIRT_PLATFORM_BUS_IRQ + i; -+ sysbus_connect_irq(sysbus, i, pic[irq - LOONGARCH_PCH_IRQ_BASE]); -+ } -+ -+ memory_region_add_subregion(sysmem, -+ VIRT_PLATFORM_BUS_BASEADDRESS, -+ sysbus_mmio_get_region(sysbus, 0)); - } - - static void ls3a5k_init(MachineState *args) -@@ -1784,6 +1824,8 @@ static void ls3a5k_init(MachineState *args) - object_property_set_link(OBJECT(machine), LOONGARCH_MACHINE_ACPI_DEVICE_PROP, - OBJECT(ls7a_dev), &error_abort); - -+ create_platform_bus(lsms, ls7a_apic); -+ - #ifdef CONFIG_KVM - if (kvm_enabled()) { - kvm_direct_msi_allowed = (kvm_check_extension(kvm_state, -@@ -1835,11 +1877,6 @@ static void ls3a5k_init(MachineState *args) - - fdt_add_pcie_node(lsms); - -- /* load fdt */ -- MemoryRegion *fdt_rom = g_new(MemoryRegion, 1); -- memory_region_init_rom(fdt_rom, NULL, "fdt", LS_FDT_SIZE, &error_fatal); -- memory_region_add_subregion(get_system_memory(), LS_FDT_BASE, fdt_rom); -- rom_add_blob_fixed("fdt", lsms->fdt, lsms->fdt_size, LS_FDT_BASE); - } - - static const CPUArchIdList *loongarch_possible_cpu_arch_ids(MachineState *ms) -@@ -1986,6 +2023,10 @@ static void loongarch_class_init(ObjectClass *oc, void *data) - mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000"); - mc->default_ram_id = "loongarch_ls3a.ram"; - -+#ifdef CONFIG_TPM -+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); -+#endif -+ - mc->reset = ls3a_board_reset; - mc->max_cpus = LOONGARCH_MAX_VCPUS; - hc->pre_plug = loongarch_machine_device_pre_plug; -diff --git a/hw/loongarch/larch_hotplug.c b/hw/loongarch/larch_hotplug.c -index 7bce95712..bb3e9826b 100644 ---- a/hw/loongarch/larch_hotplug.c -+++ b/hw/loongarch/larch_hotplug.c -@@ -32,6 +32,7 @@ - #include "hw/loongarch/larch.h" - #include "hw/cpu/core.h" - #include "hw/nvram/fw_cfg.h" -+#include "hw/platform-bus.h" - - /* find cpu slot in machine->possible_cpus by core_id */ - static CPUArchId *loongarch_find_cpu_slot(MachineState *ms, uint32_t id, -@@ -327,7 +328,8 @@ HotplugHandler *loongarch_get_hotpug_handler(MachineState *machine, - DeviceState *dev) - { - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || -- object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU) || -+ object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)) { - return HOTPLUG_HANDLER(machine); - } - return NULL; -@@ -346,6 +348,18 @@ void loongarch_machine_device_pre_plug(HotplugHandler *hotplug_dev, - void loongarch_machine_device_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) - { -+ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); -+ -+ if (lsms->platform_bus_dev) { -+ MachineClass *mc = MACHINE_GET_CLASS(lsms); -+ -+ if (device_is_dynamic_sysbus(mc, dev)) { -+ platform_bus_link_device( -+ PLATFORM_BUS_DEVICE(lsms->platform_bus_dev), -+ SYS_BUS_DEVICE(dev)); -+ } -+ } -+ - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - loongarch_memory_plug(hotplug_dev, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build -index 81ee99a02..47d886ddd 100644 ---- a/hw/loongarch/meson.build -+++ b/hw/loongarch/meson.build -@@ -9,6 +9,7 @@ loongarch_ss.add(files( - 'ipi.c', - 'apic.c', - 'iocsr.c', -+ 'sysbus-fdt.c', - )) - - hw_arch += {'loongarch64': loongarch_ss} -diff --git a/hw/loongarch/sysbus-fdt.c b/hw/loongarch/sysbus-fdt.c -new file mode 100644 -index 000000000..f750ad6b6 ---- /dev/null -+++ b/hw/loongarch/sysbus-fdt.c -@@ -0,0 +1,183 @@ -+/* -+ * Loongarch Platform Bus device tree generation helpers -+ * -+ * Copyright (c) 2014 Linaro Limited -+ * -+ * Authors: -+ * Alex Graf -+ * Eric Auger -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program. If not, see . -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include -+#include "qemu/error-report.h" -+#include "sysemu/device_tree.h" -+#include "hw/platform-bus.h" -+#include "hw/display/ramfb.h" -+#include "hw/loongarch/sysbus-fdt.h" -+#include "sysemu/tpm.h" -+ -+/* -+ * internal struct that contains the information to create dynamic -+ * sysbus device node -+ */ -+typedef struct PlatformBusFDTData { -+ void *fdt; /* device tree handle */ -+ int irq_start; /* index of the first IRQ usable by platform bus devices */ -+ const char *pbus_node_name; /* name of the platform bus node */ -+ PlatformBusDevice *pbus; -+} PlatformBusFDTData; -+ -+/* struct that allows to match a device and create its FDT node */ -+typedef struct BindingEntry { -+ const char *typename; -+ const char *compat; -+ int (*add_fn)(SysBusDevice *sbdev, void *opaque); -+ bool (*match_fn)(SysBusDevice *sbdev, const struct BindingEntry *combo); -+} BindingEntry; -+ -+ -+ -+static int no_fdt_node(SysBusDevice *sbdev, void *opaque) -+{ -+ return 0; -+} -+ -+/* Device type based matching */ -+static bool type_match(SysBusDevice *sbdev, const BindingEntry *entry) -+{ -+ return !strcmp(object_get_typename(OBJECT(sbdev)), entry->typename); -+} -+ -+#define TYPE_BINDING(type, add_fn) {(type), NULL, (add_fn), NULL} -+ -+#ifdef CONFIG_TPM -+/* -+ * add_tpm_tis_fdt_node: Create a DT node for TPM TIS -+ * -+ * See kernel documentation: -+ * Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt -+ * Optional interrupt for command completion is not exposed -+ */ -+static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque) -+{ -+ PlatformBusFDTData *data = opaque; -+ PlatformBusDevice *pbus = data->pbus; -+ void *fdt = data->fdt; -+ const char *parent_node = data->pbus_node_name; -+ char *nodename; -+ uint32_t reg_attr[2]; -+ uint64_t mmio_base; -+ -+ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); -+ nodename = g_strdup_printf("%s/tpm_tis@%" PRIx64, parent_node, mmio_base); -+ qemu_fdt_add_subnode(fdt, nodename); -+ -+ qemu_fdt_setprop_string(fdt, nodename, "compatible", "tcg,tpm-tis-mmio"); -+ -+ reg_attr[0] = cpu_to_be32(mmio_base); -+ reg_attr[1] = cpu_to_be32(0x5000); -+ qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, 2 * sizeof(uint32_t)); -+ -+ g_free(nodename); -+ -+ return 0; -+} -+#endif -+ -+/* list of supported dynamic sysbus bindings */ -+static const BindingEntry bindings[] = { -+#ifdef CONFIG_TPM -+ TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node), -+#endif -+ TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node), -+ TYPE_BINDING("", NULL), /* last element */ -+}; -+ -+/* Generic Code */ -+ -+/** -+ * add_fdt_node - add the device tree node of a dynamic sysbus device -+ * -+ * @sbdev: handle to the sysbus device -+ * @opaque: handle to the PlatformBusFDTData -+ * -+ * Checks the sysbus type belongs to the list of device types that -+ * are dynamically instantiable and if so call the node creation -+ * function. -+ */ -+static void add_fdt_node(SysBusDevice *sbdev, void *opaque) -+{ -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(bindings); i++) { -+ const BindingEntry *iter = &bindings[i]; -+ -+ if (type_match(sbdev, iter)) { -+ if (!iter->match_fn || iter->match_fn(sbdev, iter)) { -+ ret = iter->add_fn(sbdev, opaque); -+ assert(!ret); -+ return; -+ } -+ } -+ } -+ error_report("Device %s can not be dynamically instantiated", -+ qdev_fw_name(DEVICE(sbdev))); -+ exit(1); -+} -+ -+void platform_bus_add_all_fdt_nodes(void *fdt, const char *intc, hwaddr addr, -+ hwaddr bus_size, int irq_start) -+{ -+ const char platcomp[] = "qemu,platform\0simple-bus"; -+ PlatformBusDevice *pbus; -+ DeviceState *dev; -+ gchar *node; -+ -+ assert(fdt); -+ -+ node = g_strdup_printf("/platform@%"PRIx64, addr); -+ -+ /* Create a /platform node that we can put all devices into */ -+ qemu_fdt_add_subnode(fdt, node); -+ qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); -+ -+ /* -+ * Our platform bus region is less than 32bits, so 1 cell is enough for -+ * address and size -+ */ -+ qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); -+ qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); -+ qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, bus_size); -+ if (intc != NULL) { -+ qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", intc); -+ } -+ dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE); -+ pbus = PLATFORM_BUS_DEVICE(dev); -+ -+ PlatformBusFDTData data = { -+ .fdt = fdt, -+ .irq_start = irq_start, -+ .pbus_node_name = node, -+ .pbus = pbus, -+ }; -+ -+ /* Loop through all dynamic sysbus devices and create their node */ -+ foreach_dynamic_sysbus_device(add_fdt_node, &data); -+ -+ g_free(node); -+} -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -index 62e2830e2..81dcb78f4 100644 ---- a/include/hw/loongarch/larch.h -+++ b/include/hw/loongarch/larch.h -@@ -103,6 +103,7 @@ typedef struct LoongarchMachineState { - void *fdt; - int fdt_size; - unsigned int hotpluged_cpu_num; -+ DeviceState *platform_bus_dev; - OnOffAuto acpi; - char *oem_id; - char *oem_table_id; -diff --git a/include/hw/loongarch/ls7a.h b/include/hw/loongarch/ls7a.h -index 686af763a..fc78083be 100644 ---- a/include/hw/loongarch/ls7a.h -+++ b/include/hw/loongarch/ls7a.h -@@ -121,6 +121,11 @@ - #define INT_ROUTER_REGS_CORE2_INTISR 0x50 - #define INT_ROUTER_REGS_CORE3_INTISR 0x58 - -+#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 -+#define VIRT_PLATFORM_BUS_SIZE 0x2000000 -+#define VIRT_PLATFORM_BUS_NUM_IRQS 2 -+#define VIRT_PLATFORM_BUS_IRQ 69 -+ - typedef struct LS7APCIState LS7APCIState; - typedef struct LS7APCIEHost { - PCIExpressHost parent_obj; -diff --git a/include/hw/loongarch/sysbus-fdt.h b/include/hw/loongarch/sysbus-fdt.h -new file mode 100644 -index 000000000..340c382cd ---- /dev/null -+++ b/include/hw/loongarch/sysbus-fdt.h -@@ -0,0 +1,37 @@ -+/* -+ * Dynamic sysbus device tree node generation API -+ * -+ * Copyright Linaro Limited, 2014 -+ * -+ * Authors: -+ * Alex Graf -+ * Eric Auger -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program. If not, see . -+ * -+ */ -+ -+#ifndef HW_ARM_SYSBUS_FDT_H -+#define HW_ARM_SYSBUS_FDT_H -+ -+#include "exec/hwaddr.h" -+ -+/** -+ * platform_bus_add_all_fdt_nodes - create all the platform bus nodes -+ * -+ * builds the parent platform bus node and all the nodes of dynamic -+ * sysbus devices attached to it. -+ */ -+void platform_bus_add_all_fdt_nodes(void *fdt, const char *intc, hwaddr addr, -+ hwaddr bus_size, int irq_start); -+#endif --- -2.43.5 - diff --git a/Support-vfio-config.patch b/Support-vfio-config.patch deleted file mode 100644 index 01b2bb6..0000000 --- a/Support-vfio-config.patch +++ /dev/null @@ -1,47 +0,0 @@ -From e2e67dd2c2b0c3ff2737cd477bfc79cac64d4053 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:41:14 -0400 -Subject: [PATCH 17/28] Support vfio config - -Signed-off-by: lixianglai ---- - configs/devices/loongarch64-softmmu/default.mak | 9 +++++++++ - .../loongarch64-softmmu/loongarch64-rh-devices.mak | 8 ++++++++ - 2 files changed, 17 insertions(+) - -diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak -index fcb7e45dd..b4994d8a6 100644 ---- a/configs/devices/loongarch64-softmmu/default.mak -+++ b/configs/devices/loongarch64-softmmu/default.mak -@@ -152,3 +152,12 @@ CONFIG_PLATFORM_BUS=y - CONFIG_TPM_TIS_SYSBUS=y - CONFIG_ACPI_LOONGARCH=y - CONFIG_LS7A_RTC=y -+ -+#vfio config -+CONFIG_VFIO=y -+CONFIG_VFIO_PCI=y -+CONFIG_VFIO_PLATFORM=y -+CONFIG_VFIO_XGMAC=y -+CONFIG_VFIO_AMD_XGBE=y -+ -+ -diff --git a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -index e7b5bdc8e..696ee9b72 100644 ---- a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -+++ b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -@@ -153,3 +153,11 @@ CONFIG_PLATFORM_BUS=y - CONFIG_TPM_TIS_SYSBUS=y - CONFIG_ACPI_LOONGARCH=y - CONFIG_LS7A_RTC=y -+ -+#vfio config -+CONFIG_VFIO=y -+CONFIG_VFIO_PCI=y -+CONFIG_VFIO_PLATFORM=y -+CONFIG_VFIO_XGMAC=y -+CONFIG_VFIO_AMD_XGBE=y -+ --- -2.43.5 - diff --git a/address-space-code-cleanup-on-7A-virt-machine.patch b/address-space-code-cleanup-on-7A-virt-machine.patch deleted file mode 100644 index 61c4d78..0000000 --- a/address-space-code-cleanup-on-7A-virt-machine.patch +++ /dev/null @@ -1,276 +0,0 @@ -From 731b161d2cfddb67e4088282a33acaf90c2bd928 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:33:26 -0400 -Subject: [PATCH 15/28] address space code cleanup on 7A virt-machine. - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 16 +++----- - hw/loongarch/ls7a_nb.c | 49 ------------------------- - include/hw/loongarch/larch.h | 1 - - include/hw/loongarch/ls7a.h | 71 ++++++++++++++++-------------------- - 4 files changed, 37 insertions(+), 100 deletions(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 6c2602050..6eaa53d74 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -88,10 +88,8 @@ - - #ifdef CONFIG_KVM - #define LS_ISA_IO_SIZE 0x02000000 --#define LS_ISA_MEM_SIZE 0x40000000 - #else - #define LS_ISA_IO_SIZE 0x00010000 --#define LS_ISA_MEM_SIZE 0x01000000 - #endif - - #ifdef CONFIG_KVM -@@ -626,8 +624,8 @@ static struct irq_source_routing_table *init_irq_source(void *g_irq_source) - irq_info->ht_enable = 0x0000d17b; - irq_info->node_id = 0; - -- irq_info->pci_mem_start_addr = LS_ISA_MEM_BASE; -- irq_info->pci_mem_end_addr = irq_info->pci_mem_start_addr + LS_ISA_MEM_SIZE - 1; -+ irq_info->pci_mem_start_addr = PCIE_MEMORY_BASE; -+ irq_info->pci_mem_end_addr = irq_info->pci_mem_start_addr + PCIE_MEMORY_SIZE - 1; - - if (strstr(lsmc->cpu_name, "5000")) { - irq_info->pci_io_start_addr = LS3A5K_ISA_IO_BASE; -@@ -1551,8 +1549,8 @@ static void fdt_add_fw_cfg_node(const LoongarchMachineState *lsms) - static void fdt_add_pcie_node(const LoongarchMachineState *lsms) - { - char *nodename; -- hwaddr base_mmio = LS_ISA_MEM_BASE; -- hwaddr size_mmio = LS_ISA_MEM_SIZE; -+ hwaddr base_mmio = PCIE_MEMORY_BASE; -+ hwaddr size_mmio = PCIE_MEMORY_SIZE; - hwaddr base_pio = LS3A5K_ISA_IO_BASE; - hwaddr size_pio = LS_ISA_IO_SIZE; - hwaddr base_pcie = LS_PCIECFG_BASE; -@@ -1650,7 +1648,6 @@ static void ls3a5k_init(MachineState *args) - create_fdt(lsms); - - DPRINTF("isa 0x%lx\n", lsmc->isa_io_base); -- DPRINTF("ht1lo 0x%lx\n", lsmc->ht1lo_pcicfg_base); - DPRINTF("cpu_name %s bridge_name %s\n", - lsmc->cpu_name, lsmc->bridge_name); - -@@ -1800,9 +1797,9 @@ static void ls3a5k_init(MachineState *args) - - memory_region_init_alias(isa_io, NULL, "isa-io", - get_system_io(), 0, LS_ISA_IO_SIZE); -- memory_region_init(isa_mem, NULL, "isa-mem", LS_ISA_MEM_SIZE); -+ memory_region_init(isa_mem, NULL, "isa-mem", PCIE_MEMORY_SIZE); - memory_region_add_subregion(get_system_memory(), lsmc->isa_io_base, isa_io); -- memory_region_add_subregion(get_system_memory(), LS_ISA_MEM_BASE, isa_mem); -+ memory_region_add_subregion(get_system_memory(), PCIE_MEMORY_BASE, isa_mem); - - if (!strcmp(lsmc->bridge_name, "ls7a")) { - /*Initialize the 7A IO interrupt subsystem*/ -@@ -1950,7 +1947,6 @@ static void ls3a5k_ls7a_machine_options(MachineClass *m) - m->alias = "loongson7a"; - m->is_default = 1; - lsmc->isa_io_base = LS3A5K_ISA_IO_BASE; -- lsmc->ht1lo_pcicfg_base = LS3A5K_HT1LO_PCICFG_BASE; - lsmc->pciecfg_base = LS_PCIECFG_BASE; - lsmc->ls7a_ioapic_reg_base = LS3A5K_LS7A_IOAPIC_REG_BASE; - lsmc->node_shift = 44; -diff --git a/hw/loongarch/ls7a_nb.c b/hw/loongarch/ls7a_nb.c -index 5a500fbd5..5a231e6f0 100644 ---- a/hw/loongarch/ls7a_nb.c -+++ b/hw/loongarch/ls7a_nb.c -@@ -108,7 +108,6 @@ static const VMStateDescription vmstate_ls7a_pcie = { - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, LS7APCIState), - VMSTATE_STRUCT(pm, LS7APCIState, 0, vmstate_ls7a_pm, LS7APCIPMRegs), -- VMSTATE_UINT32_ARRAY(regs, LS7APCIState, LS7A_REGS), - VMSTATE_END_OF_LIST() - } - }; -@@ -153,47 +152,6 @@ static void ls7a_pcie_realize(PCIDevice *dev, Error **errp) - qemu_register_reset(ls7a_reset, s); - } - --static void pci_ls7a_config_write(void *opaque, hwaddr addr, -- uint64_t val, unsigned size) --{ -- hwaddr tmp_addr; -- tmp_addr = addr & 0xffffff; -- -- pci_data_write(opaque, tmp_addr, val, size); --} -- --static uint64_t pci_ls7a_config_read(void *opaque, -- hwaddr addr, unsigned size) --{ -- uint64_t val; -- hwaddr tmp_addr; -- -- tmp_addr = addr & 0xffffff; -- val = pci_data_read(opaque, tmp_addr, size); -- -- if (addr & 0x3c) { -- DPRINTF(TARGET_FMT_plx" val %lx\n", addr, val); -- } -- return val; --} -- --static const MemoryRegionOps pci_ls7a_config_ops = { -- .read = pci_ls7a_config_read, -- .write = pci_ls7a_config_write, -- /* Set to access 64bits data, because default to 32bits*/ -- .valid = { -- .min_access_size = 1, -- .max_access_size = 4, -- }, -- /* Set to access 64bits data, because default to 32bits*/ -- .impl = { -- .min_access_size = 1, -- .max_access_size = 4, -- }, -- .endianness = DEVICE_NATIVE_ENDIAN, -- --}; -- - static AddressSpace *ls7a_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) - { - return &address_space_memory; -@@ -205,12 +163,9 @@ static PCIBus *pci_ls7a_init(MachineState *machine, DeviceState *dev, - LoongarchMachineState *lsms = LoongarchMACHINE(machine); - LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); - PCIExpressHost *e; -- SysBusDevice *sysbus; -- MemoryRegion *iomem = g_new(MemoryRegion, 1); - PCIHostState *phb; - - e = PCIE_HOST_BRIDGE(dev); -- sysbus = SYS_BUS_DEVICE(e); - phb = PCI_HOST_BRIDGE(e); - phb->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq, - pci_ls7a_map_irq, pic, -@@ -220,10 +175,6 @@ static PCIBus *pci_ls7a_init(MachineState *machine, DeviceState *dev, - DPRINTF("------ %d\n", __LINE__); - - pci_bus_set_route_irq_fn(phb->bus, ls7a_route_intx_pin_to_irq); -- memory_region_init_io(iomem, NULL, &pci_ls7a_config_ops, phb->bus, -- "ls7a_pci_conf", HT1LO_PCICFG_SIZE); -- sysbus_init_mmio(sysbus, iomem); -- sysbus_mmio_map(sysbus, 0, lsmc->ht1lo_pcicfg_base); - - return phb->bus; - } -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -index 81dcb78f4..b8f28e330 100644 ---- a/include/hw/loongarch/larch.h -+++ b/include/hw/loongarch/larch.h -@@ -64,7 +64,6 @@ typedef struct LoongarchMachineClass { - uint64_t ht_control_regs_base; - uint64_t hpet_mmio_addr; - uint64_t smbus_cfg_base; -- uint64_t ht1lo_pcicfg_base; - uint64_t pciecfg_base; - uint64_t ls7a_ioapic_reg_base; - uint32_t node_shift; -diff --git a/include/hw/loongarch/ls7a.h b/include/hw/loongarch/ls7a.h -index fc78083be..63a070296 100644 ---- a/include/hw/loongarch/ls7a.h -+++ b/include/hw/loongarch/ls7a.h -@@ -39,44 +39,33 @@ - #define ACPI_IO_SIZE (LS7A_ACPI_IO_SIZE) - #define ACPI_SCI_IRQ (LS7A_SCI_IRQ) - --#define LS3A5K_ISA_IO_BASE 0x18000000UL --#define LS_ISA_MEM_BASE 0x40000000 --#define LS3A5K_HT1LO_PCICFG_BASE 0x1a000000 --#define HT1LO_PCICFG_SIZE 0x02000000 -+#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 -+#define VIRT_PLATFORM_BUS_SIZE 0x02000000 -+#define VIRT_PLATFORM_BUS_NUM_IRQS 2 -+#define VIRT_PLATFORM_BUS_IRQ (LOONGARCH_PCH_IRQ_BASE + 5) -+ -+#define LS3A5K_ISA_IO_BASE 0x18000000UL - #define LS_BIOS_BASE 0x1c000000 - #define LS_BIOS_VAR_BASE 0x1c3a0000 --#define LS_BIOS_SIZE (4 * 1024 * 1024) -- --#define FW_CFG_ADDR 0x1e020000 --#define LS7A_REG_BASE 0x1FE00000 --#define LS7A_PCICONFIG_BASE (LS7A_REG_BASE + 0x30) --#define LS7A_PCICONFIG_SIZE (0x100) --#define LS7A_INTERNAL_REG_BASE (LS7A_REG_BASE + 0x100) --#define LS7A_INTERNAL_REG_SIZE (0xE0) --#define LS7A_REGS (0xE0 >> 2) --#define LS7A_UART_BASE 0x1fe001e0 --#define LS7A_UART_LEN 0x8 -- --#define LS_FDT_BASE 0x1c400000 --#define LS_FDT_SIZE 0x100000 -- --#define LS_PCIECFG_BASE 0x20000000 --#define LS_PCIECFG_SIZE 0x08000000 --#define MSI_ADDR_LOW 0x2FF00000 --#define MSI_ADDR_HI 0x0 -- -+#define LS_BIOS_SIZE (4 * 1024 * 1024) -+#define LS_FDT_BASE 0x1c400000 -+#define LS_FDT_SIZE 0x00100000 -+ -+#define FW_CFG_ADDR 0x1e020000 -+#define LS7A_REG_BASE 0x1FE00000 -+#define LS7A_UART_BASE 0x1fe001e0 -+#define LS7A_UART_LEN 0x8 - #define SMP_GIPI_MAILBOX 0x1f000000ULL --#define CORE0_STATUS_OFF 0x000 --#define CORE0_EN_OFF 0x004 --#define CORE0_SET_OFF 0x008 --#define CORE0_CLEAR_OFF 0x00c --#define CORE0_BUF_20 0x020 --#define CORE0_BUF_28 0x028 --#define CORE0_BUF_30 0x030 --#define CORE0_BUF_38 0x038 --#define CORE0_IPI_SEND 0x040 --#define CORE0_MAIL_SEND 0x048 -- -+#define CORE0_STATUS_OFF 0x000 -+#define CORE0_EN_OFF 0x004 -+#define CORE0_SET_OFF 0x008 -+#define CORE0_CLEAR_OFF 0x00c -+#define CORE0_BUF_20 0x020 -+#define CORE0_BUF_28 0x028 -+#define CORE0_BUF_30 0x030 -+#define CORE0_BUF_38 0x038 -+#define CORE0_IPI_SEND 0x040 -+#define CORE0_MAIL_SEND 0x048 - #define INT_ROUTER_REGS_BASE 0x1fe01400UL - #define INT_ROUTER_REGS_SIZE 0x100 - #define INT_ROUTER_REGS_SYS_INT0 0x00 -@@ -121,10 +110,13 @@ - #define INT_ROUTER_REGS_CORE2_INTISR 0x50 - #define INT_ROUTER_REGS_CORE3_INTISR 0x58 - --#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 --#define VIRT_PLATFORM_BUS_SIZE 0x2000000 --#define VIRT_PLATFORM_BUS_NUM_IRQS 2 --#define VIRT_PLATFORM_BUS_IRQ 69 -+#define LS_PCIECFG_BASE 0x20000000 -+#define LS_PCIECFG_SIZE 0x08000000 -+#define MSI_ADDR_LOW 0x2FF00000 -+#define MSI_ADDR_HI 0x0 -+ -+#define PCIE_MEMORY_BASE 0x40000000 -+#define PCIE_MEMORY_SIZE 0x40000000 - - typedef struct LS7APCIState LS7APCIState; - typedef struct LS7APCIEHost { -@@ -136,7 +128,6 @@ struct LS7APCIState { - PCIDevice dev; - - LS7APCIEHost *pciehost; -- uint32_t regs[LS7A_REGS]; - - /* LS7A registers */ - MemoryRegion iomem; --- -2.43.5 - diff --git a/code-cleanup-for-loongarch-kvm.patch b/code-cleanup-for-loongarch-kvm.patch deleted file mode 100644 index e94f6de..0000000 --- a/code-cleanup-for-loongarch-kvm.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 4bf40ba9ed6f98e7082623927d1c0c9ec6090f12 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:04:10 -0400 -Subject: [PATCH 12/28] code cleanup for loongarch kvm. - -Signed-off-by: lixianglai ---- - linux-headers/asm-loongarch64/kvm.h | 10 +--------- - 1 file changed, 1 insertion(+), 9 deletions(-) - -diff --git a/linux-headers/asm-loongarch64/kvm.h b/linux-headers/asm-loongarch64/kvm.h -index a24375ee5..799af7594 100644 ---- a/linux-headers/asm-loongarch64/kvm.h -+++ b/linux-headers/asm-loongarch64/kvm.h -@@ -72,15 +72,7 @@ struct kvm_fpu { - * - * Register set = 0: GP registers from kvm_regs (see definitions below). - * -- * Register set = 1: CP0 registers. -- * bits[15..8] - COP0 register set. -- * -- * COP0 register set = 0: Main CP0 registers. -- * bits[7..3] - Register 'rd' index. -- * bits[2..0] - Register 'sel' index. -- * -- * COP0 register set = 1: MAARs. -- * bits[7..0] - MAAR index. -+ * Register set = 1: CSR registers. - * - * Register set = 2: KVM specific registers (see definitions below). - * --- -2.43.5 - diff --git a/fix-smbios-type4-info-for-numa-support.patch b/fix-smbios-type4-info-for-numa-support.patch deleted file mode 100644 index 3e5f0fb..0000000 --- a/fix-smbios-type4-info-for-numa-support.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 1565426c6bc04bffe941ad6d7ce819278da323e8 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:53:36 -0400 -Subject: [PATCH 20/28] fix smbios type4 info for numa support. - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 5e271f339..b1501e0ea 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -1211,8 +1211,14 @@ static void loongarch_build_smbios(LoongarchMachineState *lsms) - uint8_t *smbios_tables, *smbios_anchor; - size_t smbios_tables_len, smbios_anchor_len; - const char *product = "QEMU Virtual Machine"; -- ms->smp.cores = 4; -+ int nb_numa_nodes, smp_cpus; - -+ smp_cpus = ms->smp.cpus; -+ nb_numa_nodes = ms->numa_state->num_nodes; -+ if (nb_numa_nodes == 0) { -+ nb_numa_nodes = 1; -+ } -+ ms->smp.cores = smp_cpus / nb_numa_nodes; - if (!lsms->fw_cfg) { - return; - } -@@ -2004,6 +2010,10 @@ static int64_t ls3a_get_default_cpu_node_id(const MachineState *ms, int idx) - { - int nb_numa_nodes = ms->numa_state->num_nodes; - int smp_cores = ms->smp.cores; -+ -+ if (nb_numa_nodes == 0) { -+ nb_numa_nodes = 1; -+ } - return idx / smp_cores % nb_numa_nodes; - } - --- -2.43.5 - diff --git a/fixup-can-t-find-cpu-type.patch b/fixup-can-t-find-cpu-type.patch deleted file mode 100644 index 3ffeaf4..0000000 --- a/fixup-can-t-find-cpu-type.patch +++ /dev/null @@ -1,34 +0,0 @@ -From a08da06ba1ca817465e894737dced362babc9f18 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:51:55 -0400 -Subject: [PATCH 19/28] fixup can't find cpu type. - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index f83bd3750..5e271f339 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -547,7 +547,15 @@ static char *get_host_cpu_model_name(void) - fprintf(stderr, "read err...\n"); - } - close(fd); -- buf_p = strstr(buf, "name"); -+ buf_p = strstr(buf, "Name"); -+ if (!buf_p) { -+ buf_p = strstr(buf, "name"); -+ } -+ if (!buf_p) { -+ fprintf(stderr, "Can't find cpu name\n"); -+ return 0; -+ } -+ - - while (*buf_p != ':') { - buf_p++; --- -2.43.5 - diff --git a/kvm-csr-save-and-restore-optimization.patch b/kvm-csr-save-and-restore-optimization.patch deleted file mode 100644 index a5c3954..0000000 --- a/kvm-csr-save-and-restore-optimization.patch +++ /dev/null @@ -1,599 +0,0 @@ -From 2b5b79cc839c3b471724c263a1a5e35bf69c1bc9 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:25:52 -0400 -Subject: [PATCH 14/28] kvm csr save and restore optimization. - -Signed-off-by: lixianglai ---- - target/loongarch64/kvm.c | 547 +++++++++++---------------------------- - 1 file changed, 153 insertions(+), 394 deletions(-) - -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -index b5c655812..6885ec6c9 100644 ---- a/target/loongarch64/kvm.c -+++ b/target/loongarch64/kvm.c -@@ -95,19 +95,165 @@ int kvm_arch_irqchip_create(KVMState *s) - return 0; - } - -+static void kvm_csr_set_addr(uint64_t **addr, uint32_t index, uint64_t *p) -+{ -+ addr[index] = p; -+} -+ - int kvm_arch_init_vcpu(CPUState *cs) - { - LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ uint64_t **addr; -+ CPULOONGARCHState *env = &cpu->env; - int ret = 0; - - cpu->cpuStateEntry = qemu_add_vm_change_state_handler(kvm_loongarch_update_state, cs); -- cpu->kvm_csr_buf = g_malloc0(CSR_BUF_SIZE); -+ cpu->kvm_csr_buf = g_malloc0(CSR_BUF_SIZE + CSR_BUF_SIZE); -+ -+ addr = (void *)cpu->kvm_csr_buf + CSR_BUF_SIZE; -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_CRMD, &env->CSR_CRMD); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRMD, &env->CSR_PRMD); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_EUEN, &env->CSR_EUEN); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_MISC, &env->CSR_MISC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ECFG, &env->CSR_ECFG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ESTAT, &env->CSR_ESTAT); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERA, &env->CSR_ERA); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_BADV, &env->CSR_BADV); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_BADI, &env->CSR_BADI); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_EEPN, &env->CSR_EEPN); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBIDX, &env->CSR_TLBIDX); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBEHI, &env->CSR_TLBEHI); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBELO0, &env->CSR_TLBELO0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBELO1, &env->CSR_TLBELO1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GTLBC, &env->CSR_GTLBC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TRGP, &env->CSR_TRGP); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ASID, &env->CSR_ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PGDL, &env->CSR_PGDL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PGDH, &env->CSR_PGDH); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PGD, &env->CSR_PGD); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PWCTL0, &env->CSR_PWCTL0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PWCTL1, &env->CSR_PWCTL1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_STLBPGSIZE, &env->CSR_STLBPGSIZE); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_RVACFG, &env->CSR_RVACFG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_CPUID, &env->CSR_CPUID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRCFG1, &env->CSR_PRCFG1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRCFG2, &env->CSR_PRCFG2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRCFG3, &env->CSR_PRCFG3); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS0, &env->CSR_KS0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS1, &env->CSR_KS1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS2, &env->CSR_KS2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS3, &env->CSR_KS3); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS4, &env->CSR_KS4); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS5, &env->CSR_KS5); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS6, &env->CSR_KS6); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS7, &env->CSR_KS7); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TMID, &env->CSR_TMID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_CNTC, &env->CSR_CNTC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TINTCLR, &env->CSR_TINTCLR); -+ -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GSTAT, &env->CSR_GSTAT); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GCFG, &env->CSR_GCFG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GINTC, &env->CSR_GINTC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GCNTC, &env->CSR_GCNTC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_LLBCTL, &env->CSR_LLBCTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IMPCTL1, &env->CSR_IMPCTL1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IMPCTL2, &env->CSR_IMPCTL2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GNMI, &env->CSR_GNMI); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRENT, &env->CSR_TLBRENT); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRBADV, &env->CSR_TLBRBADV); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRERA, &env->CSR_TLBRERA); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRSAVE, &env->CSR_TLBRSAVE); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRELO0, &env->CSR_TLBRELO0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRELO1, &env->CSR_TLBRELO1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBREHI, &env->CSR_TLBREHI); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRPRMD, &env->CSR_TLBRPRMD); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRCTL, &env->CSR_ERRCTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRINFO, &env->CSR_ERRINFO); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRINFO1, &env->CSR_ERRINFO1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRENT, &env->CSR_ERRENT); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRERA, &env->CSR_ERRERA); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRSAVE, &env->CSR_ERRSAVE); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_CTAG, &env->CSR_CTAG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN0, &env->CSR_DMWIN0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN1, &env->CSR_DMWIN1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN2, &env->CSR_DMWIN2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN3, &env->CSR_DMWIN3); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL0, &env->CSR_PERFCTRL0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR0, &env->CSR_PERFCNTR0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL1, &env->CSR_PERFCTRL1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR1, &env->CSR_PERFCNTR1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL2, &env->CSR_PERFCTRL2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR2, &env->CSR_PERFCNTR2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL3, &env->CSR_PERFCTRL3); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR3, &env->CSR_PERFCNTR3); -+ -+ /* debug */ -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_MWPC, &env->CSR_MWPC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_MWPS, &env->CSR_MWPS); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0ADDR, &env->CSR_DB0ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0MASK, &env->CSR_DB0MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0CTL, &env->CSR_DB0CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0ASID, &env->CSR_DB0ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1ADDR, &env->CSR_DB1ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1MASK, &env->CSR_DB1MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1CTL, &env->CSR_DB1CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1ASID, &env->CSR_DB1ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2ADDR, &env->CSR_DB2ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2MASK, &env->CSR_DB2MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2CTL, &env->CSR_DB2CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2ASID, &env->CSR_DB2ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3ADDR, &env->CSR_DB3ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3MASK, &env->CSR_DB3MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3CTL, &env->CSR_DB3CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3ASID, &env->CSR_DB3ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_FWPC, &env->CSR_FWPC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_FWPS, &env->CSR_FWPS); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0ADDR, &env->CSR_IB0ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0MASK, &env->CSR_IB0MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0CTL, &env->CSR_IB0CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0ASID, &env->CSR_IB0ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1ADDR, &env->CSR_IB1ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1MASK, &env->CSR_IB1MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1CTL, &env->CSR_IB1CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1ASID, &env->CSR_IB1ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2ADDR, &env->CSR_IB2ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2MASK, &env->CSR_IB2MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2CTL, &env->CSR_IB2CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2ASID, &env->CSR_IB2ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3ADDR, &env->CSR_IB3ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3MASK, &env->CSR_IB3MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3CTL, &env->CSR_IB3CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3ASID, &env->CSR_IB3ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4ADDR, &env->CSR_IB4ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4MASK, &env->CSR_IB4MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4CTL, &env->CSR_IB4CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4ASID, &env->CSR_IB4ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5ADDR, &env->CSR_IB5ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5MASK, &env->CSR_IB5MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5CTL, &env->CSR_IB5CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5ASID, &env->CSR_IB5ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6ADDR, &env->CSR_IB6ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6MASK, &env->CSR_IB6MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6CTL, &env->CSR_IB6CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6ASID, &env->CSR_IB6ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7ADDR, &env->CSR_IB7ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7MASK, &env->CSR_IB7MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7CTL, &env->CSR_IB7CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7ASID, &env->CSR_IB7ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DEBUG, &env->CSR_DEBUG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DERA, &env->CSR_DERA); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DESAVE, &env->CSR_DESAVE); -+ - DPRINTF("%s\n", __func__); - return ret; - } - - int kvm_arch_destroy_vcpu(CPUState *cs) - { -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ -+ g_free(cpu->kvm_csr_buf); -+ cpu->kvm_csr_buf = NULL; - return 0; - } - -@@ -936,8 +1082,10 @@ static int kvm_loongarch_get_csr_registers(CPUState *cs) - CPULOONGARCHState *env = &cpu->env; - int ret = 0, i; - struct kvm_csr_entry *csrs = cpu->kvm_csr_buf->entries; -+ uint64_t **addr; - - kvm_csr_buf_reset(cpu); -+ addr = (void *)cpu->kvm_csr_buf + CSR_BUF_SIZE; - - kvm_csr_entry_add(cpu, LOONGARCH_CSR_CRMD, 0); - kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRMD, 0); -@@ -1082,399 +1230,10 @@ static int kvm_loongarch_get_csr_registers(CPUState *cs) - - for (i = 0; i < ret; i++) { - uint32_t index = csrs[i].index; -- -- switch (index) { -- case LOONGARCH_CSR_CRMD: -- env->CSR_CRMD = csrs[i].data; -- break; -- case LOONGARCH_CSR_PRMD: -- env->CSR_PRMD = csrs[i].data; -- break; -- case LOONGARCH_CSR_EUEN: -- env->CSR_EUEN = csrs[i].data; -- break; -- case LOONGARCH_CSR_MISC: -- env->CSR_MISC = csrs[i].data; -- break; -- case LOONGARCH_CSR_ECFG: -- env->CSR_ECFG = csrs[i].data; -- break; -- case LOONGARCH_CSR_ESTAT: -- env->CSR_ESTAT = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERA: -- env->CSR_ERA = csrs[i].data; -- break; -- case LOONGARCH_CSR_BADV: -- env->CSR_BADV = csrs[i].data; -- break; -- case LOONGARCH_CSR_BADI: -- env->CSR_BADI = csrs[i].data; -- break; -- case LOONGARCH_CSR_EEPN: -- env->CSR_EEPN = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBIDX: -- env->CSR_TLBIDX = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBEHI: -- env->CSR_TLBEHI = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBELO0: -- env->CSR_TLBELO0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBELO1: -- env->CSR_TLBELO1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_GTLBC: -- env->CSR_GTLBC = csrs[i].data; -- break; -- case LOONGARCH_CSR_TRGP: -- env->CSR_TRGP = csrs[i].data; -- break; -- case LOONGARCH_CSR_ASID: -- env->CSR_ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_PGDL: -- env->CSR_PGDL = csrs[i].data; -- break; -- case LOONGARCH_CSR_PGDH: -- env->CSR_PGDH = csrs[i].data; -- break; -- case LOONGARCH_CSR_PGD: -- env->CSR_PGD = csrs[i].data; -- break; -- case LOONGARCH_CSR_PWCTL0: -- env->CSR_PWCTL0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PWCTL1: -- env->CSR_PWCTL1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_STLBPGSIZE: -- env->CSR_STLBPGSIZE = csrs[i].data; -- break; -- case LOONGARCH_CSR_RVACFG: -- env->CSR_RVACFG = csrs[i].data; -- break; -- case LOONGARCH_CSR_CPUID: -- env->CSR_CPUID = csrs[i].data; -- break; -- case LOONGARCH_CSR_PRCFG1: -- env->CSR_PRCFG1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PRCFG2: -- env->CSR_PRCFG2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PRCFG3: -- env->CSR_PRCFG3 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS0: -- env->CSR_KS0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS1: -- env->CSR_KS1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS2: -- env->CSR_KS2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS3: -- env->CSR_KS3 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS4: -- env->CSR_KS4 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS5: -- env->CSR_KS5 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS6: -- env->CSR_KS6 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS7: -- env->CSR_KS7 = csrs[i].data; -- break; -- -- case LOONGARCH_CSR_TMID: -- env->CSR_TMID = csrs[i].data; -- break; -- case LOONGARCH_CSR_CNTC: -- env->CSR_CNTC = csrs[i].data; -- break; -- case LOONGARCH_CSR_TINTCLR: -- env->CSR_TINTCLR = csrs[i].data; -- break; -- case LOONGARCH_CSR_GSTAT: -- env->CSR_GSTAT = csrs[i].data; -- break; -- case LOONGARCH_CSR_GCFG: -- env->CSR_GCFG = csrs[i].data; -- break; -- case LOONGARCH_CSR_GINTC: -- env->CSR_GINTC = csrs[i].data; -- break; -- case LOONGARCH_CSR_GCNTC: -- env->CSR_GCNTC = csrs[i].data; -- break; -- case LOONGARCH_CSR_LLBCTL: -- env->CSR_LLBCTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IMPCTL1: -- env->CSR_IMPCTL1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_IMPCTL2: -- env->CSR_IMPCTL2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_GNMI: -- env->CSR_GNMI = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRENT: -- env->CSR_TLBRENT = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRBADV: -- env->CSR_TLBRBADV = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRERA: -- env->CSR_TLBRERA = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRSAVE: -- env->CSR_TLBRSAVE = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRELO0: -- env->CSR_TLBRELO0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRELO1: -- env->CSR_TLBRELO1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBREHI: -- env->CSR_TLBREHI = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRPRMD: -- env->CSR_TLBRPRMD = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRCTL: -- env->CSR_ERRCTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRINFO: -- env->CSR_ERRINFO = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRINFO1: -- env->CSR_ERRINFO1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRENT: -- env->CSR_ERRENT = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRERA: -- env->CSR_ERRERA = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRSAVE: -- env->CSR_ERRSAVE = csrs[i].data; -- break; -- case LOONGARCH_CSR_CTAG: -- env->CSR_CTAG = csrs[i].data; -- break; -- case LOONGARCH_CSR_DMWIN0: -- env->CSR_DMWIN0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_DMWIN1: -- env->CSR_DMWIN1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_DMWIN2: -- env->CSR_DMWIN2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_DMWIN3: -- env->CSR_DMWIN3 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCTRL0: -- env->CSR_PERFCTRL0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCNTR0: -- env->CSR_PERFCNTR0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCTRL1: -- env->CSR_PERFCTRL1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCNTR1: -- env->CSR_PERFCNTR1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCTRL2: -- env->CSR_PERFCTRL2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCNTR2: -- env->CSR_PERFCNTR2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCTRL3: -- env->CSR_PERFCTRL3 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCNTR3: -- env->CSR_PERFCNTR3 = csrs[i].data; -- break; -- -- case LOONGARCH_CSR_MWPC: -- env->CSR_MWPC = csrs[i].data; -- break; -- case LOONGARCH_CSR_MWPS: -- env->CSR_MWPS = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB0ADDR: -- env->CSR_DB0ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB0MASK: -- env->CSR_DB0MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB0CTL: -- env->CSR_DB0CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB0ASID: -- env->CSR_DB0ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB1ADDR: -- env->CSR_DB1ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB1MASK: -- env->CSR_DB1MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB1CTL: -- env->CSR_DB1CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB1ASID: -- env->CSR_DB1ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB2ADDR: -- env->CSR_DB2ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB2MASK: -- env->CSR_DB2MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB2CTL: -- env->CSR_DB2CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB2ASID: -- env->CSR_DB2ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB3ADDR: -- env->CSR_DB3ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB3MASK: -- env->CSR_DB3MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB3CTL: -- env->CSR_DB3CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB3ASID: -- env->CSR_DB3ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_FWPC: -- env->CSR_FWPC = csrs[i].data; -- break; -- case LOONGARCH_CSR_FWPS: -- env->CSR_FWPS = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB0ADDR: -- env->CSR_IB0ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB0MASK: -- env->CSR_IB0MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB0CTL: -- env->CSR_IB0CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB0ASID: -- env->CSR_IB0ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB1ADDR: -- env->CSR_IB1ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB1MASK: -- env->CSR_IB1MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB1CTL: -- env->CSR_IB1CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB1ASID: -- env->CSR_IB1ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB2ADDR: -- env->CSR_IB2ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB2MASK: -- env->CSR_IB2MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB2CTL: -- env->CSR_IB2CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB2ASID: -- env->CSR_IB2ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB3ADDR: -- env->CSR_IB3ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB3MASK: -- env->CSR_IB3MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB3CTL: -- env->CSR_IB3CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB3ASID: -- env->CSR_IB3ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB4ADDR: -- env->CSR_IB4ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB4MASK: -- env->CSR_IB4MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB4CTL: -- env->CSR_IB4CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB4ASID: -- env->CSR_IB4ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB5ADDR: -- env->CSR_IB5ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB5MASK: -- env->CSR_IB5MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB5CTL: -- env->CSR_IB5CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB5ASID: -- env->CSR_IB5ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB6ADDR: -- env->CSR_IB6ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB6MASK: -- env->CSR_IB6MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB6CTL: -- env->CSR_IB6CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB6ASID: -- env->CSR_IB6ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB7ADDR: -- env->CSR_IB7ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB7MASK: -- env->CSR_IB7MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB7CTL: -- env->CSR_IB7CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB7ASID: -- env->CSR_IB7ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_DEBUG: -- env->CSR_DEBUG = csrs[i].data; -- break; -- case LOONGARCH_CSR_DERA: -- env->CSR_DERA = csrs[i].data; -- break; -- case LOONGARCH_CSR_DESAVE: -- env->CSR_DESAVE = csrs[i].data; -- break; -- default: -- break; -+ if (addr[index]) { -+ *addr[index] = csrs[i].data; -+ } else { -+ printf("Failed to get addr CSR 0x%"PRIx32"\n", i); - } - } - --- -2.43.5 - diff --git a/kvm-iotests-test-NBD-TLS-iothread.patch b/kvm-iotests-test-NBD-TLS-iothread.patch new file mode 100644 index 0000000..c87e673 --- /dev/null +++ b/kvm-iotests-test-NBD-TLS-iothread.patch @@ -0,0 +1,277 @@ +From a0b12780f3cb97abad0a2c54d185c298d3f589e7 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Fri, 17 May 2024 21:50:15 -0500 +Subject: [PATCH 2/3] iotests: test NBD+TLS+iothread +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Eric Blake +RH-MergeRequest: 398: nbd/server: CVE-2024-7409: Avoid use-after-free when closing server +RH-Jira: RHEL-52611 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Commit: [2/3] f522ff5156086a83a7327c379dd3ccd8b583a421 (ebblake/qemu-kvm) + +Prevent regressions when using NBD with TLS in the presence of +iothreads, adding coverage the fix to qio channels made in the +previous patch. + +The shell function pick_unused_port() was copied from +nbdkit.git/tests/functions.sh.in, where it had all authors from Red +Hat, agreeing to the resulting relicensing from 2-clause BSD to GPLv2. + +CC: qemu-stable@nongnu.org +CC: "Richard W.M. Jones" +Signed-off-by: Eric Blake +Message-ID: <20240531180639.1392905-6-eblake@redhat.com> +Reviewed-by: Daniel P. Berrangé + +(cherry picked from commit a73c99378022ebb785481e84cfe1e81097546268) +Jira: https://issues.redhat.com/browse/RHEL-52611 +Conflicts: + tests/qemu-iotests/tests/nbd-tls-iothread{,.out} - drop unknown + "tls-hostname" parameter +Signed-off-by: Eric Blake +--- + tests/qemu-iotests/tests/nbd-tls-iothread | 167 ++++++++++++++++++ + tests/qemu-iotests/tests/nbd-tls-iothread.out | 53 ++++++ + 2 files changed, 220 insertions(+) + create mode 100755 tests/qemu-iotests/tests/nbd-tls-iothread + create mode 100644 tests/qemu-iotests/tests/nbd-tls-iothread.out + +diff --git a/tests/qemu-iotests/tests/nbd-tls-iothread b/tests/qemu-iotests/tests/nbd-tls-iothread +new file mode 100755 +index 0000000000..9e747e2639 +--- /dev/null ++++ b/tests/qemu-iotests/tests/nbd-tls-iothread +@@ -0,0 +1,167 @@ ++#!/usr/bin/env bash ++# group: rw quick ++# ++# Test of NBD+TLS+iothread ++# ++# Copyright (C) 2024 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program 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 General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# creator ++owner=eblake@redhat.com ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_qemu ++ _cleanup_test_img ++ rm -f "$dst_image" ++ tls_x509_cleanup ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++cd .. ++. ./common.rc ++. ./common.filter ++. ./common.qemu ++. ./common.tls ++. ./common.nbd ++ ++_supported_fmt qcow2 # Hardcoded to qcow2 command line and QMP below ++_supported_proto file ++ ++# pick_unused_port ++# ++# Picks and returns an "unused" port, setting the global variable ++# $port. ++# ++# This is inherently racy, but we need it because qemu does not currently ++# permit NBD+TLS over a Unix domain socket ++pick_unused_port () ++{ ++ if ! (ss --version) >/dev/null 2>&1; then ++ _notrun "ss utility required, skipped this test" ++ fi ++ ++ # Start at a random port to make it less likely that two parallel ++ # tests will conflict. ++ port=$(( 50000 + (RANDOM%15000) )) ++ while ss -ltn | grep -sqE ":$port\b"; do ++ ((port++)) ++ if [ $port -eq 65000 ]; then port=50000; fi ++ done ++ echo picked unused port ++} ++ ++tls_x509_init ++ ++size=1G ++DST_IMG="$TEST_DIR/dst.qcow2" ++ ++echo ++echo "== preparing TLS creds and spare port ==" ++ ++pick_unused_port ++tls_x509_create_root_ca "ca1" ++tls_x509_create_server "ca1" "server1" ++tls_x509_create_client "ca1" "client1" ++tls_obj_base=tls-creds-x509,id=tls0,verify-peer=true,dir="${tls_dir}" ++ ++echo ++echo "== preparing image ==" ++ ++_make_test_img $size ++$QEMU_IMG create -f qcow2 "$DST_IMG" $size | _filter_img_create ++ ++echo ++echo === Starting Src QEMU === ++echo ++ ++_launch_qemu -machine q35 \ ++ -object iothread,id=iothread0 \ ++ -object "${tls_obj_base}"/client1,endpoint=client \ ++ -device '{"driver":"pcie-root-port", "id":"root0", "multifunction":true, ++ "bus":"pcie.0"}' \ ++ -device '{"driver":"virtio-scsi-pci", "id":"virtio_scsi_pci0", ++ "bus":"root0", "iothread":"iothread0"}' \ ++ -device '{"driver":"scsi-hd", "id":"image1", "drive":"drive_image1", ++ "bus":"virtio_scsi_pci0.0"}' \ ++ -blockdev '{"driver":"file", "cache":{"direct":true, "no-flush":false}, ++ "filename":"'"$TEST_IMG"'", "node-name":"drive_sys1"}' \ ++ -blockdev '{"driver":"qcow2", "node-name":"drive_image1", ++ "file":"drive_sys1"}' ++h1=$QEMU_HANDLE ++_send_qemu_cmd $h1 '{"execute": "qmp_capabilities"}' 'return' ++ ++echo ++echo === Starting Dst VM2 === ++echo ++ ++_launch_qemu -machine q35 \ ++ -object iothread,id=iothread0 \ ++ -object "${tls_obj_base}"/server1,endpoint=server \ ++ -device '{"driver":"pcie-root-port", "id":"root0", "multifunction":true, ++ "bus":"pcie.0"}' \ ++ -device '{"driver":"virtio-scsi-pci", "id":"virtio_scsi_pci0", ++ "bus":"root0", "iothread":"iothread0"}' \ ++ -device '{"driver":"scsi-hd", "id":"image1", "drive":"drive_image1", ++ "bus":"virtio_scsi_pci0.0"}' \ ++ -blockdev '{"driver":"file", "cache":{"direct":true, "no-flush":false}, ++ "filename":"'"$DST_IMG"'", "node-name":"drive_sys1"}' \ ++ -blockdev '{"driver":"qcow2", "node-name":"drive_image1", ++ "file":"drive_sys1"}' \ ++ -incoming defer ++h2=$QEMU_HANDLE ++_send_qemu_cmd $h2 '{"execute": "qmp_capabilities"}' 'return' ++ ++echo ++echo === Dst VM: Enable NBD server for incoming storage migration === ++echo ++ ++_send_qemu_cmd $h2 '{"execute": "nbd-server-start", "arguments": ++ {"addr": {"type": "inet", "data": {"host": "127.0.0.1", "port": "'$port'"}}, ++ "tls-creds": "tls0"}}' '{"return": {}}' | sed "s/\"$port\"/PORT/g" ++_send_qemu_cmd $h2 '{"execute": "block-export-add", "arguments": ++ {"node-name": "drive_image1", "type": "nbd", "writable": true, ++ "id": "drive_image1"}}' '{"return": {}}' ++ ++echo ++echo === Src VM: Mirror to dst NBD for outgoing storage migration === ++echo ++ ++_send_qemu_cmd $h1 '{"execute": "blockdev-add", "arguments": ++ {"node-name": "mirror", "driver": "nbd", ++ "server": {"type": "inet", "host": "127.0.0.1", "port": "'$port'"}, ++ "export": "drive_image1", "tls-creds": "tls0"}}' '{"return": {}}' | sed "s/\"$port\"/PORT/g" ++_send_qemu_cmd $h1 '{"execute": "blockdev-mirror", "arguments": ++ {"sync": "full", "device": "drive_image1", "target": "mirror", ++ "job-id": "drive_image1_53"}}' '{"return": {}}' ++_timed_wait_for $h1 '"ready"' ++ ++echo ++echo === Cleaning up === ++echo ++ ++_send_qemu_cmd $h1 '{"execute":"quit"}' '' ++_send_qemu_cmd $h2 '{"execute":"quit"}' '' ++ ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/tests/nbd-tls-iothread.out b/tests/qemu-iotests/tests/nbd-tls-iothread.out +new file mode 100644 +index 0000000000..a3899fd2d7 +--- /dev/null ++++ b/tests/qemu-iotests/tests/nbd-tls-iothread.out +@@ -0,0 +1,53 @@ ++QA output created by nbd-tls-iothread ++ ++== preparing TLS creds and spare port == ++picked unused port ++Generating a self signed certificate... ++Generating a signed certificate... ++Generating a signed certificate... ++ ++== preparing image == ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 ++Formatting 'TEST_DIR/dst.IMGFMT', fmt=IMGFMT size=1073741824 ++ ++=== Starting Src QEMU === ++ ++{"execute": "qmp_capabilities"} ++{"return": {}} ++ ++=== Starting Dst VM2 === ++ ++{"execute": "qmp_capabilities"} ++{"return": {}} ++ ++=== Dst VM: Enable NBD server for incoming storage migration === ++ ++{"execute": "nbd-server-start", "arguments": ++ {"addr": {"type": "inet", "data": {"host": "127.0.0.1", "port": PORT}}, ++ "tls-creds": "tls0"}} ++{"return": {}} ++{"execute": "block-export-add", "arguments": ++ {"node-name": "drive_image1", "type": "nbd", "writable": true, ++ "id": "drive_image1"}} ++{"return": {}} ++ ++=== Src VM: Mirror to dst NBD for outgoing storage migration === ++ ++{"execute": "blockdev-add", "arguments": ++ {"node-name": "mirror", "driver": "nbd", ++ "server": {"type": "inet", "host": "127.0.0.1", "port": PORT}, ++ "export": "drive_image1", "tls-creds": "tls0"}} ++{"return": {}} ++{"execute": "blockdev-mirror", "arguments": ++ {"sync": "full", "device": "drive_image1", "target": "mirror", ++ "job-id": "drive_image1_53"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "drive_image1_53"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "drive_image1_53"}} ++{"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "drive_image1_53"}} ++ ++=== Cleaning up === ++ ++{"execute":"quit"} ++{"execute":"quit"} ++*** done +-- +2.39.3 + diff --git a/kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch b/kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch new file mode 100644 index 0000000..1fada41 --- /dev/null +++ b/kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch @@ -0,0 +1,101 @@ +From 676438ff8c42323c3e5d9e7eeeb1b3367999136c Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Thu, 22 Aug 2024 09:35:29 -0500 +Subject: [PATCH 3/3] nbd/server: CVE-2024-7409: Avoid use-after-free when + closing server + +RH-Author: Eric Blake +RH-MergeRequest: 398: nbd/server: CVE-2024-7409: Avoid use-after-free when closing server +RH-Jira: RHEL-52611 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Commit: [3/3] 1ee35a40ded067a085bf6fcafa690b40976d7f2d (ebblake/qemu-kvm) + +Commit 3e7ef738 plugged the use-after-free of the global nbd_server +object, but overlooked a use-after-free of nbd_server->listener. +Although this race is harder to hit, notice that our shutdown path +first drops the reference count of nbd_server->listener, then triggers +actions that can result in a pending client reaching the +nbd_blockdev_client_closed() callback, which in turn calls +qio_net_listener_set_client_func on a potentially stale object. + +If we know we don't want any more clients to connect, and have already +told the listener socket to shut down, then we should not be trying to +update the listener socket's associated function. + +Reproducer: + +> #!/usr/bin/python3 +> +> import os +> from threading import Thread +> +> def start_stop(): +> while 1: +> os.system('virsh qemu-monitor-command VM \'{"execute": "nbd-server-start", ++"arguments":{"addr":{"type":"unix","data":{"path":"/tmp/nbd-sock"}}}}\'') +> os.system('virsh qemu-monitor-command VM \'{"execute": "nbd-server-stop"}\'') +> +> def nbd_list(): +> while 1: +> os.system('/path/to/build/qemu-nbd -L -k /tmp/nbd-sock') +> +> def test(): +> sst = Thread(target=start_stop) +> sst.start() +> nlt = Thread(target=nbd_list) +> nlt.start() +> +> sst.join() +> nlt.join() +> +> test() + +Fixes: CVE-2024-7409 +Fixes: 3e7ef738c8 ("nbd/server: CVE-2024-7409: Close stray clients at server-stop") +CC: qemu-stable@nongnu.org +Reported-by: Andrey Drobyshev +Signed-off-by: Eric Blake +Message-ID: <20240822143617.800419-2-eblake@redhat.com> +Reviewed-by: Stefan Hajnoczi + +(cherry picked from commit 3874f5f73c441c52f1c699c848d463b0eda01e4c) +Jira: https://issues.redhat.com/browse/RHEL-52611 +Signed-off-by: Eric Blake +--- + blockdev-nbd.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index 87839c180b..b5d55e2518 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -87,10 +87,13 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, + + static void nbd_update_server_watch(NBDServerData *s) + { +- if (!s->max_connections || s->connections < s->max_connections) { +- qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, NULL); +- } else { +- qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); ++ if (s->listener) { ++ if (!s->max_connections || s->connections < s->max_connections) { ++ qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, ++ NULL); ++ } else { ++ qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); ++ } + } + } + +@@ -108,6 +111,7 @@ static void nbd_server_free(NBDServerData *server) + */ + qio_net_listener_disconnect(server->listener); + object_unref(OBJECT(server->listener)); ++ server->listener = NULL; + QLIST_FOREACH_SAFE(conn, &server->conns, next, tmp) { + qio_channel_shutdown(QIO_CHANNEL(conn->cioc), QIO_CHANNEL_SHUTDOWN_BOTH, + NULL); +-- +2.39.3 + diff --git a/kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch b/kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch new file mode 100644 index 0000000..54030b0 --- /dev/null +++ b/kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch @@ -0,0 +1,161 @@ +From 00af174d1388ed2d2df7961ee78be6af3757a01c Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 30 Aug 2023 18:48:02 -0400 +Subject: [PATCH 1/3] nbd/server: Favor qemu_aio_context over iohandler context + +RH-Author: Eric Blake +RH-MergeRequest: 398: nbd/server: CVE-2024-7409: Avoid use-after-free when closing server +RH-Jira: RHEL-52611 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Commit: [1/3] 6ec0ef287fbc976175da83a0c14d9878e83affa2 (ebblake/qemu-kvm) + +DOWNSTREAM ONLY - but based on an idea originally included as a +side-effect in the larger upstream patch 06e0f098 "io: follow +coroutine AioContext in qio_channel_yield()", as well as handling the +state of the qio TLS channel before it is associated with a block +device as an alternative to 199e84de "qio: Inherit +follow_coroutine_ctx across TLS". + +The NBD server code wants to use qio_channel_shutdown() followed by +AIO_WAIT_WHILE() during nbd_server_free(), but cannot attach the ioc +to an AioContext until the client has completed the handshake to the +point that the server knows what block device to associate with the +connection. The qio code is set up to handle connections with no +AioContext in the iohandler context, but this context is specifically +designed to NOT make progress during AIO_WAIT_WHILE(). In order to +prevent things from deadlocking, the qio channels handling NBD +handshake MUST be in the qemu_aio_context, so that an early shutdown +triggered by nbd-server-stop can make progress. + +Note that upstream handled the main qio channel by the use of +qio_channel_set_follow_coroutine_ctx() in only one place in +nbd/server.c; upstream handled the TLS channel by a more generic +second patch that taught qio TLS channel to inherit the +follow_coroutine_ctx status from its parent. But since this patch is +already downstream only, the minimal diff is achieved by manually +setting the status of the TLS channel in NBD code, rather than +backporting the qio inheritance code. For testing that the second +call to qio_channel_set_favor_qemu_aio_ctx() matters, I used this test +setup (borrowing a pre-built PSK file for username alice from the +libnbd project, and using IPv4 since this qemu is too old to support +TLS over Unix sockets): + +$ # in terminal 1: +$ qemu-system-x86_64 --nographic --nodefaults --qmp stdio \ + --object tls-creds-psk,id=tls0,dir=/PATHTO/libnbd/tests,endpoint=server +{"execute": "qmp_capabilities"} +{"execute":"nbd-server-start","arguments":{"addr":{"type":"inet", + "data":{"host":"127.0.0.1","port":"10809"}},"tls-creds":"tls0"}} + +$ # in terminal 2: +$ nbdsh -c 'h.set_uri_allow_local_file(True)' --opt-mode -u \ + 'nbds://alice@127.0.0.1/?tls-psk-file=/PATHTO/libnbd/tests/keys.psk' \ + -c 'import time; time.sleep(15)' + +$ # in terminal 1, before 10 seconds elapse +{"execute":"nbd-server-stop"} +{"execute":"quit"} + +and observed that, when omitting the one-line TLS setting, qemu would +hit the same deadlock with a TLS client as what I was observing for a +non-TLS client without this entire patch. + +Jira: https://issues.redhat.com/browse/RHEL-52611 +Suggested-by: Kevin Wolf +Signed-off-by: Eric Blake +--- + include/io/channel.h | 16 ++++++++++++++++ + io/channel.c | 14 +++++++++++++- + nbd/server.c | 2 ++ + 3 files changed, 31 insertions(+), 1 deletion(-) + +diff --git a/include/io/channel.h b/include/io/channel.h +index 716235d496..f1ce19ea81 100644 +--- a/include/io/channel.h ++++ b/include/io/channel.h +@@ -84,6 +84,7 @@ struct QIOChannel { + AioContext *ctx; + Coroutine *read_coroutine; + Coroutine *write_coroutine; ++ bool favor_qemu_aio_ctx; + #ifdef _WIN32 + HANDLE event; /* For use with GSource on Win32 */ + #endif +@@ -498,6 +499,21 @@ int qio_channel_set_blocking(QIOChannel *ioc, + bool enabled, + Error **errp); + ++/** ++ * qio_channel_set_favor_qemu_aio_ctx: ++ * @ioc: the channel object ++ * @enabled: whether to fall back to qemu_aio_context ++ * ++ * If @enabled is true, calls to qio_channel_yield() with no AioContext ++ * set use the qemu_aio_context instead of the global iohandler context. ++ * ++ * If @enabled is false, calls to qio_channel_yield() use the global iohandler ++ * AioContext. This is may be used by coroutines that run in the main loop and ++ * do not wish to respond to I/O during nested event loops. This is the ++ * default for compatibility with code that is not aware of AioContexts. ++ */ ++void qio_channel_set_favor_qemu_aio_ctx(QIOChannel *ioc, bool enabled); ++ + /** + * qio_channel_close: + * @ioc: the channel object +diff --git a/io/channel.c b/io/channel.c +index a8c7f11649..74704d0464 100644 +--- a/io/channel.c ++++ b/io/channel.c +@@ -364,6 +364,12 @@ int qio_channel_set_blocking(QIOChannel *ioc, + } + + ++void qio_channel_set_favor_qemu_aio_ctx(QIOChannel *ioc, bool enabled) ++{ ++ ioc->favor_qemu_aio_ctx = enabled; ++} ++ ++ + int qio_channel_close(QIOChannel *ioc, + Error **errp) + { +@@ -545,7 +551,13 @@ static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc) + wr_handler = qio_channel_restart_write; + } + +- ctx = ioc->ctx ? ioc->ctx : iohandler_get_aio_context(); ++ if (ioc->ctx) { ++ ctx = ioc->ctx; ++ } else if (ioc->favor_qemu_aio_ctx) { ++ ctx = qemu_get_aio_context(); ++ } else { ++ ctx = iohandler_get_aio_context(); ++ } + qio_channel_set_aio_fd_handler(ioc, ctx, rd_handler, wr_handler, ioc); + } + +diff --git a/nbd/server.c b/nbd/server.c +index 1265068f70..41a2003300 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -758,6 +758,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, + return NULL; + } + ++ qio_channel_set_favor_qemu_aio_ctx(QIO_CHANNEL(tioc), true); + qio_channel_set_name(QIO_CHANNEL(tioc), "nbd-server-tls"); + trace_nbd_negotiate_handle_starttls_handshake(); + data.loop = g_main_loop_new(g_main_context_default(), FALSE); +@@ -1333,6 +1334,7 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) + */ + + qio_channel_set_blocking(client->ioc, false, NULL); ++ qio_channel_set_favor_qemu_aio_ctx(client->ioc, true); + + trace_nbd_negotiate_begin(); + memcpy(buf, "NBDMAGIC", 8); +-- +2.39.3 + diff --git a/kvm-virtiofsd-Adjust-limit-for-minor-version.patch b/kvm-virtiofsd-Adjust-limit-for-minor-version.patch deleted file mode 100644 index 30ec553..0000000 --- a/kvm-virtiofsd-Adjust-limit-for-minor-version.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 3b7200134925fcf5ae99b5c3b34465456d3bc002 Mon Sep 17 00:00:00 2001 -From: Jacob Wang -Date: Mon, 2 Aug 2021 01:16:05 +0800 -Subject: [PATCH 1/1] virtiofsd: Adjust limit for minor version - -Upstream virtiofsd only supports fuse >= 7.31 -(https://github.com/qemu/qemu/commit/72c42e2d65510e073cf78fdc924d121c77fa0080), -while Cloud Kernel has fuse version 7.27, which causes virtiofs fails to run -due to version mismatch. This limitation is unnecessary in Cloud Kernel because -we have already backported mandatory fuse patches to support virtofs -frontend in Kernel. Hence, adjust the minor version limit to 7.27 to -suppress the limitation. - -Note that current fuse implementation in Cloud Kernel might lack of some -certain capabilities in fuse 7.28 ~ 7.31, which may cause unexpected results, -this patch is merely a workaround to enable virtiofs in guest kernel side and -further action is ongoing to make sure fuse APIs in both sides are 100% -compatible. - -Signed-off-by: Jacob Wang -Acked-by: Caspar Zhang ---- - tools/virtiofsd/fuse_lowlevel.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c -index 2dd36ec..2bb4318 100644 ---- a/tools/virtiofsd/fuse_lowlevel.c -+++ b/tools/virtiofsd/fuse_lowlevel.c -@@ -1917,7 +1917,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - -- if (arg->major < 7 || (arg->major == 7 && arg->minor < 31)) { -+ if (arg->major < 7 || (arg->major == 7 && arg->minor < 27)) { - fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n", - arg->major, arg->minor); - fuse_reply_err(req, EPROTO); --- -1.8.3.1 - diff --git a/loongarch_bios.bin b/loongarch_bios.bin deleted file mode 100644 index d6330c6f0532effe458726efa18222166a444839..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4190208 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 z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z`2U#z_Md*7CPPBRgBY&F3kKfweaqd8Vf_D;xS?=eX>XShQ^Lr`jW7(KmjFFX@z1~h z`SqXK)^e9IE)3h4kqjxCNm7yzP##|!e!MJ2g-YYfM(r>^y_ZC-5^`z!(eaW`k!iW4 zn12}QhD{hLew_B@MJiDpnPlrBmrv0IU9=b;W`Neiqwo;?6LBBL+oAMIK3s3~?$Fr- zov+MeQ{u%W@2uAicnjU$@qBWQr|fOjy(cmZeqSx4zfPP>7rQ%{Wue2e$}?q#D<;9$6QD44%E;YI*yY&?s+%! zmekjb*q1v`|E9^J@i0b#B+eV~mA6Gt)p62CEvD9JtF2h(~wXD+Z&uT>ja(8V^FvpBD4CM#f{oeVXt(;Ig)H(melkS;mkaErLll|v}7QVGK z`Y23etgT1ST@{`s7V4VvqcW6{w0$FW(Y3tlyYMjY@R!ZIeXnmf#HEyV{y5K}i$AF0 zo9nWDQ1T9uA9OO8rPC+A%C0>fGn6@Ju;s+*RGSwzDv24o%hy@R&E=}51-Wa! zJ$(10;1ZSeu93ZjZK@@G^l?SMp$cLd{N^|Jg7=+uyyfKHu0ltT)g8I&@BQGuQ0liS z*?irrg=WAZpdqPdyK@%?r5G0_NVVV)EDFMk|#S9{h#WG$8{b%!m| zs1EC*QT#=zXi(x+9iR42#qd7GB~{~{BLX+e&yUy-pRwb=QqbeSvRjgIg!ac)=5SQ@ z8sCxclyl_5^kR+!w_B-MIaAi&RVauR$K_248|&uvERtr0=Zg_Pc|EB7X6S(^>)LfK zsTqb@SL_QJG*AV<}`zeW1 zModhe&UL-bThd0{q2oaFMb@+7g_Prh&o%|aFS0IfIPo#3(Gb>7;+N7rlq-+Hce8Nf zn$LZo+x=EzXm>PQ{gGxG{a~SL`FF)Ml8i?;iZrhuFC=)E7c9GcmNaN(^=^jM`XG7Y zlY-j*8rlv{63H_w?L@y+zL&YYtJUDs4CNi$?^`fZ*3QgX^us9l<_oi(S;3{^2*u87 zjqk>ei<5<1msNy&Zmk}^Dt9#V%gWqJ*RO1kZ%oESqZ26JI+_H9kuT;{aueo*##X>*q> z@_r9zn~zB=&m8tKoTz-?LbJI!Nbf24=uLGMk)+VTHM@zIQQ@b4#}RzBJ5B5V z)!_N$BcGFW%dZX@-T6vBmoY;U5xMd@);4*e^B}q5=C5ADvwS;my{Tz;*czA!*L6oJ z?1UTz^n`9Ssj})P6BXL-wL9@{d5!&WbGBkH?po+Dp$TMjmo0iCxc2(EN)Hh?vo}xW zdHoZjYrTWxO>Hv7JIYrQwxtad4$4aY>ivYTqqjdYUGs@bp8dm=2l}t}ePV3QTB+fe zU7pX`7iUiq*7MAiB5_yPevu${ru|1uxxQnfaO%d|FMpXpSy3snru$E?k8QO6BB%Xb zsSrj#b7D?^iRpyty}r$z!`B=)Y+CTU?eLGNJfsV$Gd?D>$~AWT{r*?Ur91kHTv=@2 z&hl!ivilG2{}z$P`N&XRq0O|~_2^r+1`54{Tn~1swGx6T56#vePH7I&x+X&<{JCkc zU@ktl`lMy%{+XOjUytiIx-F~T57gYocc?mCF%ssdMZ)Rfe*TsxsfQKUn|DRG4NM-9 zm%cg{wc%p(>1|dzS9QroMsRfLNtu}V5AVuP*9inmk@gVGv^*LpQC8(Y#4{5=;k9yUh%ELAW3%*BbAg%l zbsp;GMK`^ERqK~W#l;yoo__S)&Efo|Bi!lp@EAa1;fZRAIJP#+#K-xi5{kte~)8|tHeipg@WN4DAa z$Yoc`)%_|Gm6wK1+5+m%A7y7*Qu>^hy7KtNQGA_?FU8C1$}%En^@e{_C2uKa8MP_j zd#+L+qZTnjbWe_>n0NkueJ@;?*Cv?5~s_^hf{npP7b8`Vh5>UfA6{-pSS)k zt)4seg#GX9_3qBgKA7ywRn>g6;Ja4}if&EWrO*+w=`kLD_g0VlvgAFtz`*5XJ+VtM z7a2KnSY~=Ec@kr0-<`T@DYjbq>MV#LMEoM79v8SGOlf+%B;cTiI zU-lwR|8XO?NRhYioj<(2#=E$Vr+EL1!s*}oghc6Q#2f`ox!PR<$O4nBOEWP+A}vnu zI=%MRyopm>q(;3zq3R@wGQ4N!iDN}nJ>KU7@~%= zBmDxM_7rX?NX^(^?>kCLKy^{%WVTiE1v9n=LlK`L{?_Aj++Pw)6K92LRT|nlBvl7U zzj5-L8t`e^lz6=A50>Y9c^yBonH*o! z^^=HHy3S&eNCYqS_(emd;?9h9zGS~)l8`F1Y@rJ+GxdJby9O1fl`O0(I;%@>EOg81 zhe`x%D<3;cIJ2&f?`VH)omTzg^VN5nyMb75aem^@R@zq6v5H$aR(-YOKNIT?2lj0#g3&3^%0xtJIn=- z{he-xE=Vttu)Fb7vV@ByMwq`BcNF4PZjWR<9{up0aUR|J71ncnHGQl;*U4&MZ#3%# z%rxHaZ`S>~X70IWyrK|3u}#3!kbRgs;!w4LNQtsp7W33+k!XV8qoE!JAvqMuPo@L? z%>wTnI$?W@<1|$phk)8}pn4W%l=t=MNq*8EBTb=K_%Grk@VS#Fw^g5T#D2T+)O9m+ z)7-ndcW!q2{GmfiHCDH5=vi}aN}ZN=EqCQBIb(LUqp|gsM9e_S_c|p}@i!g#A<@bGo5=!4m6Y;x`LTvP}4M++No8Ss%(2`Wwga6W{etF!O;=)FuqaW>9h72;DzlUp88l`IPo0sz{6kF3=TJMcI$uMR&~(rUwmSF(Y{zeQATJu6=uKzw1a2t{1sfJ@YYdm|2NEX94eMVJ*-D<`c$Ig? zaqt*pMBXiy6Ai6(x{niM9rcTyfAjg{htH|xTF}@~=3N%UhDS;iE;zmW_&}iAQYgU8 z9pBu;KE}gb)%8o9lI-TSlHTJw`#Je$S%L;BJ@i8wf{P|oU%X}1*`ShG+q!v8p>nZ^ z`Ai<0@%Z`5;9Tn?l9X(})S}&;NBQ_N2CPO0s`(0L0v^3-mZ(gScut^v?_u)Y{?&bW zzm9Ufqf&XO^ex88_bY8SkKMi{`&`4!K788Sit0Bs2{aPEx>-z&J98EBk)1V;<~<)Q z$3oL@A38n0_)))prdB|GeG|_ki!PahMLCfn*kO`b|JYDIfxhzX_r5od-t)8*@-*gr zQvN*Rwa|I3#qUGG+L{-fIFz@oZt{?*5*SkR5UO>pH~&1gaaB_-!}7)1iW>qE!V*l6 z2+XbMB9bD04YwQ0Uh`!k;G{6SlEcoz>*m9G|K4fV-U5w*Td(}aH19kY@qc{3p<7tn z`|R8{|NeQ3*B`fERk(hbx|8#`&hM0Q7%|5!zKuEi3rmaQPAPE`w56o>?<2}S)DQeR zeq-&4WRB4i##BOogv(j>THRu^Z?Dh(lf5m{GN+jjJ{Ms+a5L35ojod(sjPlkpzT*o z$d!&FwE}H>!Ed#9FNt`OtJrl6n(&!>V{;s(Z{-8zhnYLCb>QDQ9m=6UywhT|T+Wnq zu`K7USST_5=+n7Y#zF>@leD+zra}&S&x!hcyLMaGTjIHU>!}Q)XX35=U&LGH`94eV z-4nc7sh9Fmok9M>VfoB{r3ORC1MG1$EosMpefi!~rDxVK9xI~c{OJ9a`+>cq%)H{!+1C%8{% z55Ja)pFGmVg#BLg{6ds!&%mS1BT`f!PR%MqdR%bZOwNm8bL2W_%>^d^~vI~{6E&Cpf zX@b8HRP1`OEm41$$-^@4Nn;#yM^Bq}SW*kY+lkLnAVs zH;y^Vd5!mPePP(XKtxpDaBMeO$sE7+8%Co1wewqitakGAYgZ)X4+tEz3sd&!OmIBd z&qCYiLHFQ|w6H>61qt&hS&v+y`_UZzRnOhB>ng9th9zHew|TvVVPu;>{LAkMu@|1d z(bo3F%SyxfPUb<=j?{q@<*w^~Rz(l3GgY4Juu60su5;Tu7iTMOBon#pYA59t>6}5O zdSL!myy?DmHP@*qaRWE{ci+ZF>)S&I>k@LmVr$QcyDUyTHs5`D)tP=!!`hztLgVd?&cp2`2v`k?Oi*MC=tv-h`M4oHrON_bI=%+${%q&U2`^9eQ4r!I~5_wd7 z*0%bW5BP<#*QAD47KoFrYU287Ic8s2C|g)GCr&PSaFL6**p#%&5BTlm-l8r$wds6o zOecIxK4eN$u0!EPaT+g!RX>3v$m(S3iATF#xisFj@x-|NB|({a*h zH}mL=oZOaZLPM8+M9zy_oCkA`Pt~!>-0#|!Jn%3|U6K8Dm$Et0&?7;Il#6*T$(r=L zEM|q$tc6iszLid${7#g5Wx-EW-hYzvCI9^9rzF)l$yIyd%voRhL!XULEbQ`79uZJ@ zc5R&^Az(Av`?P@-rJwkkm-yhQ9`m^q!^y=7jAO*D`T3LI-22bH6pdBH`>DHG61gt! z{e@reke*WCNk%3)-je;w8QVKbsa4PDSN)oNXu28zOW4^ z-2z5&8s*tbZz7h83~hK+Tb7?k+ecVg3|<%Nq58?^-c6Bk{tZ9O<> zZgWp!UQ1LTlWe#wyc+$JI#{H*G?LEY3HMOb@n&VEBMhGvFX|8pOH_p8lhV&WqA`o! zI$?jQ=9f{JPe)!vT+PvUI^7Gzp>}mx;fdGZgjXBCa`q|XYrQL(<-VIdycXLzn|DZZ zd$LO2`x&3TN)X3y*;Om0wo6AR=1&;r;xik@eoxN*j(sGdv_94D>rC&pbR2(OaN?^+_Jl5BF%FC z=EV~+E0U?{IW#r1DyMr1KlcmPy?(*JXzNUM-=pE3=7ZD|rlO3_+H*?g2^`Gr)5rLK zAG5k(c5m#ZM*3;XQhlmtx`AqYWMUL zak7zdJ*Y)~_f=@y>#{LrI0 zde;@gytyyQmr2i$hB%y64)}E=m90T@KzyYv+@V<#i{?5qAx~9gJQDz*^^s9|dWuZd9w@ZF zNpK%;K1xQQt5)oilh?cNf$FaEpDF!pG>=NeU#ZAob`ywKGEP_a^m%;w-a{ch3nI_n zPQkPrO=YL}=?lcuX=cm!va=d{CLZ%P>ixW5a-^5YxJY#1Y{J}W{5RnPPl+t_4m@Re zDe~M$(j@&O^~o5HDF4IM^}`e^6L?2m5|*CItUZbqIAm09A9G)eU6=Tq{3Z3k*1oBe zn>43oepOI%)6Ske({$$iljFAx&dAuEDRrCv^jU-^Y<4C3z)h2HYJ=lf?@!t_Ui4s) zG{hz!XE9ZVdKRD4Tzt|0O)aPSu(aEfaK&A+fjjs1d|w$VmlBdNJeyNukn)_zCp0#V zyX-_yF47u9bsZ!B^e|I^E>glkrjPNqJ}Gyv#huOHQY2QgcvNf377uO+Fo=tpX`W|_ zj1~|!`Q6H&CV}^~H(rRTvocX!qpRb)O_a@u4BMqJ^DUP|>hqyW24;5LCp^DB{igD! zs$Duz)m+ib+;W+FSfj`y4*S&htX6sEw*M=hJ0`sY8rq^#R)Sd{bJJ=M^?tW|e_|mkww872PE2H!?zwVa z!R*mXlAa%eD&qL>yy#rzuS99+W+v%6?srwkB<3qCHYR_CsYsvZ|Ez}ZV(_L&jzwly zN~k>QBD>^h13%aJeR{$1ON{w)C$CI+J`mlSOg(DstyN4YHE3jch2>$v)Q=F~vDGoI z&?0%sA@iO3iqBGv`bT4r1-|<#K_OMbOIK8=eAvn58EN$5(_&iQ!+zr`4qr!?P936O zIIiaZ`kLtFV^^kcUl)4(cyE*87uQi4RF{NV_umR7 zw&hs56d#?6vCvM5p~vfwUBPFXw~{$L`+!HWK3l5s?01{FrY~BY7TszQEwYgeL{Flbto-qw(11PZ8zVU}%T6`QpZnz==GF>n zy41F3>4|b2z+~9;ce+8jVQkvx}U9c)ACjl&ChRPH7E7I`8}Cr z_Y~QF$>}v>kSEmEcWoi<+LbnfYbAWXWbO$!9`_z_Gf#Y*+2FVJf;rk&$?x}>-E7wI zN|TjZI^Bh%@QvnBGs=VbLL^P*OTa zw6WrLQ;xgZ_C4Kbd|Y8s66fR;#cfe3CHmo&8RE~1>N5(_-ocDK2iqNPt4O}p`8?G_ za)oIqXO}4;>3wgN_4m97Ld#5+8<%*kN||o>j^#%foHY8tOWtF4gG@%dWiZ^C{_> z`?NplV~;X1L9x+S7CMT>n)F5s{gj9O1uCN+_Y%IGTL|Fke&E0O{ve&QR%D()&G`9` z`7V5QHS7CHoS)*2rwLWe{wAiVv=U7pb$m;dRLNV`ai2Fcx2f`X;|I~W^xV6I)-=91 zn?|e}Rh+Llgm)p(;4NIv}3*Q2NPCq`Y);1Ss(w7%Rz}uO6v*W}Q>H@Fic3xR# z;`zI~hv*qFzxHPX7hf1uGpq4?9eGB)m-zltm+1z1YxOg7!GTA|cl(@=5S}*icPBl_ zVz-UQOM!jeD%O*@bD`FwKnXANhYfA|Sir26yrpf=$l}%#`Mb|D6#o3%c6$jIb6dSe zZ+8DoPZNsO<=ZdD934!)=zfNB9!geZh9euO)uw{++#B;l^?jP=gk93 za+TjU*017;)lF8H%;{)6jTp?~nvJJ>`unzSgLE}^jwE3wvFLt~$jrpU{&}L@cV3U% znEXB2%avQAKV?ZdCl>{3pHV5F;Ge^YNfM1ya@gyRYe*5L)0YOR^UBfO3~oK=9`>Qe zDUE5R#m*r2rQCvW(&);r(1er3hBiliM^7))Fp>D3=R@UQI>DdB9C?vzi?Bg`o?q4&_`2*)_Qk{sePwuWP-Ap>GW$1ezOhbmWfn* zG+#PuY||E|dwRm+nkLcUrE_PZGbwBr;=Bxv>8K3!2d0K*j;U=rKd`s>;HPxuVXpE` z;VC!n9C6Zeoo_L8k1J0~JR7=bym*>xtNz19$>fjhDPs8eCUa90^x^t8zNKXg?)xUj z9-cb<<-qSweQZ`lAe?vXkyMX|wMxf9b&Id+{hZW`1jVw~<;TW)6h{xY`n0l7oOsG9 z^Dtz1E`LyibTfKo^_oaAzN|6NmgI4~iX+osiPXGmjKWRoq(mth&+?dQoou<;X3*Jt zH}M83>91ejSB`XY3DU&LG>UC~%9=Xz_WKpOMU0Hy0qi zeQA7qSX8Mde~^6X=XL+otxf8w*ukI`0vA5F^wF*%N}4lNMx(oTD;Lhxzc>7GQtS5U z^u>HFr)vv_mdSZ?Cr1{|e%J`%AFCQ8qcym=N zwZQr3)l~em&YR6-(r28C*0c7gdY)dqb@cd7>YMmhk!@Q@yAy&F~ooKiup9;Y9De^;g)LI2hH)_ zqS!+Xd6huQ>D?9KnZIz|4Q|=lTDQz8( zF4&_x_Jfor_{6fm{XEyE1!Wm`l{z8qGuEUG$E654o80Pbla>_4)||U*7-W z@{QI{v<+vKo+}+Hu3s3vme;F#;9=s$oFgSt?70NbguO2%Q$7^lPw^*VB&SP*MV;}g7&0x+&mH&vQ8?hb ztvfNH&@}M0^;|RWQf&7dxn_Rt3#**=20Lz>dljDr1rj%C(|uV!#4eDIXh)C^ri5G- zf8sLyvZD3F3WwQ*al5>;h+*oxWx6|VYMH-$=+1`-KVKs=U3|G3ue}hi$M!LZk#4SU zjOc^Mqp)@F-tS|(9QE$|Q@<@N4n1rC+|)^~QiHXylW_tL~ZCS14z#m~RZ-3Gb_S(@oqvcf?S#G2bz& zyfI+2ojU2kH4-nS`vFdA=LSq3OYU-bbUu)^O=H+kP6|p`g}{*}lHwUpvNOb7~{~q^jl# zCAzNNr(aA;if*^$azAjZWy?A9;Yyx#P*bc>&Jp#gH<#?$F238>edF_~vM!R5wl-*?YDZ+!l?X{d5KcCZb=alhQuTAF~?$}a)^+k}*OPC?O&D`^O`nW~VO*?U#y8ymhVMvSxPOg}A^arZD|!v7Cfj7Gr$3$a6LMdZ&WSJsh2v zMruZQ4&>dos5nAmd&-0>sNpp`*Vp)mM#`77Eyes&(0+xhvN%6>Zkx5h{%v zriHL&-I^r0xvY`%r1VG;!FXWmnFkwAg|CUdBUMF%e|6Yt>*vbOhx0#r-W#U1v$3UY z#otr(vSMs?j$VL_!#IuUGWSRM@?c6ba$?Ow%_z6e7QMAzb+;wgzsDH;kjrN>2odND zS4^SiQ-62uwL`69>djIwbxCEewB*I4oMG9vFqLrYuELtJfH^DY81?5_rW0f?qV7@t zOyWwh2c$=74}ELj=s%`p_mj+*%>Q=}J6}xlYbkHe#zMBaeRASWb=TSs6Xsv&2sb@% zY2fDWGe$amJCJoXY--#zW(dMz(mt#i!Lkmw*=WI~X z^qB(!!}u9BG!FA(N_3PN1d8UB3ZI^bOKgiWTPOFYl|zTslAg)Kstf!fF*=k)G7S_iY-;!j>7$9o$mryE{DNok^9!4~iK z^&_Y87IiIN6(v>LJ?0AGGQsC^jmDzIsawbDjWDV6aCxY~jbAzTTfchB zrQ^(XW=RD<4^O^P>ErM;EDw@SVmoMS@$=cf&VcrM^-!;K!C3jqz3=plY9T_JUaAjj z=OmoRl1xUSAc<1v0mS^vuW z6CA@u*~F&e6_#7EiLS9!+t$lL+sjjc4v)+2Y z*;%jD+dI9973qt$yZ$mM>RJHLm0ebeyQ&xJtey@?jY62WLNeW0{-i7 zFEF-LaLT^E8m4YNrTp}&`4Mx@-rEgocC(GoRC0Ga0)zCT2$im1y=unpbUL3!_)8I? z&Vo1VFY}EkzhtM5D=yS~i?cp=_oOh1q3URw9~bsIYM!%jGiOWcpHCCo-#1ItJEtM~UX3bV)YsWoe&CPJ%xX)83pV4<+>p;7yR4IqT^S4~{y+J%`aZBIA zIERgEX1BA{3di(V52%uoXO+-YJnptV|Lcp9nWcAaw-v{kL7U3Ur1_hBDvt!#S)AjT z;~zX#O&KiAdUpJgb!{U%Ddtwwe0)lZ7LeL9?s-)43<7M#meu%}Tqs$L)jK(xV#> z9Qi;hy<4xHKByIvHW_&1e6E)G%{oPnVa;DmgtEhhMUiJeTr`}k>cH4lZuk^s40mtG zT#89C8HDzhrim zNpt?52gg+>y2F*j&Vm)`WC9gW4fMNmt&>w!t%~U@8d=yTLt>(}SgxL5I3vUS>irj| zuFO(*nL|mxd6V$vrDNa99O8P|M0Z@lZQuz{Zu!;B0ClN+8o#HXNV~7J<^CSXoj8g2 zB;|JVzNqu&F(;ko#8NwlTyg}B?6`$p22wv9-CSTE-%eg_elsn-_~Co)Bfre}8KQpP zymgm#R{FQJnu5y1voit&m)@&oa0b-h7#bbPwld$(&?hiD{#x$@m*n8@{l3gJ-A*kD zRLoM+gp(Zj+0^xH3?Frqr9UfDxHiq$60s-q8<6V!Hl{wRj=kG#j%-~S?~|l-M5lrg(tWIbWf&Y1u9wC+K|d6F+pkKP+`a?$s?uMy)E-8KWplGcO8O{{ z2VkLZ9*;09Jss>j^}$^_r?*Kq>lelGk;+Noz5MDylc$gNE~$nD&%dPlzW^yf*1ze)?cxD_ zm$KyX3Y&C(5haVrWC;*I1x@2@7!*yP6isEEx8w{ur$9Nl31rBIK9%6`wu>7QAgMf* ztDrapiB{eOd&0xsZ{mZRzSA`|I?Qg$mA{-)<7gT#>oGnL6X^*!e+YtDK${w}wqvIM zIr3$l)a%)MI?<(xvzyKew%DWt+3*6VkhrGUyzwnYfc4HDl&a)u%a%9YF zhpBf$As?ypW9J-F`5J#ev#QZ@hRacrbmEpKoAW|q*mlz5ik!rL{evg@R_m-z`mLWdPelYaVJmO-)u}p3`>KstjeD7rw_yR2RgZly z<5I12ZeUOV^?7TyU$=^_Dh|gILAxpn>veNV(Xit zYk8t4D**I%Mm+~7Yji5d?3LA@8^+ifr z4#2&UZC3F*o_355;+h1Bu<)ZYs%1Uj6OWNPbvT57N+rN!&t~u)H35{&hDR?c3KT< z4s!vnt8^G(R)1{7URDyF>E!EEh47zy)RvA9ggHK6VE zV&+KvgPTen=Uif{Sqal1=zPpFI9~@=#=ry2%bUp!yVpGRPuIg8h0Bt<;bg6XL?wCF zb{uEphko9@Z#eOb@3Y6BH%4y^w6XV0156Sgqukv=I74x}1(Cr5UN7&eG#JD4sE(hxpI1%NUtbUJq43Y&it0X_wL)9-b42#`1GL!#%q(nX-)AwIPVADhVgDEU}p zr|b~sEw0dU1=*V4wJ$xxF7V_^Yhu4!fC4!vH?!N>^VrR$t1)!LzJB}mgo#Sie^|!Q zwJy6cX9t!8Y3RUncCchN6=6s^tK@Q?LJ<}`Zp`RrdwS=~jA=5Jg&Z;Hvgb(P7QGyg zX}oJ;BpGc=-7TiDl~D3m*axl~4SH-nEoDa4N7=%E3cKC%e$|V8>@J&VZO03)w@dw< z=Qx5&Jz0LEyY+D%YTF~rK+TKZynIN2OVaM!&xRq?tJ=Y+R&7g+6&AhmOCBv7vhMhhXo1J;iRx9>Z;V8X}# zx|HAYKLX~vNx{=!Dcb57um^O$u$=;6EeBXa?T1@f@JOdxj+I4{pL9uQ%W^>_R`hi^ zHmaT$C$kzO)Js*^CNy{(@r~t}|8D|z=(|j((&y3xKjWI`S3x3odQtS^B8XoKa~XWm z^LYK?KO($bA?rbFDtJs<2cI0ejd?O$ECxXJVf4um@HX7J0NXf%aKdLWorr7H& zriE#|zI?h?6@p&E*+>L@F5C2WD&;c&- zy3R1<#!&Y|*V8<((;yLdG#l>J!m&DyBIXHBq|n0zw&;w1;4kJR(!W|V-yqDt6TBYC zsb1qUYgh76?3lC1_?)CsBj0eg4Ho`k?Hj>ExwZwi1#uSgdrJ7hW2HO z7)D1%KNwIQq2sXAi8`Tfk6_9z$vOyRMQXSqK?(WULAg*(R;Ljzjq|~xZPkQg2WHr< zn!~M9W;3qYfYa>PSUts;^9^!5&G`s$C>NK+ULg>o_!L8*OLFMzMUoLwFnhFTwxqZX z!Wz5Ras}4iD^e5sDv(_!Khj-Uy0*Y#kw88zGD02Qq{ThGs@f}d^i$ts2ogb#+~5{) zkab&XOjnX_k@NwZc6vi$)T2^}%dB~jJM!2kS197^UF>mjikHbM*=9o zszuO4mkUCp;@^+|kI>S^st;gC!)K>0z)#1287mLV8p}ipAPOA0ns7H8l?+hV={0_z zb2FfNxF*9>BJaO#=h78oKGfwdsi7HNr3WJLmtAro_0+W%@@b%jTYSD_(jh)K1VOg4 zTEbd@v8jO4-c^_i6nw&%2Qa}RXZ`l*?tG!79d>-lk$EzB1G#xwr7EV9aYU_T&r!aj zi&yC$ZEpvs!IW1kJ4SEu2FuH}x^LW8cHKOK0BTccS>Ha4I#jSrBr4so`sWMRBzCDF z6X)>Dv&#p)g+BOrISVh^zUdwziyKjsjbbCxr@4xbuBVI5;ZcWRLvQgJ)!Jc~;x%tC(HFqK%xwdF~g^jw5%NGfm5$C+ODpGrt0ih;w*^FE)&Ek?1QcOkY-%*K`;hfxz~gv3&1 z#g?0`4zctxMI=5+Q68`x*w28E18lqm7P7K!yYv^a^{4{AL>jL`%1 z0&qPv9(GESmZ5rg<8Q>5Gfl9Hktpl9ZhB+oa?Ds0X7zCF?yCP&HYg0t zCJ!SH40a_MkUgF&UE^^+qfhk(G1WX*l=^C%a#IlXD>5169jL-4?Nh_eU4Frx)_w&_ zDTl693D_8@B7iwm5pR}m8pc`mT7BOc$~RiSfqSE3LT<02;|+0Pal^cg?4;^k%<@fm z=<&Le%f<8E5kbEk{cA^&+P_OCR(1?9;9y>i4bpF1Ctvl4r1PxvY>Iosae0=Ao zAxTH4Dg@~+luc=IAg+Ef&{vRiaA5kb9oh>bM5OFUxWn7Wiu)UOK<%Nnz0q;d7)}PZ z$5C95v3`IQlfh))Z%;}o4QkT{iQ(37%+^#a%F%60nv8`F9gl+BO9FfejjXm3&^Y^I z6gq{$CL1=9=DmptF4R!t<`ep`ysfPK9UK;-&z?@b%B~>IN9bLO=o*kX5EU$+&W*GM zs9tzM-~X;@2XViu70^8cy2Wd7s{*_g77;eWqHv&;f&~psh1UX5>uh1o->|pR&CxLx zBg=jf-zHBHg+=yuRi%x+gkpSG2o?#D8PYSVy(yw#B6=a6%4KKgDb|QJmDqSdJ=A-4 zWfs48#c0HSD^IoUXSAnQn{X#&*OQv@jH&hP7dWdRY$-Bb3CN|luSo!TdcZQu_PX*l z23Lq_k^e_#K}|1#(RX;{cihYV1rKSV;)jF663pw$n{t$KkH&EM^pBM>VgLIc?~TJs zpIfx@3*+afL-K@wp*|eJvV$ZHj~;n*LB=#JDO3mEe}g(Jx;*&g2Z; zP|&+M>(8+!+`gHSZwm_*TJQD8qD2XK!R6`$$s~8A7G%D@&1rgL)hV*n+C{PHYpl^Y zf6z7b5((7I0nRo5JlXc<4tBtd2AHkT1en%D+E}0f1@Mbc%tYW|mMknCVV{gNa7ZXO zxFmj93|^v_m~TP!kqZ}eEn;Su!xvZxe6l4qh*iI>m0;@SdxPm+2yR+EI*R&Slu8WW-p5r z`~zl^Qkdzi`j=gJD&D&Q;)T!86$Q|~4jDE~8^%`O&-zLVa=EM#$$NA-D+fQ33?2=M;P_;dy;?1776uKc0*6lG zjNM=pNkS)Ul!&*MihmjSS8u6Owr^xF(@cK{@j|3j`kb3xI!LVoEP1MUSZ`VS3Z6c9 z?l3CE93pyBGpOQ-Oy;nFXn~R-t4SW9XGSD6%6BGl0hjD&lw%_d7i`rqJ;^?G^-g$O zkdFM>r;b_)9;$n4K&#kU292zP>xQ!J2k3cEJ>qbN19XCJ#5rZ*cn6K2#hjZmrZF&! zhT#ZT-slFUS?eVYRpT)BeJyl;o+O3nSW4LfuFPngx;A_8@DTieE!~R!kyTQxCAfU8 z#yYYqm>n?ScUc`8~s|!nzRAxCamzz2tU)JuQZ(Gt@eX#aV*Li491Si)F zdA*H)v!8>8jieB1{^;X34$E&w_7*~r?1diV&9(tFOj)-#$B z3fOC=)Uju^``j#(6&By`7#d~iBbyd8q@dvxNEA9$}!wouhMl1OCOxtL(w zPH+hI{uKu6j2uPjpA|U|ar;&MmopIu^Hy$>#IxM$o34m05gy`^2Iipsmu(Udi8}9` zfQU+KKcE8{6*;OgUbD0M`xyjCnf+WDpoNKY#1+pOpmGU1u4cLX0)M^OhnwHT3lbV@ z*{SUKn^8CpJ|o;XZw=UxMU%bl&V2W9O4}Z0+odaAt8>Oi9&jtTa|NT0*ED&Zr=uR` zX)6E;ER;DxMNnxS-Uv(qk^YxZUF3ztH@ZIUGaVV4Q>2e#eOp>r>}-5R{uu(uJ`?|i zRLPg>5fzZ+JcM29MS0_BA6mOf(?*Ns>lpRq&obUVik zV6&;MN-+N%->Z28PwZ!+X#4*4AiV%01^N>Yz@DbXl)%eGXPvT4&J88mRjT~aLwZ&- zM`Le4e758!i9{JfbF*85e9lMs*)q>55UNabMDJ)fKV9&Xz_=AI_8;XtzwSK-e+37- z_fDxs=#FdAlhNwj4ChmlkwFRw9S9=KTo@qEJe0Vv0FA1em2Ik~8pfbn8Bw6BBLK>a zr-m@l$S?Sir&$c7MS0QzNiQ*?vhBH zD+MgpNRg?8yi&)8&nF$IsfINDd2Iq{%(Nd4AMUt)fBZ=M!^V@T9MLec6{ZJ8w;+V( ze?}Yr7T|iS`cWWJYf}XY${tKC)9KX?dX0~SH5oN>z==Mty#s`GILg{WQJv=&O%(tX zhwA7CMhl{|A1f-HoMfEFlQDmzJ)1xkwOEn8?3gCz;JHM1ZGh>FKuxWMwXewLP@(!58Aj>&DFq6R2! z))XUf#Z=Pn(MfXM^DeK#J%`%1fII6;H;pcQd}#@>+D!R(;I&YYaII#vI=(MlD{=sP z2+a&v+t&R#c>!mCIFo@S&!Bef+OFMxW`AF^EDi)PXEO^3D>1XUW4o!%LZ0-vZ5EV? zFcf{a!<^fDOj{Olw`LF|69j~>D=Modqlr!Kaa)|MVJ|0baTT93sLE)S6=F}l`bX)0 zEe|W1>MAolYa4U$mFQ{?8@V^X=Nix9HWU;TxiEE?6u2Nh(WOEH@2OOFM9QKg?!6Cs zszDN_a#Pc?Cs*m=I}N4O1!cmCB?g}!h2-lF?vKFrI}{1WHUS8EfqPz^lQRikt9!vS zIIOtg%o$8f+c!u0{rx$f%}@JnH1m_8>3?oJAhdZbd4NC5s_>t@yuy%~VAKw9xa1~_ zgp7nz@3Kq zW~J(`zt1!Q?f$T&2X@+bK9cG`G{1JqgdNdakxIWpe^gdkM>2{f=N3BP^jF7tHW=2v z6ZC8{!>S#pFRyhm>3+5MD?oeTahEx;HOuN#{@4XnAh9RV&8A$@qpEku*LGBojYMx& zFiqM%G#x0MiKkzhAM3~crGbNp3?-rORwu$xKyQ6?3-ihk>lXpkUpu9`&Qd}~`KPBr z^*`jig4a}kNW$B}PAOi^2w5YDZue!erbsON57VW^X}D)9_fTJRi2|kk@3`C=Mw%#s ztC+=@e>$jO_H~26U&qw|-u|oFHlsm_-R#?`1)@|RfoKf7N^oQYj;J7#-~ZfZ*myF# z@W;{ZHMHeWWBT4en51F9+qYUIibI9TV1QI`!~{UR^xL(Vz3Sdj0~}G~rADMM-!m+U z`*8B0r5wrv>F=y@n^BKUB?~|n)yQT3Ea=}d$spgG{|jq$m-(TL2n;_6CWWxV?^U&t zr@=Zx>_%$)I^wA#`zzOq$^p+RfzE>Vi4yVwj$6*uqw1h65YFtz=udC-Fn||rHkQ=T zPfQ-Fdc7t^-QF%ETU86-_DB4qkENwgOb^K*60!PQyI-@LLsD`49U^`~%vQ?f*8vny z=PTdyO&N!|?9l$n(CZm$=^XMQaJYQ_RA=5$6Fn|Jw5vly^HF0qnc6bk7Z(;{np(o9 zY(Gdx;$<)^BIf}gYJj*Ds@X7Br91CUD;dgqC8J^BD(*NW?|0VI9FM?6%b!urcgO_j z9ZDc{CVo}q1czKO$q&C%LQn6~&CX~9U8&1EznefJZ7vDRFU0+H9!~d@dit*OCt3xI zZ+8W7MxAWcV(PmWD25T6^@`%#RvxaB-M0F zi4CQ+A4n~gfIK}*-*_ih7A3t^YKs8$v_?kje{3j_<#?-+-5jmDyjfqLqz6pKiMpO& zb8ptd#`@@I{3+ojOU1}gW;y@fNM4k|zKhP+%boA+#3wdi#@(iC15YCe2AU;Cd^J`u+sg{aX<=nMTwi&UQq9_t{9mt| zN^XNx%MK5Ajs?pfJ~o?MG95LBwuJREP+e0mOj2XaATKmo|NH^CG9ws z^ssl5ZSo?B;}0bNnAa!bckjT0=Yi)n80ZrcfJzfN8iJwv8SjOrBq#nJ>0nV3esLE8e%pmyH>+rL2j zIQtwvVs0rYyQdksPL#yR@hyvus^xRqndgH3KI!2=4W&GQcMPliMTp2c{Uv7(qfi`IF6yEn2zUuSvQmk_X;5k#I-b%==xmE{v}VQ>pW`3KaY zywb)hY}!pPLE=Vkz*6q3Z^8u}E27fa6AteJ!=^(b*%52({}k<tMFg=)>R^mR;@hQea zB11B@Cg?{20Q=BpmR2zj^^BbbHL?JE6jMhOp+2KkHFaszh%0B(!&(>iWsAHYE`6#T zms=!h>A5v94pojk+jt@0tT!`L8cd46^cr_B&brjdU>78F|CTcP6R%z zwR1XsQ?eK0_9X+G>~KWb-G2obPD#V=VuBbxv%a`jy6;Ndoe3?>CyCZ^_cJYhK!=#d z1`Ze8S&)BfenoqPtpNQ11I`xvQmNe7@lia-uEBB)b$Q$M@AgWEJ?Ge+(c0wqj}`>3 zjJ`J#U)gpB-pkTVDL1{GgS=7I8{Z*kT$Pj)?6PRUA;qGga17`UG}*{k3wqW70LYXw znKmh=;A>GuMKtn?3|v2Jcj0GqIB(~N zTs$m+iF|CM6r6SNalJm;l;!JO{qvQ|Z$1uK+zJN*;cFmr8mh3TvHD1`J{E**%if#M ziecOS2)S_X($88O=X?i>l$|eb!M!jA{27Mhq)dQiX$dfIw!~!Lk==FOc?)4rq<+e- zxAu>WSth`v{`0d;xF>1L>bC04ardmu`slw7{!v`kJOVDVk}2;IGD~Z4-C%tNKTpro zXyF~)>H$Eg+Bi{ic<8DwQ1@9GsOM{-e6O$(hFB|2j!ie?=F*kvc?IE&{`u7*9v1GY zKYzTZzzS~!^HW!WU2vJq?p|k?GJxMRn_H8c7)U|;7SLo_U#L=@5S_C|NC>QjHc{-- z6~4oArD6BaUhs$ZChgA-w{PDI02F^%B(QrM5J3|4TK=YKjqw@zAzf=TN}mGsRe@+gx^c?YY1j+y!Y`{$nJ}84MpQ_;sPb;yM=_&YSwVOp#MTqm$zRSAQqsC11;i3$!S-qTIq%idP#w|!{dcCFt&HNlzI3LCWY zMyW@c#_pLLY_dAmeb@aqY24GxzhaXHfp8YP)zoyWV_7Sg9?b4HQsK@%tT?e zoEcX+ufROZM`1hdb&|L?>q$dbojhi8tgIT_6_UCy)~zIV@EySKGsLHM=qew{90sA^ zl_e>~wZ^LtN~;MaXGM|KB(*^+wsiulSn!SIKnWWJ{S=coVLIF*B$h?)#&Ca*K=Jbt!8M6AzgPNX{UDMloKR`N1b$>znGB5Wv#`=bwa zKNpHP;4P7$r74fFw1R{(Javi!C54+yt2bgWbPLgU7gIh&0Dzu-hxeSL{>VBrlPbCu z@+~X7q;Jm7@|(n{s>Z3ZMJA)VnY&9Bgw0ElqE4OYk+UM>{Za4hW;H)mli?;s<^#n>!0YHd2q`1jz?l5qR0V2X5sC1z2y1|cDV=< z#H-C5&5OiXN(H{q6{bp-yuo?24DqQ9VQojI0E$i$R*kY;Z{sOZZy~e4MgF9{T5?!2 zqb0;^sX1K<>vuEdO?`I`YHTm7M&B3>#K1A=2fSFHk~2}x-py2DrJlcT7N-68vT7Ss zp5{gX+D}w{WoK}{9E28zWy}`hFYXA>NU*jvV*o#0L+CyUTd1poA%6nyU zb|P0xPH0jFdbY`>18@qGjg*nASs5-*bXmw3qoX4{RBnTn-J|!HiZcA>rT&$p5u1*Z z#%jw8A>y5@zU^0X7q{mL>muLs(=5d}I%PJ)#;z1k46?ekEd7zYdw%`0RsK9OHf{A$ zR~x3FV{5TkWv(Ii=&t-jjsr3qP|pA~9BC1Wl$oGmU3{n8(MBJUy@Zs7BB7y!^0>-H zFXU1i$Wl7A$4gKNT8&=%%yBu^G9R5)zIbvUcJ>M8X^fl-AK5*#{#4b*_>aXygm;*G zL-XRY$(7YBigDoTQC29tV-BD{5?#kjG>zJn!yHo)P7AC+{qjv z^VOd!X;({{r}Y}=vVH>z1%D}N!X1eea!|6rOFe{Ni22C%JUS;yj~Ia(emTjg^{#0h zD_g+X#i5zWfoUAtq*=AFwnrTC2INw+z%^D@3;{@))E5koLo$sPqG@FY;LAqFjX+lZ zH!f~`cwOD)$WV_2!t2WSYYd^N5Ft&LHVFSWuUDy_7|ob`3U{)Xj(H#`h>+n}`yS4Y zw1HveBYO*u=1u>UowUUDn-%mdqX#Rw5J7UYJa`*K3`QWaTuh8~65+Gi1~b{NCQFLc z(C&*KH71dNHFCumMoA0&t_(J;=gftf2(#7yKiacei!eog8{OF40|?Ey`7YM?;Tou2 zmq+c{a|2iGu`>+HOaXxucp`HK@!oL5Z316kr!Ra3Wzb+FCshB0&^@HwTcG>pwGh`I za9JG1)GL)VnKWWnfFh9E2T!&_6AtxswfYQ+%@lDX=!f?G8X<uY)j!86dZB9TN7)qnd|#EjHG-HECl(qWRrm>73VH&G1J0I38@|FF@{>&sh* zIM2s_)&j^5QHt5IPv+y)BU!+eo&Jge%jJ>{kE6XcysaC%1LFf+gIOoF$UGV0;)!?d z_FMy}8n-qxI|r@^PJL{aF`uk2l@)q_BU)FS(i>wA<+r6lpWJsnFbV7=`@~9gjLtj< zVrsQ(6qTV+#AS&mn20I&0u+Zs;C>T?vG9fVg**Vy0MLacqtAB2Zx>?4`iitr#9OPmHE@uis8?& z<<-%~HUD|Yv_`&=q5zw-WMgRuWO7?JqYDU&j)F$89mlxSE|#!g3uwOi-J7R0>?4vB zZFZhp&e{A$-ea*=0a}8~RhK$J!#azV?3}{c=SH^gOZqXcLtQEz={yWg3qdxy%AWck zRIm>8JR9QHlrXV@S3IkMRZ;b3^DSGEO7;}Qm}UQ1;Lhqf&``w+;Hes*bXMh7f1Jtk z;h5{00v^GSOR6Bel zHta1sNg1#Dpy7snimgu~HOYvLHKxIBy#$MK;A=RqjdN@31^8h$@HYprIGCo0st!?U zpgtwNd#o$7nueZ$pTSIv6ZmB5Qk~_j4WHWjnnhp3Ic4WrqD@DVS7rp+8?s8#s!bxxo&zH z!Qp7n6P(G$Km1j}Gq8_-khc!eq|l-p1jqBtx8`J%g*%b6o=?W0HUTO27fXMv*KqBT zJ(@gvpfv0Gc0KIm=>sAvG)kkPhhD_sq+;U#twlA}$wU3qGkajXT=r0)()Fh_K_Lm+ zD8(9)?Y+Rc=zBBC?(nDcd0|Gs7pMmtV{f+ki4EHs%f~+PZ13f-_TXxBC{)YtXGYR2 zHvIOmy(U3UmBF#fm~BoYW(xIJ0JSvMi^7P?wgRuSch-ypL3b;)yr_N~;4ycn73ot6 zyU~n_em^201*45U{-x(FO}YL&=-INeGS{$iU{?`oq$mB#DxJgaZ7MUnon&#F#)zsr#Tyc!BY+2AZsj>x+~(?_Ry{kdONIA=O*>60%v8+mg# zn|$3RlO!wBmbzfN%*J#-CgC#@)h{XCVu*)uWR-F*@T4Yhc*Ts8ozJPF7EXD7+Z~eERIBHhDxe(o zksLV!2T8AeP6FEf=%Vf%Yd=gMrZXeOp_MWZ%jhWsqe5fBh$;$amhUwnhu~y#6R?~n z4g4M^=nj-{M>I$Yb6I;6M$iue+$l7|wM;(z(9?NKHw5Li!uC?!#)`%(#_=47nuROQ z`}UjHr<1Ho>h6!f9Ji?B<{eN|yZApHpD78aOJ|ob>@buj$w^HOs@3OO9)1RaK5n*OK!C<4lp~&Kq$q}gp@st5*kcl6VR46S{&;s+pry&)TP>TepqS3In&=C0#_!dp z$P1b(t3{o656is;2Zm4wEd&{NxBUZ6lyqiY1mjpYMMSx zZ-@tFa9wzigX|h3eIdPH)+3^owBhaT=ExKpe0R!(Cv&+M87W3&PFTz^7d+7F;-P+z z)ulA6b%_v5C`bjAN`?f6T(rs#D%i0=;s^Gaf`$cfWygXNX?j3Tl0kpHAo9^s3<498 z7ZRqv9{sgGSmB-DmhyHFSsq7@Z|1ZvRhb7$QuU(2#%Ng12XrFKYFB-wxlgtVXGZ~JuY#7(@UX6Fwf4Ke|8eEpGI-4?Xg0E z<}tGae=gQ0g%tz1v%>H3>b4jnWb@0}B#HZ}A&)}&l=eh$^+}moJH1O;9Kt4dc%M&* zvqfY7$?ik8PN&y885hgR@zyT@*I6Fde&!F|NF| z1l36SH4`O2OZ*AwwEioN+*%?wS#32Dk6?jMP6C&#+iV=O$K4@p99*he9cYiieR<-)OH)-S{iP`QA_;i6Q?;x!dIL!$+}n*DsX&}h%)Q<2VJ3z(Q{=>miU zMU(k2+zw`s)OVWh0ox)$zI5(}J;Xy)1T!%jaiKu2ZPf}-1(@4^92H5xuh^|(}7s)60j_h%u(4t zHZ@iSjGId`vRviBs@4fhX%rNZ!t*C0^ll(|x+_|57cO^9WoIB2q;i=ntJ!SCSOxV6 zKGdEmVOeP#yQ%Tc9uGwn&2hEx8!m=4)b@XwmslH87|=MEg#SQ%!Fq^cvqh^NX<31kjI>D*O#GezW?nI?A$+x1!(SVt&ZYQ!c7Cj83&` zi>ewhw88q!iB1kK?8UgFI4v54`t7w%Cax5Tk>#6K+*3?Vv;nnKhaq3I(GS=kNb zH@lwGcm3LzJ%L*=q)CjKf0m);r?e8{Nokt=AE zDL=w_k_>JdPm7C>u4Pt=PDBqR>!s~-(C1HX%y0{v;-n=D+aKB@ggxoG@G7VkNK-v~ za;X&3nDf)a-7gjocBXx5Kx2BNQRw{Y>oN30xvfE~=}6VmUHl@jK=Q(*qlBwk)aUfN z7QKLN*Op<0N{dWJE3t~mh0&or-XUIJKWzO9%qm2IAsO6@l(8yOr2OZnKcex6 zMoU~v)24q>-Hoz3_f?FM(q8CoJj4VypTKO^j#$-U-i(>v_$wzR7Dnm6QnaW}E&qc# zoVB+uO~=#e4D98v8Xyx3&_;GKPiW~}d6RY*8?CV^46?u377bgH0pdT|M=<&?Q3ni zB*6txu)Z40=@s9R*_=81)TTi-9ABysnZ{PFA^w0>o`L^vQlrFvIjZY%T#0?Nbs%o> z#jv0vB7=1OHw|5Ri%s;%;(b?MV1ac`pCtj3iO(?K>3z6p%L-yDBdgCHv%pQY${Fug z2U~6BzeBJPagE(PzCJ*mNgCz~fiG=#2q+xYD>GNyv1IfKXa_@kgOsCO?tena;svFb zkpSa48kDbN-uRR_0bc(QWdmlqp)boku6{^Q)G;6TtsnDCk2}zE<9887v@LJYw^kMT zDuS0mGc@i{&jjxDQF8|>)1=a^6Dj%s7UcMcA_?(ZuWN;o{)~w>D?dvAGWzW=FCnLb2^!7CBpq@0c1pr zx}#J*kZuFb35^>%=iH`tFKnyQ^BWulm#ViWkb5MFvmDVJH<7=wRPPh2I~+t z`tG3m8T_SVi7uz@(`~HCu+=mQ^J<30`U3@2Y%4!z)p*~nOl*Y$U2WD`R8fAkq-hRp zLYG%mC&IC$F5n1L~FdUdfO%@}BC!l7W3Uu}9w>_Q`UWrz!6bAgE z08ozbUn14&0oT7hHfL##{SZ4%4Nq%l_s&148K6=sa*8$IZa7pruovWNM*cXl*qR@X z7T{qtn(QJ@u+1r72jSYo9jbJ+h;@Pp=7@;&3>JF4q&VEk;CC@oEp8YJk!{6Kp&Wlm zNX%zgY}BzCaAL8GPry7*T%`jYA22LWOm*nI>x%60VCOvQ6cUvR=PIKQ&JXVn?J@^p zIuKu5grq24Hq|%Nbj0vtK?h%|=gg(xxPW*(-3i!olE_E%d2=w!)4qp%2Y+GD?gkav z5Qf2DpT>}pUja%Yo9Ij^aRs8ni>ifIpltIU3mlt)zcJ(=(C-+Cjaa<7)c_;<1xvFLRwR=8ksB{Wjq_ zU<|XHc2Wm|VS41;qBQfJuEwXmUZVCTy<4jiQlT?nsOqHv;W#+o8o{qmSZX&F6eBcn zp*!rDIXI~Y(E%yLvczo}NVa!`Ur6W~G>m_-x*Ux=nVY?Pb04I)houbWeQ2_M^Thys z8;z+w2*1{%k!fLtU`YqNMG`O~t0r`O(1nwT64y_vL%`C6Y8>abqa=O!XK*Wi9G_nx zW9DkNB+Sqq5htI4rDl&h==nl}VYKnS`GDyictTv_<3^hBTg&i${XB;feyufb+JFGq zwGmJDDc@e$)Ww*q#0wm=DQib&bw@H%3O7`&E(*meofO+g`dbl}n}rRhvjWXK&>w4% z=j|96{YMbXY62i}iPv?&44sIh-&r-%m% zC{oT@Wy#rYux+&6@c9enQYH;U;&YYuh!X8X^FMD}ETiyHnimL$HW>Mc+P;Ob3E z7j67vyr)-Ri{?-{-j??-h>&A3)L9{ZBQ5LAkS!{8(Y;6~l$m&e32$bDonl4{CZ>bH zO?0X`1HhWh3qn1kf$ zUxA%$qnP>ay*D&*liSTqa>J+NT0v8T7Jo2&WXGZu+r|$sFN%`ZfYH-f>7Z`4Q(y<$ z7X~xh)N`>zD1lVDGo|s5%1g3nmil@-N8&Is2xHo3*@9@Ew;o98MNywr@?hcQg|U4B zGES-?zn#5-}oC%P9y^HcwuL9-cLTo+9$FAeO(3A5ijt>Z1DJ?uD zsf!Pl{@{T~E&O!iK@+^jzvd6pwRI@@?2S2(kn-o!#s=NGmxHRA)&7K`?|sQ7OmCUf z|8hKXFPR@i{OVywR(=G-mV-AyjHtbAVWn%9O7Pfxe%})GQV+g1g+> ztbICPXs;^hEap0QuT3U~-7>I8ROU$)evPsO%zf9D0~N*%nyT|I6-(9eM4n+9<2LCE zDi!N1%U#>%MmK*HpTjmvo$1$? z>m_1{Rns9uZ!Jq5Mfx0JOOXUCi;S4x%zVMh_(W99Po+v^W&t@=$oq&*=QMpIe*2IW zoH`Gi*@n@fUvOYHnqSQvCfdfM`b&|HhZ1%gnJMWzBLALW{)%+XjU*U}<*9}h0OeMg zy!Cokh&4UYvOEt&UD!)>*KXS4v}#J>_QJ24h3LmkcO2aCPZq399NU?n(M+&ns))p- zcl6}uMG)m?`9-=#95nI=?5RlfNtci%uHB*iR~HBZV5Akh5wNQHSx5nSLHgmqa(LyB z+8<3@>t|#9T;3_7wmX}ldfvI>Ij7KexU8uh8Bu|)N@?;s=VJWFqW*kMHZQPW=!b#+ z+9HU}M`wl3eB9VMau<(~r72lv!;vhOlL8vR2{r}N6+D{-oA+TlJ((H5*NKK!kZv*L{pt_hbPMBw0`{>Eedqnp7N+5M<&&<}y zn%`R8ZWebXFz$@;kWSKO!}t@gL_;9Xon(Z_pejq=+!+dJewA^z|gSxpzelgb|o zwWluNbh~8?%`98lnN~irJKhK#K#)5ulX{5BA;#E>78LdxP;*&(9#;Atl|Q|-&)zc| zN}r4+BOdj=48oZNR{%0=2q0^1 zDBr;?0xHQn1^`63B|!{A+~Mo65Z}>&L!JU5=RH^^b@sL+TI!JPMTS#ca}Sk-F}Rvu zqi8+Wu#_=7Jgl3wX1tP==w5{6nNGvGXq+sx;s6tQB_(J!yZ2L{LE|)8k}SNFYI%-7 zuFtD|H6vEH7NsmUQa-b-q5an76!)zb!O8LYC$_OwI>o-J_LwhhRXMOnflnS~iU#Hw z38iHiv%e~8%eBty3wFq*4uV6@69xh^Iqyk6eWgDZ-r!7hav~oRqh(jF(nbPQ_^xA} z#C>_85mj`tpppask);&wcsEC8EaKm)e}n%lj)~V#e)n#^s>ds*`_IkF=L<#LjFFvU7%e-L+2oymymH*$+l_@mIG>Pqmj#GB>7PYd^v55r7h z>0G}yegKyOB_U{#WPGOGWFxHXrg;_3qlMv+3PJR3p!XVUAvTUHzWyS*&R(#Qf%aaC z@>{bcQ+z2-{^*O_gF@&i16P2dosU=ZJtM+eVy_-tYpbs~Clw{=9M z-0j?hX^qtYpW_R!55!O&4P##CJJ2BOEA82n4qo2mKIupT*&ZAVlyES3Fn){fW^Rs`xnX8>9=shM6gi4G zTM*pjS9-xKHFSe#zdEdRCQ(CiY~g3aCm0(g_e?edZzT4J{TQov$IeK++iydnt2$c~ zyBi4C9=&YTppWpmq1ES@2o%M9vy}Vo*#@dbCudxO$++BR%s#WpxbJ)&D>qcKnaf#+ zQpy?53>Y-I^;L>M6==FEcTm7=Afv|3DkQWK2K%8x$m0aMh^Xh$Lb7wHMDbzQ>VwmG zxEldl_&M9DCrK9C`gUTkgF}kY8O~~KGhO*t&AwP_craU?3oQG*UOilzSp`$x=)NzS zi0(5)&7$e!PQF~i=l7Ch2WQ;wNx%c$12Z$!{z3Eq1X1H-E*0O?J)Q6qE_g$g!z>p7H$ce0Pfx!_!+=Sp z+^{?A+cI3YlBnp1I-(JCHd8!P&+p9KeQF@Cg{orX)42~U%n4%sVB(tDsfxUg1lzje z0vvG`{I;(L@lAq*|DP;7XHb?Fw>Ub(i*KErld*s?X%kk-K(+kkB>R#@=_`a($vP*t zaHcjpi}f<}?`N1foRoUZyd#AcrlQJ*9Ye1rhbVcJut%!aFhYaXjKkkyW5_Hvqam1N zCq}+5pW1ipO#w8LO`qrRwMpMn8whV+Pkf1JQ(HsJU|~4Edd=A)R%@|W3F&l|K7ZDD z5w9(a9;jZQ{cy2t^Wa#=RHJa(b*Z@yeA1rM8ZUjPI&#)dD*h?UKUopcN_W^kd_XKk z@;|XGq{e5Zdl%_xmbDC4%*FMM>ShW6rLqqbX$^omqWie8=<{Xw%al0oX87PWcjh+a z2RoLoN+Gz5;ikL;zt>OJvG6Mol2>8&Dk5MrgHkm5Z3gHwwLH+pyz&E@a~hjp9dr10 znVe$z_4Qd0+%xxO{dFlbT8MUGgCEvXc!%7oEXM)onj>j7vUz)R@VMtPm*@@BnP?{j zt9sZ0m^sMk~lr{v?uZ15UV)FmyrI^H9II*7O}Rqw?MlJrecvFaOc3hI{6s>6Yv!MLf%q&eWY!CsadZlbd1yY0|&y)5!NMOb?w`TsY3d^Xql?jk1oMrAVyu zZB*hX8#y(CXRpCx4s$YU-3t_XykAh3ou3?d#(+(VfW3&IqZGrXxxG2O1k)Aa%C_j2 z;#WHKk?nF9h1OJ(V)R|p?fIa)QU7%JoNcq80$IuU67-S(chi1rudlwBRNy8#VEf)R z!4*7dSPEMO$@V)08NEC|_u$?_a1gMv6|Km&dS2x@=NwBRP-os`t~xtB+^BC7tkUqI z8!WHvGx1Gx(?4avv>3M&AFkWvX^Ka~g0{$hxVe6V2=FrHNa(!0v2;~kfan-?;uon7 z!N7~D41dapoF{rTi{Tnp8$LlN_k=qSU6_*z4x*C8a-b6U%%g=v&y%@IPRUFdzG3vP zz=Nur%urgJOc2iTu7UxueQDNTm4~)GjJjYnLg1%Gb{mm1j~GS$9-OaJlukEgk;eHQ zZ>nZ!hZ*6V&1N}LQV9gX&bp6t1E?=M>;vBH zI|HVi4A;!N7#1u2U}^^y?jy&^00`Ff#~X?y;5GkMGBkG*79v|>tsSnL5%4cvV(|uL z3pEWdlA!gS)^kXiwfd_vn@qKm5|^uQkM@dgl+LJDs77_xoF)~GgUqcU>fX7J(r9HE z4*afuzv4U7k2cmJ=*$!qBs)sQ*ia~{jzx55rb~>zK@0aO*ji+5gF}Eqnxir8X5r)V3q&4C=+|53r-(LoEoptIw%`mJU^$_+O|?~C>F0+9Ks3D7!#o0c|%r! z<^|ZzfxOhC7|J9t^>PK;%8C~7U^#289!=L0w#GeUQ=H4BdL!@ZE!nB_peJS{7nVrN z3X2l>fDQ~LzsNUtDvUIYJOT}C_h+WQoecsTrK%W4(1&5We0(2hO{oYa6V-8)SyPay zd!Sk$ptuLIx}%C_;mX6Wbx0W>L~}n@u=fgB~K$*XDqsqH496&z_Y>`(~`W9#g9{Bl?bSdbbZOJ8`LF2`s-Mmu_G*O1GriDP-1XUCLus2wxUlodkS zL(zLY?r4zv!qM0p3_B#H1__Bi8Q+$j8Tx7;l&BRGtD&=}2W4m{i)y;0I8{=bTG*3Z zfI;PngLPIrl#rwv(G>E~Xv}AWn&A>5@US;58r)@vJg*sED_5y1v}QtM)zQM!mUJ-? zj6a))L|ygh2dkTyqVOppw{b=yeROzYP*%^MF&X4T>?n7SGDb%Sl6M|{5^j}i?1XC` z{}7CvD8q2X-=Y(BQc7P)*kYDlHUXh*#oI+@M*MpZAXHE_1i^rGoPwF5td7048AU8k>3FCDd= zOGfAJhbrjS`vZt8lzn)|tr{{7Vf z?Vl9hE(~FW8g#V}y|&-v0?D<0b2XFUMl2F{M^Th*s>4DPD8 zqL4G6`zEL*K39Q;DgRro8>@>}*H~YJpn2tf{C3+p)L&DJ8R@0EwL&O2yfk#**VA!> zSzE>DP-z6QhvjD<1^W0s3B%Mu204tUI^$_fUgJ{eys>9X)^gyYJ#=Yot}82H7g>(7 z8AQzJCG%3{%V&SF0b_U7pM7JU&N-yNqNeJ6x93l*y!&tW?^iZoOg_+%b~)>t{Ymwm zS))8)_wCSmpoOhx8o6g@cd8`37A{flD6kE9R+Og4#)sJ|Ct8K{u_WmtdZ!waD7K1e zsl_Od!}lUOOHPcoq^t99(W5IHg;b?agQ4+L9fT$FLgT!bf)dTHBnMKgW*(AAWTzp@ zm9dlaYw1tE7iX}2GUbx?Uz}YDC+>PUIaE-m^mCjxeB8$W&gxOFF{?;pwq-t?`E_H3 z=N+)DhT(QXH@`bH_?P<0rHAU~CRd#I9H!0$ z(?Akc%r??4)|}(%M!!EtzQ+@p})p;)cGaLz6~d}-TU{|db$FsUw6 z^?EwebZ@^xw|b^0&L&q(;}bzHG`l#9U!fjZhwFGS zyhgex3EDpa+>EE9gpAum00$RX=;Ns;hak{N5J|hrnNL%w?^6=)^1yD9N5Q&K%ukz` zC)_5H!v&h{%u!X$f%rq>>j98#`2*oj+ZA9}TwrZd`}wbgk4e~>hG*5xOc9N(T5KVw zi4FoPe>gEs-EsEeH_MULYD5Qwi)OR6r z=YoYXc+fW8@x2VHPEE|d5gSr*QY#Z;7zj`&7yYyJfk^iVads@Cqw%(reaE4a#4Djixm0gIzjJ3}0HWPpic=B~o$ z)Az4K&l;uV4Q1f!{t+qf$7{+#cf-dWkc3}merBdS(ge-bBYoKCrYe0y*j;q{F3V`<|68x&LNOv5*3|9~V%UBF}Cw7}I4Fh!ZXR z`FLAWqCm9!T?-mpooe)KJ*fASwLN1%SejkkI2r_9YSIR>)cnXnd_-wl1l;p1gy~g> z@sC|Cbn*6(_m>@#ounhHeMJKclG#Uzh`sYjhRK&1wy;K>l9}*8EW{B z1yhy;a7TFIg`o;@k<>?gduAj@P^s>334_3ONT1cFcra=OB5|C^GxAm`G0AxidyEEU zI0e1zZD8OHfkXQCVbtnUB3vB_ZuX=%kQwchc%9zk`-LGjU-UZL8(F#Vg5FZn0gS=q0`OE|L)A{-GmK+^S8ToLq8-{6UDJLCTUo7l zn{4@?G7WDe4beOl&Nc$q*~R1!-+L96-L}ij6g3O}Y8{ppQElbA;CzltUvRpV6CMy( z5hg%jWtr-7ejVV*3Tb>UY?3~I%p)jn&Ez)>Gn&GE#N`izjPQZf<4phf6?&xU)E-}( z2Yt*sR*(eRrwp3WS=IY-3AH15^OXT9W?V_>Sjzb?Nrw%@d!b(ftKFBLn|zODr>xh0 zxUFS_=TC=xe!@6!k{t$g)!vn8JpV=w9`E3}2SnVc`cnA6`$oj!ZsMIGs{m&9(+C4$s z_`4nCxa3gIIqGw?RXgzpMLC_?hFaBCDm+XGja5!-nI&c5k=^ykXO>=Dj}-jOejV2( z=yp}JVsgF_8Zz#bs2{W*=?0M25*FSfdlxh4iHY9xY1JX^tbz%~ZS*)*fC_5y^tvR~ z9tLNkD6gcM%mld}nY^$!Y=0TXtIA^d9U_0iXsj@DzPv=B&~^VRK6$k+ug=n%4XNI7 z5}v3nc0eUzJbD!AYiwsvHu8#G4%GFmZSNrDtQ<;KWStx{9^vS(38SRr|6;WLcu8agP{>kd)>T8S)r@u%|r11<_ zB}BXV99`?Pg?e(+cQ5cZWK;MH&YCgmcNGgRprx{*7Y%LQbd%M-6}dHL$y*Gk$Lm@$ zl^jbVb;?wXim|(C9HklXeV%l~kbA%wal9O{&An`CAbF0L9{c-gC%PC6g{TBo`IKRm zzrzM$Woy`6O8muB#bEh(*FOe9KOX_`!LAQ7>c7R zzWSxd?wXc|Q*#Up*khXCyhueaZ1hQ{E5UFFVbshyvDYS=rpGHfefoKWDK!_ z=un#jJ-=>kYA2LwG&|Z+JAn7IzPJ$b`UQ&ete~_1TU{cb|E%@HbHkbfTitn)dpb zv*f5culrmK6Wb|rGPjcsEO8|IzRyS@7?wRRnj!rJGX-7s$HE_EKR7ss=^r;0#K)f1 zM9?%r+^>W>w{=&7TM)RKG7w>d4&KW_#Y2c<~2<#yB}X>pK5yhd71xPlbba8 zd*AA;*;O%pKi^)aGi^0{&VI0&X1P-Vhr**;=lhKnZO2#X1u&QYYG^+YgYkpYI;H+n zoJbdDO05j+$GDKcc$Y-rame+w&0S?0!A3E^8co|eN?OY(V+(?EDtLt5o{lVELIBL= zp^qa}+FG!TmRN0cS*{9==VZcl>K z7k?UFGU_jK-tTu~BA>Ucl)htfGnWrOajv3UD#L+7KgmNgau9(pWdC&2lOVtA)k$~E2&Q)(s=^F8?!Op<~+neo>&tjOGq$nB{JoP zI1AS;DGjkssbQ9WI$Do$wvEqS1ix;Y?l0Ie5CZ0ltNR5jJW$X&b}%2(fDvYZLOq(? zsn6K$getWYRlXG&@wXJUsKh{*ZW-wQ?vBb6nAIx*BSrV_ z>;BLr0{X=t6b^GQp&Q=A6h&sY(9AnY3@$LaIBZ99*YBVK`qS-yOK@bX_35y*?%>jPt{$yC!M}_2Fii1L%?QrgizREi3LW`;{SXF}4 z089aOOFitQkZ#4R|DeN?rFEV1xxwPV*z9N>_?5sVnf#JS>7^)I13n>bWq%*jtGc39 zkVF%rP`f`ap^rCjWhsa2$oElSF3(tNI-6=yMwUnRE?ug<9;x?f!}u3LccPA0mmYm) z2elZhP0<(Y1qxY#Pn)sH%`Y?M4Vfhw1mjbww1t|k*NQ;3;jtf{+qi`G{znuouwm-j zs4gB|LK@T5;F9uc2jMm}{ITYd(ToZ7VDAh7j3bK5PWlZZa05=D`eXXG2isx5)1f>H z(9k}G6K09ZvzT^6LW^nCh6+8ml{Ew1;u(Lk**;;Y#7@8AAeRZ!F$b%Tz53A?f7Wmo zZ+cp+t!4GF{fUrBgXE#)BkkB!EJZkS@vacn2Dr#>l_!(Ic#@put$(rX_MaUFj>4W@ zDLNGRu>ljUOj&H4P+~>SMod$Rs!JyjVxjn=kZANaL)s`prYUidMTHA(>|rQhm8`B$ zdI9c3tER8Ru*}1(gq^dE*%2eeOoCEQskCrI zC2%$evIhk<7uEHsV>e5`wPv#5v^g>*nOEfExJh%dyHvpW-4Lh^F>P+10HU_r3mJU_ z(;`f-sk;m=(hxtMipwdLW05iV!Ww}A5Q$%sx9dLlBUT;G7tC$EcbrnnkU~Aqj^ze$ zA2w!0y_z^)UN}Vi87VzUv4owvHP_~GRfck(-qi*vfxvi%uEB^F~f8tkF+rn3{j^vyB+v9l>|m? zi{+K2{nBkSLAaVRDo)=4+SlV^cb2ghZ#Aj-7EO&i`6}ZZkzeZT?YhP`9(_?whC)4t zpq2?qNI?g4Wt<)Zxn^<^sz%d)z%ey71{$a8)5^nmndez8;nHqkaF+6HzN=bqSNnj(8q}!N~5c+rzn$RUQ%^StR2ApmR;z z@E7RCu9$cr#AN9*_yazsW9p1a2zg9l`R-*k0^bA!(?%zUTjLo3P$(aTXFmz<3{9z< z-IDHq7@$x9*%L*%U(mz3Ze`qeK>EDNS)@B3aOKG{R(!gufjAvMbz@Um#&#?097hrm zE1J1)aZoq@!{nkw&o|gMFW4M;hZs7TN$%@O;q*|%W$5nk(it#qb_dQ}VlY-O9YJ#f zjLrjQdE4@_Cxk?LMukdnod3a=gEoU&$5aN|GScln!xUsJCfuOlfMC78R4J&BYWAtP z-Q-14MoJKQmxVe;3B2C5fa?#;Zar?Zd#2v?_zY#wmehrKeg}37Ah3fM%|1CS?A4QR zLf%FJ)W9>=oZ3e7UH%fhPmBw~dei*m#5!obQN0PP;(v4aV~qj0O!DX zz~o)JqhO`kVJL?+C5m7W8fD_JGXXuq^~n{$f7;?dP_&(t>HjN-c5!8je+f-- zhO?7TqgvF#;9utn@Un55C|5_f>yp+E#Ek1SLX7+MxUf=;lVuXA77yT8AFM0)vuCY7 z61*)}s%An@g84BKDwllBVRz^=3GjQ0J<19z@BoPY%g>8@V0({}y=Zlju73eZkr7al`xo>xS8hw4y?Qg(NF;af3`Vfi9j zX1M#nd=Woa=E52HE#m~Ts%C2u6j~df8^Ag!_vB0h_e&jhar|Wuf%GQU>SK|?B1mpJ zJxkd5jkI%oH7wm(YKa5%A6z9lr7wWZ=>MSicp{-O4vwLh;f^w^YLh4cz>QefT9(%`a`#g><%WJU+r_#8pcjDSqhQjhena_%K}z z>}q+u!;WM|t$)~wrho17l(+z>DcrEhP}?(9_fgRsNM;t+8IMvrJ&0jyP!<=YDzRNi zda~EeD_OS)i8Z7;S1*!{bnv_g_U{0hRq9&9_a^_7Q-#&I^Ao-B5Gg7bnFfwK!M~tB zaZ=;>-Wc?qxW!Rs3ha^NdH|*7&e1EeQcxAixx98h5^jYO4GYSqhj9K1Axyai<2Uyc z0!e}gkwMx(i2hh>vKZF6N8CZDTS0m!O5xvrGHkt{(OL?CfLHhQtU%w6eJy2~tG+?j z&P{VP4R6cWL2ae!_Kh>w+q>P&=a#X#7kNl%S0*5YZ?w^S zm|I4fN?Hc^iYDc(Qn~rfD&pOQ`!THf1j0*L?9JlM{*8X`s9+>?++64P8K7tN?8-vs zQlaN=dWdFvz%1K4G0?P5lk;Ic#7nZemX^G9;VWetl7T9dLAA8ZtGvkPW9WQSo3&|F zqR?v^2Nc)%oqzK8)MAgpaoo+vjo59v&$%7?z&c%!qG!-80anXAqKQ|>#=~ee}|;-@(b;+ zfXY=Bx`WC$A$)+_A-$$1D%;RMKyX~9vJZX@f0hF|htm`LLPVy|NC#xS=T2F%Uf6_c zMBYYb8QTmZ&=-TE)N!-sLVY_qO*5N{el#hM+KPg}h(2nm=n_8|0;)I{r$YIEcoO z)7M;t4{g_zId`qNsm?R@x=tBG@l@xPux9cB2>+WZ2K(qr(TL&GwFEaB*mNB+pzn`P zm4wTv>3em1r6>|cMtNcqNeAiB0x@UC%B(I_Lj>mhe~ejBFaj4q<&l$Uj)BRE@}aOF)#oM@K18^MV?_Vzk>XWa zlK;(O@m6{Z_K-V5ar8w8nQ)GXTH_vFZy^?GK~ac|=ZU`8OAyt`8NG^;j-`k7NjODY z7Xbw8C$JPIC+5ut7)$vbAiZUlVz#|Q4R}M$OQ08W?YIhy9V0+i@H5kPKPTn;2ucsG zV#2&|$_-yo)9(3oAu^A-j{N~>zSKG3N(pfxPl293cbH470&k$fsP!He2MwMduzRm~ zH4~0-@`m$Y$-~}mdFnNgCR2H8l{GWM6Uln!){i8~6~RYVR&-qhYs8$GgaJi!CZri} z96B8eb%qBBWPLZ6D~T0BocoDhy22lP{0YK&Mgyw3*DOl3r&Iy55g=FJ1hMh=eP-W|6Ld;AXh;#Iom0-SYyE$qCw@>K5%n!d#$5 zUk(P_Qiv(m1$eM~`?E&XZXzmoLuqE@!4%ILD)sSk??&cLCkB32!Rg)k7Zg_K+FB#@ zy$#xj!zj$Jfk8-vD8T`U$-*K+CbwO1K3MS{eBJCa=H(ojV#YTcpI2%Czr99)R zeUL3uKTOyY0-HkI!o(8&#Jz=i8k1MrDDcf&7ugr`UHDb`YuAMD7O^D`_7tl z;lxG#XW5aTS;0*V;rF-UN%vd&wyayy^bKiC-5p?uH&Fix0Rl%B%!Sck-35cUXO_TA zbZ{U>2<@&c=%E8*Q=}o3(uCz*>*gq$?!b9I^$|Po9y+H!&tpDe$K9)nlNsu< zmpI^(9bphN2|@Rh7Q^tkJA0PCz)I$NG|b_>9NOv(K_3n8+i$4}O?BK&a4wjKlrx6i z5a6%TpUv(JH(FA#av2e8JKf$%3^z?O!}GJjLvqV@=}$ z$(Fu|)J^g-KB7yCGPp9957-ByV!+pegYY4CCw?FA6>JbpRfjc~Wnp6&ljXtR4uLNu zA-W`n>Dp{sZqmarb5v%YAi8WltHb9#=3yr0dEqgt4bX`4$|W93iLl$iwz^*eiuC6i zr=86Gy^+Q3x}Kvagk%Y5a`7ZX9jps=G)ROG=CuoLdL=+^^Y|+hkxNSPWve&8FeSnK z6~M$`WHg_GUrLSa(x&~;rU)DA2%e_^P3(S`^5`%9+~7KPf%P2p6wB*pi|XMms#p53xQETF9nGH#=r7 zO$w3%2_Qh_NY_=aQ%09Fp&nmF%LG!ZSa_*p+T)d}Kc9)B(Ac?;w&<-Ff3 zKE*k`JphO)Dh+z{Mawcvkt087BbP(Ku_)g3R+)8b5=dgh+zTEH{%%e5u@u(+9B10@ zJCK;HZShl3ofLK`=2@c#GC^y@rsdheYt-@~#7T;4BQ1IwX`Ixf_(x>|`* zXk!LP*#WjBkFMG=NPCwHk@B4f0k|nkw6Z)^;K?7;ocCe9=Klnh&CvWgWt*BxF#DMb zdT6Skao6I|u(PKZC_{_lVH=cEUG*iINbi!_(_Hc55UF#UTK_`rF7uQphPQbcSQ!UM zib=Y4TZ#RB#Lp>IXgK3HUylvIAou#e!L;BZ@Ju*rDd;qviEkoHYX2?n75yY;;h9Me zAS<$qXDN-@jt2JoDJiGbWfy4 zT_#5;($aI1%t?NzT1>5q8!Jd7(wy}9)_6k!U&uhV`rgbl8(dtHo9xIH27Wee-CBg z=By&pI$hkj#oOJP_!=hJZmrEJb?V4`H%oUC&2;?wOZ7d=ds-?SZ@Hd*lD1k|JQq~- zc2CorD3I&ZU7L4(8<8egL|rkS?l~*!1Tb=4%m%BS0<{>*{T|J>+44@qAiNWWvP1i` z*Q`FlwEfb-Pzkz`+Ch8-w+`_OohEfT-uJu=WedrtYn+e0r|*@-3?^wZGy6Eb+j(|T zhA4BUL@cpvoqaHviA6dOa~7p);pj$5;ejDyP{4II&P}yIpez1x8lfZ7^hl zjgVp|x~q3@?E>ZOlHu(bTxNRtLPM*2MUwDJoKZsGzg8J8gAtRF3L^c!SF-JO{i^GZ zTg=nPKgq0P&UhEl78WJvj*nI85nX7bXRNjg(C=w`3pHEAD3fpgn>xD3 z^X8qR_wR$rUmMw6Bc_?9JYtR!r8&PT9jp)(5f2eYJ1K*;HW3XG*yt8`tx%~;2Q@mJ za@DGnh*yO2(kVGfr|HX{cZGy|^5gT)j*a=>pn?aIaRgNTomENDrUeKW9p@y zaO1yQgZiLXc`;PwHK)wDAeU-OkvlvLgUb)%-um~HTmFis zRdwcMFSTje?#-cFU+qhRkSPAVSCn!el6&8SsrbbA>7<}Ev#~-9Le!;FHnrEEPsH4>y$A7CHEm#}Mw}>e36la7e zlQjayR6nVk&VZ46z5Rq0jAk39<0y*iaLF4iJR8ozb<^uZpl%c{}VsNfK z1n}4_lmsP8ePU4S&ykw;;4{ZEW{H;4j4mt-p~TEBpAtk{6K5NnvM5B_VoY4NCBCwh zKz^=jYl#T8WK#pMi|4ui<37)bV;LRS*95~^)!sBn1~JmHQ7)arZImm?+~77*FAuI= zhHbI1h~@jlDt>Jv5ZJQr$sNQ9XiDj?WDM7Xl3(|v6-R-v+{)OZ>ux520&NRt z(&XP_LB-T(Q+UZ{OWcL$U7Ux_TadB%q}C!Hs%}`xgAZH^dzyrs%Od+%JK^T&Jck9< zS=wBR1Ha+z=X~fg@oab^kqD77SJw;sPOgIB$`Q{~h~&y{4MyJ~xbS;jgOs=%l?fgc z;TEzesFtgOyqsLXwWn0?-3Vqk>3`GtpS8S_6z(5rk9qz}84@njRbtmOpB z{SdY9ID^2WnolX=AB9{?#r0yRYXzwMU2<*nyCUp?2LRc!$qy>wmjFJ^u95^eh5byy z@yT3zGeBX{$DW;PL=3L^)4NT&$B8UqXCiV=j7+1n%6B_OB`Om#)=a5U=j=|iEX76iCwbtX)8C^0%GXLzEVuqR8>OviDm0<@J zob)^-VKMjJIP_M)2bc zV&CfMK@9Ub&U-I-ot=1WMVDuZvXS#$$ky zY6j#Ikf|%8bQ{bD3<87zViMNunD2$TY#y#292Y~Oiny1ciAn=_QKNp`a;Cm6kD7LZ zyLP|;AF$e9eJvVVU>a9(8>f@m-gn3%nrm2wOVFwUE#P$4H)cC(Lz)=_l%mvYRy!Tk zcwiM5cp(jqe<$gcwyY{loQq6hImEfw1W5~Ds8lcsyW!X-)YckOSKoWF2|xXiN|q*O zBMnNF)RMkvb`5ZEPbJ_A|Ma5{b27)yOr}8vm+CunWN<$n9ySvE03o4z&Bq>?hUz$| z##jZ)*SCC94ygF{jkezWoNiyyixqi65j?@vx4F{XomcZV3nuj`sVGbSG zkFJWkT#YLK9$-Q8|8T7sliZ|ms*RT-QM9%S_ko(k`D`nxoBo@C><1!FGtqO4OwdQ} z87r3zlsD2_KF3rO`mczz+*5jTgg~DsCj{Yh*mmn+gT~$HYq@gS5dB0)MjX5GI5hDj zv*7+R>O(au&@0_uBq>yh3y1#@%b>iPZ!YD4xdN-oK(F1scS#9Xqun{$J7w+51_X-( z>T|%hY48jzS5LnrXE|n>Go5-6`ID82rgApGEp@$Cqlb>#-R7iCn07Ctuz}MjVAaKW z)<~2vGdljmuuwPFwrmjD?h!EqCo`A1|ISiIq%QGhzACBZGdiyuefWFLZJhUYyW1m_ zdp%PtY&NR$f8Cj{p8^TSeLkJ$k5_gZ1&k38Etk#r92v7foJ0a*Ae~NlMVk_D%4Q7i zJ24=Y+>Fw&SSEGxDF>E3 zwt=^h9VXM8oShGSJyb8-hGldd4l;^Cd;#3%s9yxRq)J)zz2h@;{6|)ujYZ!D6ZxWR z^g9xF0Z$B=MfLTrvyFjf)B1*66#+jdiD!+mpd<&mGit)>D-FqB+Ire{?Clcf0NA zx71sagG?R}a0zx4(}ioe5K&6d2-17L7}3)9Pq&siw%@ku8p!_8T;Q#`Yam)-5nlTb z%45NRMr!;cie1Syn9jixq~I4Rv>;hlVgd2-qzF!1whUZ9fBm^!?uX;7JV>Hn3hzNm za`eS0LSp?5)$Z9YoZF~&rgpwllz zGbbFO&sc7+rC^wLE8a=hH~~K`g3&oK*-L+UUY(_?LOqR)t*N0}}%5WyAh?qh{ z2sK3Uw}hIh0uQFZhoF}GF%;P|b*zcyQQWEk7H6w26{TQt2(n3r85Yc&N7)mq7tl5( z1SGSNKsbEin54oXFL3z-#G;D;_AyNcKzr7cp^Yaz`>p@oNl3Dc z3St9Qom-=Sv0g1<5i(Ka;K8YQbuJRt9v2)C-xFk0RlUT1()TCt;-ZxO!IoZQ5Ml!@ zEXn`onS<>Oit6=J8lvVlj3@af&}}PoWgcY~`*~SWa}2f>IA0*|r0$+z)tI_~CW%gX z)%#s>JR?NEKrG8!TXjtz!v8Pn$w`&>s6ZFGv##jbZXNCHG$raxJl5FHx|RfxYj`xk zNBiXnY9pWB3b0t&g-dE@w%~F6VsviTB{RY2v&c>J!;uT*L{tdsW#6e#^@i0#`|FgE zmR=&yMi1yv3PMs}SxmEZy4`2WuNyNu(6(YH7>bidDv$@ahdI-l+eHS00OS;N>d)MuLlU9Xw^3-My`GriP^su;TgO~4O5(VS#eDz7|gTeco9 zb30Fw^c>I*uxwEv|Mxje0X+VWD}H}M>ji&p=cFd|GTM`<^ksC;CyJijB?zINNE~{T`gu>}<1}%~ z4kCdo((48tujK`{e#WQ-Z_HE;In&tzI%SHj!m{$gUK%<)Lng1KXp_FF+ipdY?cN2| zBI}I_^d9eR%hDwjGuKTmqF+lmWFrpy2;rd=FNG16w_ux&qb!ff?;K?_ z$*lJP}(5Z`t+yMC0{I+Slw>Oh}d)qd!P z%DM1r2A1{?qJc~J7uH@@+W-DzaL~9HDLxzvbB>sL!pitFF2k^w7|D9s8f=V~fi~iA zUp*lw7Vr8b(ARp)yYp$94uVWwSK3nwEb43Vx2a~hsp$|k%sxy>-~-tx@md|OIUYbO zycvs3k3w^QGz0MN>n#u25+7k(?pjZT2&nBJ!?b+u9x<_1G21ock*H&Mgj4Wg_pz~? zM?xKF-ZOS^epn6uR{rgdcBybfos=_k zM*8)pLwH;(Bx)vz-S4q=sf>1Mn}#x)GKqd!mn14CQ~ljE&)>A)3EtvKzqWT$fCy{! z&pdh5_e2rRCc_;8v(F!#^bvJ}q7J|Zf%TcS{u~)xepzg&O?87HH#wMwEw{q$;FlEk z|ED%2SY;Q*Ml zyn}4N{A?ef^m?e`Q#Q#}{X-N!{&HqZgH4ts3Z_brFMi?hWpWF8$fZjxEaVY#RdjyC zw^6~$zbr7+!jav%HFakFh9Q&ZV!Nll$+fI6$SJlDb^sQ8(8p1t`vYm{|6xH0~K#U__v%L_l*Nlt&Kq21}-l@Nb>Mk}#!v}xPAFnxrw zE&Kx9JpESMsX*f4japBJt2xCa=stcU0}u6no=AXGou6}=!!##N)XvDMfkw4*1HbEL z_93yeT1y_y>1(7gYKf9{`g8HOq70nAZV1y)q64>H^n=JmJN%FRnKQ(}v74eJk~Mbu z7Mr$w2cIXWcO;%?)9X*+b^2C>iRX!_FZ(NNC(CAu-I52BcXaIvD5joM^2ZHSfN~^d z%Z9y9_M}t2AW?)^HJ6wTh96XcqJ!_765=%}oSwuFt*&S4j&LP0krt_(X4DiM?8nn$ z{WFpr2vQ9a5SNuOlCVL$-$d2EE$scpho?)s3>w5HuW}(Dev9dPZ=ug#4Bg=~JzQO) zR6c9_>>g!@WANlz%v9|mFN?wzYK?~G=F4dBe|?&ud^$N`zVkss{1hoexfhE^q7}cE z^j*Kw`i6SPqk)zQ54Fq$ z$TD@BQH7XI2B6fT$MM!6z?Q&BkYTUyAV3s|M>@^1tP=NX|5O42p0c!iIO%p*RsAXe8h3o-cQ(q0@49QK$48y=tA1N8 z*T((yGuB85wdtlCS;d({x6qn&Rdv-_V0-g!>C#oAWrT<`oq`XSNs`c{5g{^bfYq#x zw+I6W{EYxPdeeV!Qcju>=#JuN5TW-dYLZ@Yb(e{#28 zF{?RaV`h!ElEbSgT~yWm>=1j{ZeDU>b4;8b!l28OTH1CQ8@=FngK#G7Aq-)#8qj5h z3u4=cql;n)4#A`cubM{x2m5icBKir5a5W=Hgr7=RC61CUF@^OMh__uNwBstMliKrs z2DtyI*M~0TtTwDe zAd#sB<=sH;*(y>p0qVKU=S)(tG2LicsA{-rbD95odI%;5nw;d!&!$0VLf=23C*`W0 zlI%J^$zgeJ+ZNSWJyxwA%Kb4U22D9FEk~|6NITKx>1&`vUHV5&5i5nUlA#)qi52Kx z{|Prml|DUu7v_X?ppWD7ShHC9-D;WUlWt5feZ-C7kaJhlKup@!aKKz`i;=6>*}Xo3 zg#TB1BH^WxDXE$ z!MS0gZT~o~bKdRgdMHz^Ac8$WC6_c4ZIiPm7u=^85ykC}MRMRmf`U zFfgMO^bPBl83xf3Y^(CK^dGZ@6+? zqK0&bW^Bi$)=Fu#=Uqn{rb+&5+I`j@d$JpoE;Mf?KRfg_^JnpBf`wiF-*w?qvlZbN zDjCLrOM^hu&*ShmrKab4t-UZOLe3Fn?tQv0F;sjH{H{DCX(4txfV zEkRhZyE7HgWxT7)Zf!>(QA{OS_E_MmA|YR&WdUtDE&tR1n8E|VDo&zD58f%`u;3zR z%g_huHTPOwsWN~kcZL=Hb8}S=0s#I%_InQN?PAT`1{iI8V`D-icqh=Oe(dxnJGbO?H%LuqTgX3R@m*3m4)r|f zC5zj{okG$&+A_ueIc3Lxot9H`PF8WmTJA&KXc>b+cccy^&AhZh^<^w5I+&qK7|r(^ zF|O?@j`nM9+YI3O(vS;%0}(5bjg=XIHr)fcgGhDaRkx zx?7U;9S`y(ONg4?-^Ev;R-}~p=H+Z5b}jtLYioV)@1@Cea^2krIBNKxT4ZXj?k?$f zb^K(|u^Ntkk*3A*R_Kp|NgF8S

QTQo+|HZ@ByG_EXr==mhtmuge;4Xri(alK&~ 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

K@wriSq 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%0D!~#{S_Z~(#1(G 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 B3V{Fs diff --git a/pass-to-make-check.patch b/pass-to-make-check.patch deleted file mode 100644 index 3a3761e..0000000 --- a/pass-to-make-check.patch +++ /dev/null @@ -1,164 +0,0 @@ -From d597742733befe23034a87afad7d18ee36d01ceb Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:49:06 -0400 -Subject: [PATCH 18/28] pass to make check. - -With this patch, when running make check command, qemu passes to -compile. - -Signed-off-by: lixianglai ---- - hw/loongarch/apic.c | 4 ++-- - hw/loongarch/ioapic.c | 4 ++-- - hw/loongarch/iocsr.c | 20 ++++++++++++++++++-- - hw/loongarch/ipi.c | 4 ++-- - hw/loongarch/larch_3a.c | 3 --- - target/loongarch64/machine.c | 7 +++++++ - 6 files changed, 31 insertions(+), 11 deletions(-) - -diff --git a/hw/loongarch/apic.c b/hw/loongarch/apic.c -index d6ba2a2ce..67994d201 100644 ---- a/hw/loongarch/apic.c -+++ b/hw/loongarch/apic.c -@@ -64,7 +64,7 @@ static int ext_irq_pre_save(void *opaque) - struct kvm_loongarch_ls3a_extirq_state *kstate; - int ret, length, i, vcpuid; - #endif -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - #ifdef CONFIG_KVM -@@ -112,7 +112,7 @@ static int ext_irq_post_load(void *opaque, int version) - struct kvm_loongarch_ls3a_extirq_state *kstate; - int ret, length, i, vcpuid; - #endif -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - #ifdef CONFIG_KVM -diff --git a/hw/loongarch/ioapic.c b/hw/loongarch/ioapic.c -index 3de0ed88d..60abff855 100644 ---- a/hw/loongarch/ioapic.c -+++ b/hw/loongarch/ioapic.c -@@ -253,7 +253,7 @@ static int kvm_ls7a_pre_save(void *opaque) - struct ls7a_ioapic_state *state; - int ret, i, length; - -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - -@@ -297,7 +297,7 @@ static int kvm_ls7a_post_load(void *opaque, int version) - struct ls7a_ioapic_state *state; - int ret, i, length; - -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct ls7a_ioapic_state); -diff --git a/hw/loongarch/iocsr.c b/hw/loongarch/iocsr.c -index 60daafd6e..13d356d80 100644 ---- a/hw/loongarch/iocsr.c -+++ b/hw/loongarch/iocsr.c -@@ -95,6 +95,11 @@ static int kvm_iocsr_pre_save(void *opaque) - IOCSRState *s = opaque; - struct kvm_iocsr_entry entry; - int i = 0; -+ -+ if ((!kvm_enabled())) { -+ return 0; -+ } -+ - for (i = 0; i < IOCSR_MAX; i++) { - entry.addr = iocsr_array[i]; - kvm_vm_ioctl(kvm_state, KVM_LOONGARCH_GET_IOCSR, &entry); -@@ -172,8 +177,19 @@ static void iocsr_instance_init(Object *obj) - { - IOCSRState *s = IOCSR(obj); - int i; -- LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -- LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ LoongarchMachineState *lsms; -+ LoongarchMachineClass *lsmc; -+ Object *machine = qdev_get_machine(); -+ ObjectClass *mc = object_get_class(machine); -+ -+ -+ /* 'lams' should be initialized */ -+ if (!strcmp(MACHINE_CLASS(mc)->name, "none")) { -+ return; -+ } -+ -+ lsms = LoongarchMACHINE(machine); -+ lsmc = LoongarchMACHINE_GET_CLASS(lsms); - - init_vendor_cpuname((uint64_t *)&iocsr_init.iocsr_val[IOCSR_VENDOR], - (uint64_t *)&iocsr_init.iocsr_val[IOCSR_CPUNAME], -diff --git a/hw/loongarch/ipi.c b/hw/loongarch/ipi.c -index ade182abc..59186f1de 100644 ---- a/hw/loongarch/ipi.c -+++ b/hw/loongarch/ipi.c -@@ -25,7 +25,7 @@ static int gipi_pre_save(void *opaque) - int ret, i, j, length; - #endif - -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - -@@ -67,7 +67,7 @@ static int gipi_post_load(void *opaque, int version) - int ret, i, j, length; - #endif - -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 6eaa53d74..f83bd3750 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -1435,9 +1435,6 @@ static void ls3a5k_bios_init(LoongarchMachineState *lsms, - - if (kernel_filename) { - lsms->reset_info[0]->vector = load_kernel(); -- } else { -- error_report("Please specify at lease one of -bios and -kernel"); -- exit(1); - } - } - } -diff --git a/target/loongarch64/machine.c b/target/loongarch64/machine.c -index b69bca6a9..dea6a7034 100644 ---- a/target/loongarch64/machine.c -+++ b/target/loongarch64/machine.c -@@ -15,6 +15,10 @@ static int cpu_post_load(void *opaque, int version_id) - CPULOONGARCHState *env = &cpu->env; - int r = 0; - -+ if (!kvm_enabled()) { -+ return 0; -+ } -+ - #ifdef CONFIG_KVM - struct kvm_loongarch_vcpu_state vcpu_state; - int i; -@@ -48,6 +52,9 @@ static int cpu_pre_save(void *opaque) - LOONGARCHCPU *cpu = opaque; - struct kvm_loongarch_vcpu_state vcpu_state; - int i, r = 0; -+ if (!kvm_enabled()) { -+ return 0; -+ } - - r = kvm_vcpu_ioctl(CPU(cpu), KVM_LARCH_GET_VCPU_STATE, &vcpu_state); - if (r < 0) { --- -2.43.5 - diff --git a/qemu-kvm.spec b/qemu-kvm.spec index 08304dd..1a2b05a 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -1,4 +1,3 @@ -%define anolis_release .0.2 %global SLOF_gittagdate 20191022 %global SLOF_gittagcommit 899d9883 @@ -11,10 +10,6 @@ %global have_kvm_setup 0 %global have_memlock_limits 0 -%global user_static 0 -%ifarch x86_64 -%global user_static 1 -%endif # Release candidate version tracking @@ -59,11 +54,7 @@ %ifarch aarch64 %global kvm_target aarch64 %endif -%ifarch loongarch64 - %global kvm_target loongarch64 - %global have_spice 1 - %global have_usbredir 1 -%endif + #Versions of various parts: %global requires_all_modules \ @@ -92,13 +83,13 @@ Obsoletes: %1-rhev <= %{epoch}:%{version}-%{release} Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm Version: 6.2.0 -Release: 52%{?rcrel}%{anolis_release}%{?dist} +Release: 53%{?rcrel}%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 15 License: GPLv2 and GPLv2+ and CC-BY Group: Development/Tools URL: http://www.qemu.org/ -ExclusiveArch: x86_64 %{power64} aarch64 s390x loongarch64 +ExclusiveArch: x86_64 %{power64} aarch64 s390x Source0: http://wiki.qemu.org/download/qemu-6.2.0.tar.xz @@ -124,15 +115,13 @@ Source30: kvm-s390x.conf Source31: kvm-x86.conf Source32: qemu-pr-helper.service Source33: qemu-pr-helper.socket -Source34: 81-kvm-anolis.rules +Source34: 81-kvm-rhel.rules Source35: udev-kvm-check.c Source36: README.tests Source37: tests_data_acpi_pc_SSDT.dimmpxm Source38: tests_data_acpi_q35_FACP.slic Source39: tests_data_acpi_q35_SSDT.dimmpxm Source40: tests_data_acpi_virt_SSDT.memhp -Source41: loongarch_bios.bin -Source42: loongarch_vars.bin Patch0001: 0001-redhat-Adding-slirp-to-the-exploded-tree.patch Patch0005: 0005-Initial-redhat-build.patch @@ -890,106 +879,12 @@ Patch358: kvm-nbd-server-CVE-2024-7409-Drop-non-negotiating-client.patch Patch359: kvm-nbd-server-CVE-2024-7409-Close-stray-clients-at-serv.patch # For RHEL-50854 - vnc: increase max display size to 4K Patch360: kvm-vnc-increase-max-display-size.patch - -Patch1000: kvm-virtiofsd-Adjust-limit-for-minor-version.patch - -Patch1001: 0001-Add-Acpi-support.patch -Patch1002: 0002-Support-rtc.patch -Patch1003: 0003-Add-loongarch-machine.patch -Patch1004: 0004-Add-target-loongarch64.patch -Patch1005: 0005-Add-linux-headers-and-linux-user.patch -Patch1006: 0006-Add-disas-gdb.patch -Patch1007: 0007-Modify-kvm-cpu-vga-qapi.patch -Patch1008: 0008-Modify-compile-script.patch -Patch1009: 0009-Add-loongarch64-rh-devices.mak.patch -Patch1010: Modify-smbios-option-lack-and-Modify-the-maximum-num.patch -Patch1011: rename-kvm_msr_buf-with-kvm_csr_buf.patch -Patch1012: code-cleanup-for-loongarch-kvm.patch -Patch1013: Support-TPM.patch -Patch1014: kvm-csr-save-and-restore-optimization.patch -Patch1015: address-space-code-cleanup-on-7A-virt-machine.patch -Patch1016: Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch -Patch1017: Support-vfio-config.patch -Patch1018: pass-to-make-check.patch -Patch1019: fixup-can-t-find-cpu-type.patch -Patch1020: fix-smbios-type4-info-for-numa-support.patch -Patch1021: Fix-smp.cores-value.patch -Patch1022: Add-lbt-support-for-kvm.patch -Patch1023: Modify-the-ioctl-command-of-kvm.patch -Patch1024: Add-usb-storage-config-for-loongarch.patch -Patch1025: Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch -Patch1026: Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch -Patch1027: Fix-LoongArch-KVM-header-macros.patch -Patch1028: Fixed-the-issue-where-qemu-specifies-the-boot-order.patch - -# CSV3 feature on Hygon hardware -Patch1030: 0001-anolis-csv-i386-add-CSV-context.patch -Patch1031: 0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch -Patch1032: 0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch -Patch1033: 0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch -Patch1034: 0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch -Patch1035: 0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch -Patch1036: 0007-anolis-target-i386-csv-load-initial-image-to-private.patch -Patch1037: 0008-anolis-vga-force-full-update-for-CSV-guest.patch -Patch1038: 1038-doc-update-AMD-SEV-to-include-Live-migration-flow.patch -Patch1039: 1039-migration.json-add-AMD-SEV-specific-migration-parame.patch -Patch1040: 1040-confidential-guest-support-introduce-ConfidentialGue.patch -Patch1041: 1041-target-i386-sev-provide-callback-to-setup-outgoing-c.patch -Patch1042: 1042-target-i386-sev-do-not-create-launch-context-for-an-.patch -Patch1043: 1043-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch -Patch1044: 1044-target-i386-sev-add-support-to-load-incoming-encrypt.patch -Patch1045: 1045-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch -Patch1046: 1046-migration-add-support-to-migrate-shared-regions-list.patch -Patch1047: 1047-migration-ram-add-support-to-send-encrypted-pages.patch -Patch1048: 1048-migration-ram-Force-encrypted-status-for-flash0-flas.patch -Patch1049: 1049-migration-for-SEV-live-migration-bump-downtime-limit.patch -Patch1050: 1050-i386-kvm-Add-support-for-MSR-filtering.patch -Patch1051: 1051-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch -Patch1052: 1052-anolis-migration-ram-Force-encrypted-status-for-VGA-.patch -Patch1053: 1053-anolis-target-i386-sev-Clear-shared_regions_list-whe.patch -Patch1054: 1054-anolis-migration-ram-Fix-calculation-of-gfn-correpon.patch -Patch1055: 1055-anolis-target-i386-csv-Move-is_hygon_cpu-to-header-f.patch -Patch1056: 1056-anolis-target-i386-csv-Read-cert-chain-from-file-whe.patch -Patch1057: 1057-anolis-target-i386-csv-add-support-to-queue-the-outg.patch -Patch1058: 1058-anolis-target-i386-csv-add-support-to-encrypt-the-ou.patch -Patch1059: 1059-anolis-target-i386-csv-add-support-to-queue-the-inco.patch -Patch1060: 1060-anolis-target-i386-csv-add-support-to-load-incoming-.patch -Patch1061: 1061-anolis-migration-ram-Accelerate-the-transmission-of-.patch -Patch1062: 1062-anolis-migration-ram-Accelerate-the-loading-of-CSV-g.patch -Patch1063: 1063-anolis-target-i386-csv-Add-support-for-migrate-VMSA-.patch -Patch1064: 1064-anolis-target-i386-get-set-migrate-GHCB-state.patch -Patch1065: 1065-anolis-target-i386-kvm-Return-resettable-when-emulat.patch -Patch1066: 1066-anolis-kvm-Add-support-for-CSV2-reboot.patch -Patch1067: 1067-anolis-vfio-only-map-shared-region-for-CSV-virtual-m.patch -Patch1068: 1068-anolis-linux-headers-update-kernel-headers-to-includ.patch -Patch1069: 1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch -Patch1070: 1070-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch -Patch1071: 1071-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch -Patch1072: 1072-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch -Patch1073: 1073-anolis-target-i386-sev-Add-support-for-reuse-ASID-fo.patch -Patch1074: 1074-newfeature-support-vpsp.patch -Patch1075: 1075-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch -Patch1076: 1076-target-i386-Add-new-Hygon-Dharma-CPU-model.patch -Patch1077: 1077-target-i386-add-FSRM-to-TCG.patch -Patch1078: 1078-target-i386-add-FZRM-FSRS-FSRC.patch -Patch1079: 1079-i386-Add-new-CPU-model-SapphireRapids.patch -Patch1080: 1080-target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch -Patch1081: 1081-target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch -Patch1082: 1082-target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch -Patch1083: 1083-target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch -Patch1084: 1084-target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch -Patch1085: 1085-target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch -Patch1086: 1086-target-i386-Adjust-feature-level-according-to-FEAT_7.patch -Patch1087: 1087-target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch -Patch1088: 1088-target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch -Patch1089: 1089-target-i386-Add-new-CPU-model-GraniteRapids.patch -Patch1090: 1090-target-i386-Add-support-for-AMX-COMPLEX-in-CPUID-enu.patch -Patch1091: 1091-target-i386-Add-new-CPU-model-SierraForest.patch -Patch1092: 1092-target-i386-Export-RFDS-bit-to-guests.patch -Patch1093: 1093-target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch -Patch1094: 1094-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch -Patch1095: 1095-ebpf-replace-deprecated-bpf_program__set_socket_filt.patch -Patch1096: 1096-target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch +# For RHEL-52611 - CVE-2024-7409 virt:rhel/qemu-kvm: Denial of Service via Improper Synchronization in QEMU NBD Server During Socket Closure [rhel-8.10.z] +Patch361: kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch +# For RHEL-52611 - CVE-2024-7409 virt:rhel/qemu-kvm: Denial of Service via Improper Synchronization in QEMU NBD Server During Socket Closure [rhel-8.10.z] +Patch362: kvm-iotests-test-NBD-TLS-iothread.patch +# For RHEL-52611 - CVE-2024-7409 virt:rhel/qemu-kvm: Denial of Service via Improper Synchronization in QEMU NBD Server During Socket Closure [rhel-8.10.z] +Patch363: kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch BuildRequires: wget BuildRequires: rpm-build @@ -1099,10 +994,6 @@ BuildRequires: pkgconfig(gbm) BuildRequires: perl-Test-Harness -%if %{user_static} -BuildRequires: glibc-static pcre-static glib2-static zlib-static -%endif - Requires: qemu-kvm-core = %{epoch}:%{version}-%{release} Requires: qemu-kvm-docs = %{epoch}:%{version}-%{release} %rhev_ma_conflicts qemu-kvm @@ -1183,7 +1074,7 @@ Requires(postun): systemd-units Requires: seabios-bin >= 1.10.2-1 Requires: sgabios-bin %endif -%ifnarch aarch64 s390x loongarch64 +%ifnarch aarch64 s390x Requires: seavgabios-bin >= 1.12.0-3 Requires: ipxe-roms-qemu >= 20170123-1 %endif @@ -1315,15 +1206,6 @@ This package provides usbredir support. %endif -%if %{user_static} -%package -n qemu-user-static -Summary: QEMU user mode emulation of qemu targets static build -%description -n qemu-user-static -This package provides the user mode emulation of qemu targets built as -static binaries -%endif - - %prep %setup -q -n qemu-%{version}%{?rcstr} # Remove slirp content in scratchbuilds because it's being applyed as a patch @@ -1331,9 +1213,6 @@ rm -fr slirp mkdir slirp %autopatch -p1 -cp %{SOURCE41} ./pc-bios/ -f -cp %{SOURCE42} ./pc-bios/ -f - %global qemu_kvm_build qemu_kvm_build mkdir -p %{qemu_kvm_build} @@ -1342,9 +1221,6 @@ cp -f %{SOURCE38} tests/data/acpi/q35/FACP.slic cp -f %{SOURCE39} tests/data/acpi/q35/SSDT.dimmpxm cp -f %{SOURCE40} tests/data/acpi/virt/SSDT.memhp -%global static_builddir static_builddir -mkdir -p %{static_builddir} - %build %global buildarch %{kvm_target}-softmmu @@ -1620,25 +1496,6 @@ gcc %{SOURCE35} $RPM_OPT_FLAGS $RPM_LD_FLAGS -o udev-kvm-check popd -%if %{user_static} -pushd %{static_builddir} -# add more targets here when necessary -%define static_targets aarch64-linux-user - -../configure \ - %{disable_everything} \ - --enable-docs \ - --enable-attr \ - --enable-tcg \ - --enable-linux-user \ - --target-list=%{static_targets} \ - --static - -make -j - -popd -%endif - %install pushd %{qemu_kvm_build} %define _udevdir %(pkg-config --variable=udevdir udev) @@ -1825,8 +1682,6 @@ rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/opensbi-riscv64-virt-fw_jump.bin rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/opensbi-riscv64-generic-fw_dynamic.* rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/qemu-nsis.bmp rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/npcm7xx_bootrom.bin -rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/loongarch_bios.bin -rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/loongarch_vars.bin rm -rf ${RPM_BUILD_ROOT}%{_libdir}/qemu-kvm/ui-spice-app.so @@ -1842,11 +1697,6 @@ rm -rf ${RPM_BUILD_ROOT}%{_mandir}/man1/virtfs-proxy-helper* rm -rf ${RPM_BUILD_ROOT}%{_libdir}/qemu-kvm/hw-s390x-virtio-gpu-ccw.so %endif -%ifarch loongarch64 - install -m 0644 pc-bios/loongarch_bios.bin $RPM_BUILD_ROOT%{_datadir}/%{name}/ - install -m 0644 pc-bios/loongarch_vars.bin $RPM_BUILD_ROOT%{_datadir}/%{name}/ -%endif - %ifnarch x86_64 rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/kvmvapic.bin rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/linuxboot.bin @@ -1947,27 +1797,11 @@ rm -rf $RPM_BUILD_ROOT%{qemudocdir}/specs popd -%if %{user_static} -# Install qemu-user-static -mkdir -p $RPM_BUILD_ROOT%{_bindir}/ -pushd %{static_builddir} -for src in qemu-*\.*; do - rm -rf $src -done - -for src in qemu-*; do - mv $src $RPM_BUILD_ROOT%{_bindir}/$(basename $src)-static -done -popd -%endif - %check -%ifnarch loongarch64 pushd %{qemu_kvm_build} echo "Testing qemu-kvm-build" export DIFF=diff; make check V=1 popd -%endif %post -n qemu-kvm-common %systemd_post ksm.service @@ -2062,7 +1896,7 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_unitdir}/ksmtuned.service %{_sbindir}/ksmtuned %{_udevdir}/udev-kvm-check -%{_udevrulesdir}/81-kvm-anolis.rules +%{_udevrulesdir}/81-kvm-rhel.rules %ghost %{_sysconfdir}/kvm %config(noreplace) %{_sysconfdir}/ksmtuned.conf %dir %{_sysconfdir}/%{name} @@ -2088,10 +1922,6 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_datadir}/%{name}/s390-ccw.img %{_datadir}/%{name}/s390-netboot.img %endif -%ifarch loongarch64 - %{_datadir}/%{name}/loongarch_bios.bin - %{_datadir}/%{name}/loongarch_vars.bin -%endif %ifnarch aarch64 s390x %{_datadir}/%{name}/vgabios.bin %{_datadir}/%{name}/vgabios-cirrus.bin @@ -2113,7 +1943,7 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %ifnarch s390x %{_libdir}/%{name}/hw-display-virtio-gpu-pci-gl.so %endif -%ifarch x86_64 %{power64} loongarch64 +%ifarch x86_64 %{power64} %{_libdir}/%{name}/hw-display-virtio-vga-gl.so %endif %{_libdir}/%{name}/accel-qtest-%{kvm_target}.so @@ -2206,7 +2036,7 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_libdir}/qemu-kvm/audio-spice.so %{_libdir}/qemu-kvm/ui-spice-core.so %{_libdir}/qemu-kvm/chardev-spice.so -%ifarch x86_64 loongarch64 +%ifarch x86_64 %{_libdir}/qemu-kvm/hw-display-qxl.so %endif %endif @@ -2222,53 +2052,14 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_libdir}/qemu-kvm/hw-usb-redirect.so %endif -%if %{user_static} -%files -n qemu-user-static -%{_bindir}/qemu-aarch64-static -%endif %changelog -* Wed Sep 11 2024 Quanxian Wang - 6.2.0-52.0.2 -- Intel-SIG: Supprt new SPR models - -* Wed Aug 28 2024 Jacob Wang - 6.2.0-52.0.1 -- Adjust limit for virtiofsd minor version -- Add loongarch supporti (lixianglai@loongson.cn) -- Add package qemu-user-static (fuyuan.wh@alibaba-inc.com) -- Modify-smbios-option-lack-and-Modify-the-maximum-num.patch (lixianglai@loongson.cn) -- rename-kvm_msr_buf-with-kvm_csr_buf.patch (lixianglai@loongson.cn) -- code-cleanup-for-loongarch-kvm.patch (lixianglai@loongson.cn) -- Support-TPM.patch (lixianglai@loongson.cn) -- kvm-csr-save-and-restore-optimization.patch (lixianglai@loongson.cn) -- address-space-code-cleanup-on-7A-virt-machine.patch (lixianglai@loongson.cn) -- Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch (lixianglai@loongson.cn) -- Support-vfio-config.patch (lixianglai@loongson.cn) -- pass-to-make-check.patch (lixianglai@loongson.cn) -- fixup-can-t-find-cpu-type.patch (lixianglai@loongson.cn) -- fix-smbios-type4-info-for-numa-support.patch (lixianglai@loongson.cn) -- Fix-smp.cores-value.patch (lixianglai@loongson.cn) -- Add-lbt-support-for-kvm.patch (lixianglai@loongson.cn) -- Modify-the-ioctl-command-of-kvm.patch (lixianglai@loongson.cn) -- Add-usb-storage-config-for-loongarch.patch (zhaotianrui@loongson.c) -- Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch (zhaotianrui@loongson.c) -- Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch (zhaotianrui@loongson.c) -- Fix-LoongArch-KVM-header-macros.patch (zhaotianrui@loongson.c) -- loongarch: Fixed the issue where qemu specifies the boot order (lixianglai@loongson.cn) -- 0001-anolis-csv-i386-add-CSV-context.patch (jiangxin@hygon.cn) -- 0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch (jiangxin@hygon.cn) -- 0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch (jiangxin@hygon.cn) -- 0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch (jiangxin@hygon.cn) -- 0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch (jiangxin@hygon.cn) -- 0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch (jiangxin@hygon.cn) -- 0007-anolis-target-i386-csv-load-initial-image-to-private.patch (jiangxin@hygon.cn) -- 0008-anolis-vga-force-full-update-for-CSV-guest.patch (jiangxin@hygon.cn) - (Hygon CSV3 feature) -- Support Hygon CSV/CSV2 live migration, CSV2 reboot (hanliyang@hygon.cn) -- Support CSV3 live migration (jiangxin@hygon.cn) -- Support reuse ASID for CSV guests (hanliyang@hygon.cn) -- Support tkm key isolation (xiongmengbiao@hygon.cn) -- Add Hygon Dhyana-v3 and Dharma CPU model (zhouyanjing@hygon.cn) -- Intel-SIG: Supprt Intel SPR/GNR/SRF new ISAs and cpu models (quanxian.wang@intel.com) +* Thu Sep 05 2024 Miroslav Rezanina - 6.2.0-53.el8 +- kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch [RHEL-52611] +- kvm-iotests-test-NBD-TLS-iothread.patch [RHEL-52611] +- kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch [RHEL-52611] +- Resolves: RHEL-52611 + (CVE-2024-7409 virt:rhel/qemu-kvm: Denial of Service via Improper Synchronization in QEMU NBD Server During Socket Closure [rhel-8.10.z]) * Wed Aug 21 2024 Miroslav Rezanina - 6.2.0-52.el8 - kvm-nbd-server-Plumb-in-new-args-to-nbd_client_add.patch [RHEL-52611] diff --git a/rename-kvm_msr_buf-with-kvm_csr_buf.patch b/rename-kvm_msr_buf-with-kvm_csr_buf.patch deleted file mode 100644 index 6d13b6e..0000000 --- a/rename-kvm_msr_buf-with-kvm_csr_buf.patch +++ /dev/null @@ -1,638 +0,0 @@ -From 25f1ae50858b5c580336321e18ef0029d3dec922 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 05:57:27 -0400 -Subject: [PATCH 11/28] rename kvm_msr_buf with kvm_csr_buf. - -Signed-off-by: lixianglai ---- - target/loongarch64/cpu.h | 2 +- - target/loongarch64/kvm.c | 564 +++++++++++++++++++-------------------- - 2 files changed, 283 insertions(+), 283 deletions(-) - -diff --git a/target/loongarch64/cpu.h b/target/loongarch64/cpu.h -index 10facb3b7..078556a22 100644 ---- a/target/loongarch64/cpu.h -+++ b/target/loongarch64/cpu.h -@@ -200,7 +200,7 @@ struct LOONGARCHCPU { - VMChangeStateEntry *cpuStateEntry; - int32_t node_id; /* NUMA node this CPU belongs to */ - int32_t core_id; -- struct kvm_msrs *kvm_msr_buf; -+ struct kvm_msrs *kvm_csr_buf; - /* 'compatible' string for this CPU for Linux device trees */ - const char *dtb_compatible; - }; -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -index 404a605eb..b5c655812 100644 ---- a/target/loongarch64/kvm.c -+++ b/target/loongarch64/kvm.c -@@ -31,7 +31,7 @@ - #define DEBUG_KVM 0 - /* A 16384-byte buffer can hold the 8-byte kvm_msrs header, plus - * 2047 kvm_msr_entry structs */ --#define MSR_BUF_SIZE 16384 -+#define CSR_BUF_SIZE 16384 - - #define DPRINTF(fmt, ...) \ - do { if (DEBUG_KVM) { fprintf(stderr, fmt, ## __VA_ARGS__); } } while (0) -@@ -101,7 +101,7 @@ int kvm_arch_init_vcpu(CPUState *cs) - int ret = 0; - - cpu->cpuStateEntry = qemu_add_vm_change_state_handler(kvm_loongarch_update_state, cs); -- cpu->kvm_msr_buf = g_malloc0(MSR_BUF_SIZE); -+ cpu->kvm_csr_buf = g_malloc0(CSR_BUF_SIZE); - DPRINTF("%s\n", __func__); - return ret; - } -@@ -111,15 +111,15 @@ int kvm_arch_destroy_vcpu(CPUState *cs) - return 0; - } - --static void kvm_msr_buf_reset(LOONGARCHCPU *cpu) -+static void kvm_csr_buf_reset(LOONGARCHCPU *cpu) - { -- memset(cpu->kvm_msr_buf, 0, MSR_BUF_SIZE); -+ memset(cpu->kvm_csr_buf, 0, CSR_BUF_SIZE); - } - --static void kvm_msr_entry_add(LOONGARCHCPU *cpu, uint32_t index, uint64_t value) -+static void kvm_csr_entry_add(LOONGARCHCPU *cpu, uint32_t index, uint64_t value) - { -- struct kvm_msrs *msrs = cpu->kvm_msr_buf; -- void *limit = ((void *)msrs) + MSR_BUF_SIZE; -+ struct kvm_msrs *msrs = cpu->kvm_csr_buf; -+ void *limit = ((void *)msrs) + CSR_BUF_SIZE; - struct kvm_csr_entry *entry = &msrs->entries[msrs->ncsrs]; - - assert((void *)(entry + 1) <= limit); -@@ -767,144 +767,144 @@ static int kvm_loongarch_put_csr_registers(CPUState *cs, int level) - - (void)level; - -- kvm_msr_buf_reset(cpu); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CRMD, env->CSR_CRMD); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRMD, env->CSR_PRMD); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_EUEN, env->CSR_EUEN); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MISC, env->CSR_MISC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ECFG, env->CSR_ECFG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ESTAT, env->CSR_ESTAT); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERA, env->CSR_ERA); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADV, env->CSR_BADV); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADI, env->CSR_BADI); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_EEPN, env->CSR_EEPN); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, env->CSR_TLBIDX); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, env->CSR_TLBEHI); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, env->CSR_TLBELO0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, env->CSR_TLBELO1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GTLBC, env->CSR_GTLBC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TRGP, env->CSR_TRGP); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ASID, env->CSR_ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDL, env->CSR_PGDL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDH, env->CSR_PGDH); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGD, env->CSR_PGD); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, env->CSR_PWCTL0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, env->CSR_PWCTL1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, env->CSR_STLBPGSIZE); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_RVACFG, env->CSR_RVACFG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CPUID, env->CSR_CPUID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, env->CSR_PRCFG1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, env->CSR_PRCFG2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, env->CSR_PRCFG3); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS0, env->CSR_KS0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS1, env->CSR_KS1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS2, env->CSR_KS2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS3, env->CSR_KS3); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS4, env->CSR_KS4); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS5, env->CSR_KS5); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS6, env->CSR_KS6); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS7, env->CSR_KS7); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TMID, env->CSR_TMID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CNTC, env->CSR_CNTC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, env->CSR_TINTCLR); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GSTAT, env->CSR_GSTAT); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCFG, env->CSR_GCFG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GINTC, env->CSR_GINTC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCNTC, env->CSR_GCNTC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, env->CSR_LLBCTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, env->CSR_IMPCTL1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, env->CSR_IMPCTL2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GNMI, env->CSR_GNMI); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, env->CSR_TLBRENT); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, env->CSR_TLBRBADV); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, env->CSR_TLBRERA); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, env->CSR_TLBRSAVE); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, env->CSR_TLBRELO0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, env->CSR_TLBRELO1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, env->CSR_TLBREHI); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, env->CSR_TLBRPRMD); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, env->CSR_ERRCTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, env->CSR_ERRINFO); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, env->CSR_ERRINFO1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRENT, env->CSR_ERRENT); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRERA, env->CSR_ERRERA); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, env->CSR_ERRSAVE); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CTAG, env->CSR_CTAG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, env->CSR_DMWIN0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, env->CSR_DMWIN1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, env->CSR_DMWIN2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, env->CSR_DMWIN3); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, env->CSR_PERFCTRL0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, env->CSR_PERFCNTR0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, env->CSR_PERFCTRL1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, env->CSR_PERFCNTR1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, env->CSR_PERFCTRL2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, env->CSR_PERFCNTR2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, env->CSR_PERFCTRL3); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, env->CSR_PERFCNTR3); -+ kvm_csr_buf_reset(cpu); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CRMD, env->CSR_CRMD); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRMD, env->CSR_PRMD); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EUEN, env->CSR_EUEN); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MISC, env->CSR_MISC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ECFG, env->CSR_ECFG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ESTAT, env->CSR_ESTAT); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERA, env->CSR_ERA); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADV, env->CSR_BADV); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADI, env->CSR_BADI); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EEPN, env->CSR_EEPN); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, env->CSR_TLBIDX); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, env->CSR_TLBEHI); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, env->CSR_TLBELO0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, env->CSR_TLBELO1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GTLBC, env->CSR_GTLBC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TRGP, env->CSR_TRGP); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ASID, env->CSR_ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDL, env->CSR_PGDL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDH, env->CSR_PGDH); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGD, env->CSR_PGD); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, env->CSR_PWCTL0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, env->CSR_PWCTL1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, env->CSR_STLBPGSIZE); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_RVACFG, env->CSR_RVACFG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CPUID, env->CSR_CPUID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, env->CSR_PRCFG1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, env->CSR_PRCFG2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, env->CSR_PRCFG3); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS0, env->CSR_KS0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS1, env->CSR_KS1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS2, env->CSR_KS2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS3, env->CSR_KS3); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS4, env->CSR_KS4); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS5, env->CSR_KS5); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS6, env->CSR_KS6); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS7, env->CSR_KS7); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TMID, env->CSR_TMID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CNTC, env->CSR_CNTC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, env->CSR_TINTCLR); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GSTAT, env->CSR_GSTAT); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCFG, env->CSR_GCFG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GINTC, env->CSR_GINTC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCNTC, env->CSR_GCNTC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, env->CSR_LLBCTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, env->CSR_IMPCTL1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, env->CSR_IMPCTL2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GNMI, env->CSR_GNMI); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, env->CSR_TLBRENT); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, env->CSR_TLBRBADV); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, env->CSR_TLBRERA); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, env->CSR_TLBRSAVE); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, env->CSR_TLBRELO0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, env->CSR_TLBRELO1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, env->CSR_TLBREHI); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, env->CSR_TLBRPRMD); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, env->CSR_ERRCTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, env->CSR_ERRINFO); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, env->CSR_ERRINFO1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRENT, env->CSR_ERRENT); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRERA, env->CSR_ERRERA); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, env->CSR_ERRSAVE); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CTAG, env->CSR_CTAG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, env->CSR_DMWIN0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, env->CSR_DMWIN1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, env->CSR_DMWIN2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, env->CSR_DMWIN3); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, env->CSR_PERFCTRL0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, env->CSR_PERFCNTR0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, env->CSR_PERFCTRL1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, env->CSR_PERFCNTR1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, env->CSR_PERFCTRL2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, env->CSR_PERFCNTR2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, env->CSR_PERFCTRL3); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, env->CSR_PERFCNTR3); - - /* debug */ -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPC, env->CSR_MWPC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPS, env->CSR_MWPS); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, env->CSR_DB0ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, env->CSR_DB0MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, env->CSR_DB0CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, env->CSR_DB0ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, env->CSR_DB1ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, env->CSR_DB1MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, env->CSR_DB1CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, env->CSR_DB1ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, env->CSR_DB2ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, env->CSR_DB2MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, env->CSR_DB2CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, env->CSR_DB2ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, env->CSR_DB3ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, env->CSR_DB3MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, env->CSR_DB3CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, env->CSR_DB3ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPC, env->CSR_FWPC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPS, env->CSR_FWPS); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, env->CSR_IB0ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, env->CSR_IB0MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, env->CSR_IB0CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, env->CSR_IB0ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, env->CSR_IB1ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, env->CSR_IB1MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, env->CSR_IB1CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, env->CSR_IB1ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, env->CSR_IB2ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, env->CSR_IB2MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, env->CSR_IB2CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, env->CSR_IB2ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, env->CSR_IB3ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, env->CSR_IB3MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, env->CSR_IB3CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, env->CSR_IB3ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, env->CSR_IB4ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, env->CSR_IB4MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, env->CSR_IB4CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, env->CSR_IB4ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, env->CSR_IB5ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, env->CSR_IB5MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, env->CSR_IB5CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, env->CSR_IB5ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, env->CSR_IB6ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, env->CSR_IB6MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, env->CSR_IB6CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, env->CSR_IB6ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, env->CSR_IB7ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, env->CSR_IB7MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, env->CSR_IB7CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, env->CSR_IB7ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DEBUG, env->CSR_DEBUG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DERA, env->CSR_DERA); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DESAVE, env->CSR_DESAVE); -- -- ret = kvm_vcpu_ioctl(cs, KVM_SET_MSRS, cpu->kvm_msr_buf); -- if (ret < cpu->kvm_msr_buf->ncsrs) { -- struct kvm_csr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPC, env->CSR_MWPC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPS, env->CSR_MWPS); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, env->CSR_DB0ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, env->CSR_DB0MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, env->CSR_DB0CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, env->CSR_DB0ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, env->CSR_DB1ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, env->CSR_DB1MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, env->CSR_DB1CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, env->CSR_DB1ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, env->CSR_DB2ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, env->CSR_DB2MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, env->CSR_DB2CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, env->CSR_DB2ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, env->CSR_DB3ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, env->CSR_DB3MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, env->CSR_DB3CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, env->CSR_DB3ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPC, env->CSR_FWPC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPS, env->CSR_FWPS); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, env->CSR_IB0ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, env->CSR_IB0MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, env->CSR_IB0CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, env->CSR_IB0ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, env->CSR_IB1ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, env->CSR_IB1MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, env->CSR_IB1CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, env->CSR_IB1ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, env->CSR_IB2ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, env->CSR_IB2MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, env->CSR_IB2CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, env->CSR_IB2ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, env->CSR_IB3ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, env->CSR_IB3MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, env->CSR_IB3CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, env->CSR_IB3ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, env->CSR_IB4ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, env->CSR_IB4MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, env->CSR_IB4CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, env->CSR_IB4ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, env->CSR_IB5ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, env->CSR_IB5MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, env->CSR_IB5CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, env->CSR_IB5ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, env->CSR_IB6ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, env->CSR_IB6MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, env->CSR_IB6CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, env->CSR_IB6ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, env->CSR_IB7ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, env->CSR_IB7MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, env->CSR_IB7CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, env->CSR_IB7ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DEBUG, env->CSR_DEBUG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DERA, env->CSR_DERA); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DESAVE, env->CSR_DESAVE); -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_SET_MSRS, cpu->kvm_csr_buf); -+ if (ret < cpu->kvm_csr_buf->ncsrs) { -+ struct kvm_csr_entry *e = &cpu->kvm_csr_buf->entries[ret]; - printf("error: failed to set CSR 0x%" PRIx32 " to 0x%" PRIx64"\n", - (uint32_t)e->index, (uint64_t)e->data); - } -@@ -935,147 +935,147 @@ static int kvm_loongarch_get_csr_registers(CPUState *cs) - LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); - CPULOONGARCHState *env = &cpu->env; - int ret = 0, i; -- struct kvm_csr_entry *csrs = cpu->kvm_msr_buf->entries; -- -- kvm_msr_buf_reset(cpu); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CRMD, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRMD, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_EUEN, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MISC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ECFG, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ESTAT, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERA, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADV, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADI, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_EEPN, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GTLBC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TRGP, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDH, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGD, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_RVACFG, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CPUID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS3, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS4, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS5, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS6, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS7, 0); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TMID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CNTC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GSTAT, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCFG, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GINTC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCNTC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GNMI, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRENT, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRERA, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CTAG, 0); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, 0); -+ struct kvm_csr_entry *csrs = cpu->kvm_csr_buf->entries; -+ -+ kvm_csr_buf_reset(cpu); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CRMD, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRMD, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EUEN, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MISC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ECFG, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ESTAT, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERA, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADV, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADI, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EEPN, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GTLBC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TRGP, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDH, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGD, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_RVACFG, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CPUID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS3, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS4, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS5, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS6, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS7, 0); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TMID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CNTC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GSTAT, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCFG, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GINTC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCNTC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GNMI, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRENT, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRERA, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CTAG, 0); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, 0); - - /* debug */ -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPS, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPS, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DEBUG, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DERA, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DESAVE, 0); -- -- ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, cpu->kvm_msr_buf); -- if (ret < cpu->kvm_msr_buf->ncsrs) { -- struct kvm_csr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPS, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPS, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DEBUG, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DERA, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DESAVE, 0); -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, cpu->kvm_csr_buf); -+ if (ret < cpu->kvm_csr_buf->ncsrs) { -+ struct kvm_csr_entry *e = &cpu->kvm_csr_buf->entries[ret]; - printf("error: failed to get CSR 0x%" PRIx32"\n", - (uint32_t)e->index); - } --- -2.43.5 - -- Gitee