From 4401f0d4d3f1288c16d647cf19d8d3eba0b577ee Mon Sep 17 00:00:00 2001 From: Renbo Date: Thu, 15 Sep 2022 11:19:37 +0800 Subject: [PATCH 1/3] update to qemu-kvm-6.2.0-11.module+el8.6.0+16516+f8cbd5fe.5 Signed-off-by: Renbo --- 0001-Add-Acpi-support.patch | 1348 -- 0002-Support-rtc.patch | 370 - 0003-Add-loongarch-machine.patch | 5752 ------ 0004-Add-target-loongarch64.patch | 15918 ---------------- 0005-Add-linux-headers-and-linux-user.patch | 1663 -- 0006-Add-disas-gdb.patch | 3183 --- 0007-Modify-kvm-cpu-vga-qapi.patch | 480 - 0008-Modify-compile-script.patch | 36 - 0009-Add-loongarch64-rh-devices.mak.patch | 3227 ---- ...sync-missed-zero-copy-migration-stat.patch | 87 + ...lags-on-io_writev-and-introduce-io_f.patch | 420 + ...et-Add-support-for-MSG_ZEROCOPY-IPV6.patch | 56 + ...-Fix-zero-copy-flush-returning-code-.patch | 65 + ...-Fix-zero-copy-send-so-socket-flush-.patch | 58 + ...-Implement-io_writev-zero-copy-flag-.patch | 249 + ...-Introduce-assert-and-reduce-ifdefs-.patch | 82 + ...n-why-max-batch-is-checked-in-laio_i.patch | 49 + ...balanced-plugged-counter-in-laio_io_.patch | 56 + ...migration-Add-migrate_use_tls-helper.patch | 106 + ...ro-copy-send-parameter-for-QMP-HMP-f.patch | 250 + ...gration-All-this-fields-are-unsigned.patch | 329 + ...false-positive-on-non-supported-scen.patch | 93 + ...-zero_copy_send-from-migration-param.patch | 289 + ...ration-Introduce-ram_transferred_add.patch | 122 + ...ver-call-twice-qemu_target_page_size.patch | 116 + ...pre-copy-downtime-and-post-copy-byte.patch | 122 + ...maining-params-has_-true-in-migratio.patch | 62 + ...d-Report-to-user-when-zerocopy-not-w.patch | 83 + kvm-multifd-Add-missing-documention.patch | 81 + ...-Fill-offset-and-block-for-reception.patch | 50 + ...t-zero-copy-write-in-multifd-migrati.patch | 182 + ...zlib-compression-method-not-use-iovs.patch | 98 + kvm-multifd-Make-zlib-use-iov-s.patch | 53 + ...zstd-compression-method-not-use-iovs.patch | 94 + kvm-multifd-Make-zstd-use-iov-s.patch | 53 + ...ultifd-Move-iov-from-pages-to-params.patch | 190 + kvm-multifd-Remove-send_write-method.patch | 160 + kvm-multifd-Rename-used-field-to-num.patch | 177 + ...der-packet-without-flags-if-zero-cop.patch | 102 + ...ariable-is-only-used-inside-the-loop.patch | 48 + ...Use-a-single-writev-on-the-send-side.patch | 80 + ...-normal-pages-array-on-the-send-side.patch | 261 + ...send_sync_main-now-returns-negative-.patch | 163 + ...sed-parameter-from-send_prepare-meth.patch | 135 + ...sed-parameter-from-send_recv_pages-m.patch | 149 + ...-improper-cleanup-in-vhost_net_start.patch | 56 + ...backend-feature-should-set-only-once.patch | 58 + ...e-name-and-polarity-for-vhost_vdpa_o.patch | 123 + ...mproper-cleanup-in-net_init_vhost_vd.patch | 48 + ...-ctrl_vq-index-for-non-mq-guest-for-.patch | 143 + ...-handle-mq-request-in-userspace-hand.patch | 109 + ...-vhost_dev-and-notifiers-for-cvq-onl.patch | 52 + ...iofsd-Adjust-limit-for-minor-version.patch | 41 - loongarch_bios.bin | Bin 4190208 -> 0 bytes loongarch_vars.bin | Bin 389120 -> 0 bytes qemu-kvm.spec | 191 +- 56 files changed, 5505 insertions(+), 32063 deletions(-) delete mode 100644 0001-Add-Acpi-support.patch delete mode 100644 0002-Support-rtc.patch delete mode 100644 0003-Add-loongarch-machine.patch delete mode 100644 0004-Add-target-loongarch64.patch delete mode 100644 0005-Add-linux-headers-and-linux-user.patch delete mode 100644 0006-Add-disas-gdb.patch delete mode 100644 0007-Modify-kvm-cpu-vga-qapi.patch delete mode 100644 0008-Modify-compile-script.patch delete mode 100644 0009-Add-loongarch64-rh-devices.mak.patch create mode 100644 kvm-Add-dirty-sync-missed-zero-copy-migration-stat.patch create mode 100644 kvm-QIOChannel-Add-flags-on-io_writev-and-introduce-io_f.patch create mode 100644 kvm-QIOChannelSocket-Add-support-for-MSG_ZEROCOPY-IPV6.patch create mode 100644 kvm-QIOChannelSocket-Fix-zero-copy-flush-returning-code-.patch create mode 100644 kvm-QIOChannelSocket-Fix-zero-copy-send-so-socket-flush-.patch create mode 100644 kvm-QIOChannelSocket-Implement-io_writev-zero-copy-flag-.patch create mode 100644 kvm-QIOChannelSocket-Introduce-assert-and-reduce-ifdefs-.patch create mode 100644 kvm-linux-aio-explain-why-max-batch-is-checked-in-laio_i.patch create mode 100644 kvm-linux-aio-fix-unbalanced-plugged-counter-in-laio_io_.patch create mode 100644 kvm-migration-Add-migrate_use_tls-helper.patch create mode 100644 kvm-migration-Add-zero-copy-send-parameter-for-QMP-HMP-f.patch create mode 100644 kvm-migration-All-this-fields-are-unsigned.patch create mode 100644 kvm-migration-Avoid-false-positive-on-non-supported-scen.patch create mode 100644 kvm-migration-Change-zero_copy_send-from-migration-param.patch create mode 100644 kvm-migration-Introduce-ram_transferred_add.patch create mode 100644 kvm-migration-Never-call-twice-qemu_target_page_size.patch create mode 100644 kvm-migration-Tally-pre-copy-downtime-and-post-copy-byte.patch create mode 100644 kvm-migration-add-remaining-params-has_-true-in-migratio.patch create mode 100644 kvm-migration-multifd-Report-to-user-when-zerocopy-not-w.patch create mode 100644 kvm-multifd-Add-missing-documention.patch create mode 100644 kvm-multifd-Fill-offset-and-block-for-reception.patch create mode 100644 kvm-multifd-Implement-zero-copy-write-in-multifd-migrati.patch create mode 100644 kvm-multifd-Make-zlib-compression-method-not-use-iovs.patch create mode 100644 kvm-multifd-Make-zlib-use-iov-s.patch create mode 100644 kvm-multifd-Make-zstd-compression-method-not-use-iovs.patch create mode 100644 kvm-multifd-Make-zstd-use-iov-s.patch create mode 100644 kvm-multifd-Move-iov-from-pages-to-params.patch create mode 100644 kvm-multifd-Remove-send_write-method.patch create mode 100644 kvm-multifd-Rename-used-field-to-num.patch create mode 100644 kvm-multifd-Send-header-packet-without-flags-if-zero-cop.patch create mode 100644 kvm-multifd-The-variable-is-only-used-inside-the-loop.patch create mode 100644 kvm-multifd-Use-a-single-writev-on-the-send-side.patch create mode 100644 kvm-multifd-Use-normal-pages-array-on-the-send-side.patch create mode 100644 kvm-multifd-multifd_send_sync_main-now-returns-negative-.patch create mode 100644 kvm-multifd-remove-used-parameter-from-send_prepare-meth.patch create mode 100644 kvm-multifd-remove-used-parameter-from-send_recv_pages-m.patch create mode 100644 kvm-vhost-net-fix-improper-cleanup-in-vhost_net_start.patch create mode 100644 kvm-vhost-vdpa-backend-feature-should-set-only-once.patch create mode 100644 kvm-vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch create mode 100644 kvm-vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch create mode 100644 kvm-virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch create mode 100644 kvm-virtio-net-don-t-handle-mq-request-in-userspace-hand.patch create mode 100644 kvm-virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch delete mode 100644 kvm-virtiofsd-Adjust-limit-for-minor-version.patch delete mode 100644 loongarch_bios.bin delete mode 100644 loongarch_vars.bin diff --git a/0001-Add-Acpi-support.patch b/0001-Add-Acpi-support.patch deleted file mode 100644 index 5b1561c..0000000 --- a/0001-Add-Acpi-support.patch +++ /dev/null @@ -1,1348 +0,0 @@ -From 612826687e639d007e4270b01a61f34f7fc1f813 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:11:23 -0400 -Subject: [PATCH 1/8] 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 622b0b50b7..2f2fb33a7b 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 0000000000..35d4a75266 ---- /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 0000000000..2de50ccb9c ---- /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 adf6347bc4..5fe4cfa4f1 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 0000000000..4401515c7b ---- /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.27.0 - diff --git a/0002-Support-rtc.patch b/0002-Support-rtc.patch deleted file mode 100644 index 082fcdf..0000000 --- a/0002-Support-rtc.patch +++ /dev/null @@ -1,370 +0,0 @@ -From befa5ef7576fdbe2e729203538b066e5f87c3b8f Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:15:49 -0400 -Subject: [PATCH 2/8] 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 010be7ed1f..b395c72d7d 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 0000000000..756f2fc9ce ---- /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 03092e2ceb..e841a2f6ee 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.27.0 - diff --git a/0003-Add-loongarch-machine.patch b/0003-Add-loongarch-machine.patch deleted file mode 100644 index c1617ba..0000000 --- a/0003-Add-loongarch-machine.patch +++ /dev/null @@ -1,5752 +0,0 @@ -From 2562504ad867de4a0539c261983c08cd5108bfe4 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:39:00 -0400 -Subject: [PATCH 3/8] 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 0000000000..3fe2677fda ---- /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 0000000000..6ba637be53 ---- /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 0000000000..a914268bbe ---- /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 0000000000..d6ba2a2cec ---- /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 0000000000..3de0ed88da ---- /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 0000000000..14521c2d5c ---- /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 0000000000..ade182abcc ---- /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 0000000000..3db269274f ---- /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 0000000000..7bce957124 ---- /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 0000000000..ca073a19cf ---- /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 0000000000..5a500fbd5a ---- /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 0000000000..81ee99a028 ---- /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 0000000000..3677303bfa ---- /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 0000000000..c05ae7a7fc ---- /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 0000000000..0886ed52af ---- /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 0000000000..686af763a0 ---- /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.27.0 - diff --git a/0004-Add-target-loongarch64.patch b/0004-Add-target-loongarch64.patch deleted file mode 100644 index 38e74c2..0000000 --- a/0004-Add-target-loongarch64.patch +++ /dev/null @@ -1,15918 +0,0 @@ -From 441bbe9ec5021bf56a929134a71cd85815ec3956 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:44:33 -0400 -Subject: [PATCH 4/8] Add target/loongarch64. - -Change-Id: Idd3ed114968c4a1f1be5fe19dc279028775eb89d -Signed-off-by: lixianglai ---- - target/Kconfig | 1 + - target/loongarch64/Kconfig | 2 + - target/loongarch64/arch_dump.c | 175 ++ - 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, 15657 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 ae7f24fc66..50b46d0487 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 0000000000..46b26b1a85 ---- /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 0000000000..9fb43b33d2 ---- /dev/null -+++ b/target/loongarch64/arch_dump.c -@@ -0,0 +1,175 @@ -+/* 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, void *opaque) -+{ -+ struct loongarch_note note; -+ CPULOONGARCHState *env = &LOONGARCH_CPU(cs)->env; -+ DumpState *s = opaque; -+ 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 0000000000..e549bb46b6 ---- /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 0000000000..24ca458af0 ---- /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 0000000000..ee9c1de571 ---- /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 0000000000..a4535d34a6 ---- /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 0000000000..10facb3b73 ---- /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 0000000000..182e59e925 ---- /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 0000000000..795458205b ---- /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 0000000000..42d7f05ca2 ---- /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 0000000000..b6898c2e91 ---- /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 0000000000..4013178f45 ---- /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 0000000000..841240e57b ---- /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 0000000000..ff2026ed82 ---- /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 0000000000..f194f70116 ---- /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 0000000000..6e85847f8a ---- /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 0000000000..79a70e9d26 ---- /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, void *opaque); -+ -+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 0000000000..404a605eb6 ---- /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 0000000000..a56026d10c ---- /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 0000000000..d3a61cf255 ---- /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 0000000000..b69bca6a9b ---- /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 0000000000..6badf4484e ---- /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 0000000000..9a34c0d25e ---- /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 0000000000..b86fecf899 ---- /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 0000000000..f5e68349a9 ---- /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 0000000000..e0bca4f82e ---- /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 0000000000..e50670be47 ---- /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 0000000000..fe122e4c31 ---- /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 2f6940255e..ac0ce618b7 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.27.0 - 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 93ba8ed..0000000 --- a/0005-Add-linux-headers-and-linux-user.patch +++ /dev/null @@ -1,1663 +0,0 @@ -From 0d21e423fc15e8e2e2fdc910a7e94e051427f230 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:47:06 -0400 -Subject: [PATCH 5/8] 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 0000000000..5c2c8779a6 ---- /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 0000000000..a24375ee59 ---- /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 0000000000..b809608349 ---- /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 0000000000..2a6014562a ---- /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 0000000000..6d4093e1d7 ---- /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 0000000000..c4c0b4d701 ---- /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 0000000000..6fe6852758 ---- /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 0000000000..0e4c8f012d ---- /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 0000000000..a30aca8d8e ---- /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 0000000000..0f6845737f ---- /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 0000000000..6c153d12c4 ---- /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 0000000000..a3d7b46062 ---- /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 0000000000..e418c8e8f5 ---- /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 0000000000..280acd0971 ---- /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 0000000000..cb77f07080 ---- /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 0000000000..6c613a1973 ---- /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.27.0 - diff --git a/0006-Add-disas-gdb.patch b/0006-Add-disas-gdb.patch deleted file mode 100644 index 00d9b5e..0000000 --- a/0006-Add-disas-gdb.patch +++ /dev/null @@ -1,3183 +0,0 @@ -From 0789663b3a2ad105a209c7aa36d102a5b05f1397 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:51:12 -0400 -Subject: [PATCH 6/8] 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 0000000000..fcb7e45dd2 ---- /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 0000000000..dc5ab39661 ---- /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 0000000000..14dd131e2e ---- /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 449f99e1de..06a69d9d72 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 0000000000..04891e023f ---- /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 0000000000..6308fb6ecb ---- /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 0000000000..a5b4d80e6c ---- /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 0000000000..74ab55a015 ---- /dev/null -+++ b/gdb-xml/loongarch-fpu64.xml -@@ -0,0 +1,57 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ --- -2.27.0 - diff --git a/0007-Modify-kvm-cpu-vga-qapi.patch b/0007-Modify-kvm-cpu-vga-qapi.patch deleted file mode 100644 index 72fe897..0000000 --- a/0007-Modify-kvm-cpu-vga-qapi.patch +++ /dev/null @@ -1,480 +0,0 @@ -From 6e52e755bd54efb15afa052dac6dd0c7f696e366 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Sat, 20 Aug 2022 02:18:41 -0400 -Subject: [PATCH 7/8] 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/loongarch_bios.bin | Bin 0 -> 4190208 bytes - pc-bios/meson.build | 1 + - qapi/machine-target.json | 6 ++-- - qapi/machine.json | 2 +- - qapi/misc-target.json | 1 + - 21 files changed, 138 insertions(+), 18 deletions(-) - create mode 100644 pc-bios/loongarch_bios.bin - -diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c -index b20903ea30..cd73fab65b 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 14521c2d5c..60daafd6e1 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 3db269274f..3194a822cc 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 b3366c888e..f224f8ad28 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 08e1beec85..95b93f1002 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 811bf4a1cb..66030f4906 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 0886ed52af..62e2830e27 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 60718fc342..903475bb21 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 70c579560a..62d1a4b92d 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 bcaf66cc4d..20b90426f5 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -2002,6 +2002,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) - - #endif /* __LINUX_KVM_H */ -diff --git a/linux-user/elfload.c b/linux-user/elfload.c -index 767f54c76d..9fb632780a 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 bf62c13e37..195f9e83ac 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 5c713fa8ab..66ddb25d1c 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 f1cfcc8104..729131ecd0 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 0b13975937..7e2915d53e 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 5f6ba86dbb..fc2dc58f33 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 b40ff3f2bd..a09ca4d03c 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 f5ec4bc172..682dc86b42 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 a9f33d0f27..cd47b8d6bc 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 4bc45d2474..63cebef573 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.27.0 - diff --git a/0008-Modify-compile-script.patch b/0008-Modify-compile-script.patch deleted file mode 100644 index 87054ee..0000000 --- a/0008-Modify-compile-script.patch +++ /dev/null @@ -1,36 +0,0 @@ -From b051f9fdabc2cd49c1c80ef50bbee276b6946609 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 22 Aug 2022 08:22:03 -0400 -Subject: [PATCH 08/10] 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 fc2dc58f33..c0fb5788f7 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.27.0 - diff --git a/0009-Add-loongarch64-rh-devices.mak.patch b/0009-Add-loongarch64-rh-devices.mak.patch deleted file mode 100644 index ef7533d..0000000 --- a/0009-Add-loongarch64-rh-devices.mak.patch +++ /dev/null @@ -1,3227 +0,0 @@ -From d2163a939cd14d3d9a8a4afb9d9eacbb71b61517 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Wed, 24 Aug 2022 22:56:29 -0400 -Subject: [PATCH 09/10] 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 0000000000..e7b5bdc8e9 ---- /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 48c21775f3..1f932f7eeb 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 c0fb5788f7..c5fdb78569 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 a09ca4d03c..60009bd89e 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 0000000000..d162571856 ---- /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 0000000000..349c672687 ---- /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 0000000000..c3986a4fd4 ---- /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 0000000000..9b53549edb ---- /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 0000000000..d58a6162f2 ---- /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.27.0 - diff --git a/kvm-Add-dirty-sync-missed-zero-copy-migration-stat.patch b/kvm-Add-dirty-sync-missed-zero-copy-migration-stat.patch new file mode 100644 index 0000000..fb67d64 --- /dev/null +++ b/kvm-Add-dirty-sync-missed-zero-copy-migration-stat.patch @@ -0,0 +1,87 @@ +From aba4d52b3c06aaf5a7553db6dadcb02645e153f1 Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Mon, 11 Jul 2022 18:11:12 -0300 +Subject: [PATCH 30/34] Add dirty-sync-missed-zero-copy migration stat +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [30/34] 95d0255ea03cb7c986dc64645e95e10a5fbe0f9a +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Signed-off-by: Leonardo Bras +Acked-by: Markus Armbruster +Acked-by: Peter Xu +Reviewed-by: Daniel P. Berrangé +Message-Id: <20220711211112.18951-3-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit cf20c897338067ab4b70a4596fdccaf90c7e29a1) +Signed-off-by: Leonardo Bras +--- + migration/migration.c | 2 ++ + monitor/hmp-cmds.c | 5 +++++ + qapi/migration.json | 7 ++++++- + 3 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 87b4a6c3f9..a3e0ac954c 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1006,6 +1006,8 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) + info->ram->normal_bytes = ram_counters.normal * page_size; + info->ram->mbps = s->mbps; + info->ram->dirty_sync_count = ram_counters.dirty_sync_count; ++ info->ram->dirty_sync_missed_zero_copy = ++ ram_counters.dirty_sync_missed_zero_copy; + info->ram->postcopy_requests = ram_counters.postcopy_requests; + info->ram->page_size = page_size; + info->ram->multifd_bytes = ram_counters.multifd_bytes; +diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c +index 8c384dc1b2..f7216ab5d0 100644 +--- a/monitor/hmp-cmds.c ++++ b/monitor/hmp-cmds.c +@@ -305,6 +305,11 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) + monitor_printf(mon, "postcopy ram: %" PRIu64 " kbytes\n", + info->ram->postcopy_bytes >> 10); + } ++ if (info->ram->dirty_sync_missed_zero_copy) { ++ monitor_printf(mon, ++ "Zero-copy-send fallbacks happened: %" PRIu64 " times\n", ++ info->ram->dirty_sync_missed_zero_copy); ++ } + } + + if (info->has_disk) { +diff --git a/qapi/migration.json b/qapi/migration.json +index c8ec260ab0..94bc5c69db 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -55,6 +55,10 @@ + # @postcopy-bytes: The number of bytes sent during the post-copy phase + # (since 7.0). + # ++# @dirty-sync-missed-zero-copy: Number of times dirty RAM synchronization could ++# not avoid copying dirty pages. This is between ++# 0 and @dirty-sync-count * @multifd-channels. ++# (since 7.1) + # Since: 0.14 + ## + { 'struct': 'MigrationStats', +@@ -65,7 +69,8 @@ + 'postcopy-requests' : 'int', 'page-size' : 'int', + 'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64', + 'precopy-bytes' : 'uint64', 'downtime-bytes' : 'uint64', +- 'postcopy-bytes' : 'uint64' } } ++ 'postcopy-bytes' : 'uint64', ++ 'dirty-sync-missed-zero-copy' : 'uint64' } } + + ## + # @XBZRLECacheStats: +-- +2.35.3 + diff --git a/kvm-QIOChannel-Add-flags-on-io_writev-and-introduce-io_f.patch b/kvm-QIOChannel-Add-flags-on-io_writev-and-introduce-io_f.patch new file mode 100644 index 0000000..b0f1766 --- /dev/null +++ b/kvm-QIOChannel-Add-flags-on-io_writev-and-introduce-io_f.patch @@ -0,0 +1,420 @@ +From dc840cee933cfc1790b7624c88052f6deb43101d Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Wed, 18 May 2022 02:52:24 -0300 +Subject: [PATCH 17/34] QIOChannel: Add flags on io_writev and introduce + io_flush callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [17/34] 8ebb6301a83816937d7b87709cf906e1a9c16b01 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Add flags to io_writev and introduce io_flush as optional callback to +QIOChannelClass, allowing the implementation of zero copy writes by +subclasses. + +How to use them: +- Write data using qio_channel_writev*(...,QIO_CHANNEL_WRITE_FLAG_ZERO_COPY), +- Wait write completion with qio_channel_flush(). + +Notes: +As some zero copy write implementations work asynchronously, it's +recommended to keep the write buffer untouched until the return of +qio_channel_flush(), to avoid the risk of sending an updated buffer +instead of the buffer state during write. + +As io_flush callback is optional, if a subclass does not implement it, then: +- io_flush will return 0 without changing anything. + +Also, some functions like qio_channel_writev_full_all() were adapted to +receive a flag parameter. That allows shared code between zero copy and +non-zero copy writev, and also an easier implementation on new flags. + +Signed-off-by: Leonardo Bras +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Peter Xu +Reviewed-by: Juan Quintela +Message-Id: <20220513062836.965425-3-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit b88651cb4d4fa416fdbb6afaf5b26ec8c035eaad) +Signed-off-by: Leonardo Bras +--- + chardev/char-io.c | 2 +- + hw/remote/mpqemu-link.c | 2 +- + include/io/channel.h | 38 +++++++++++++++++++++- + io/channel-buffer.c | 1 + + io/channel-command.c | 1 + + io/channel-file.c | 1 + + io/channel-socket.c | 2 ++ + io/channel-tls.c | 1 + + io/channel-websock.c | 1 + + io/channel.c | 49 +++++++++++++++++++++++------ + migration/rdma.c | 1 + + scsi/pr-manager-helper.c | 2 +- + tests/unit/test-io-channel-socket.c | 1 + + 13 files changed, 88 insertions(+), 14 deletions(-) + +diff --git a/chardev/char-io.c b/chardev/char-io.c +index 8ced184160..4451128cba 100644 +--- a/chardev/char-io.c ++++ b/chardev/char-io.c +@@ -122,7 +122,7 @@ int io_channel_send_full(QIOChannel *ioc, + + ret = qio_channel_writev_full( + ioc, &iov, 1, +- fds, nfds, NULL); ++ fds, nfds, 0, NULL); + if (ret == QIO_CHANNEL_ERR_BLOCK) { + if (offset) { + return offset; +diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c +index 7e841820e5..e8f556bd27 100644 +--- a/hw/remote/mpqemu-link.c ++++ b/hw/remote/mpqemu-link.c +@@ -69,7 +69,7 @@ bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp) + } + + if (!qio_channel_writev_full_all(ioc, send, G_N_ELEMENTS(send), +- fds, nfds, errp)) { ++ fds, nfds, 0, errp)) { + ret = true; + } else { + trace_mpqemu_send_io_error(msg->cmd, msg->size, nfds); +diff --git a/include/io/channel.h b/include/io/channel.h +index 88988979f8..c680ee7480 100644 +--- a/include/io/channel.h ++++ b/include/io/channel.h +@@ -32,12 +32,15 @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass, + + #define QIO_CHANNEL_ERR_BLOCK -2 + ++#define QIO_CHANNEL_WRITE_FLAG_ZERO_COPY 0x1 ++ + typedef enum QIOChannelFeature QIOChannelFeature; + + enum QIOChannelFeature { + QIO_CHANNEL_FEATURE_FD_PASS, + QIO_CHANNEL_FEATURE_SHUTDOWN, + QIO_CHANNEL_FEATURE_LISTEN, ++ QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY, + }; + + +@@ -104,6 +107,7 @@ struct QIOChannelClass { + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp); + ssize_t (*io_readv)(QIOChannel *ioc, + const struct iovec *iov, +@@ -136,6 +140,8 @@ struct QIOChannelClass { + IOHandler *io_read, + IOHandler *io_write, + void *opaque); ++ int (*io_flush)(QIOChannel *ioc, ++ Error **errp); + }; + + /* General I/O handling functions */ +@@ -228,6 +234,7 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc, + * @niov: the length of the @iov array + * @fds: an array of file handles to send + * @nfds: number of file handles in @fds ++ * @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*) + * @errp: pointer to a NULL-initialized error object + * + * Write data to the IO channel, reading it from the +@@ -260,6 +267,7 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp); + + /** +@@ -837,6 +845,7 @@ int qio_channel_readv_full_all(QIOChannel *ioc, + * @niov: the length of the @iov array + * @fds: an array of file handles to send + * @nfds: number of file handles in @fds ++ * @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*) + * @errp: pointer to a NULL-initialized error object + * + * +@@ -846,6 +855,14 @@ int qio_channel_readv_full_all(QIOChannel *ioc, + * to be written, yielding from the current coroutine + * if required. + * ++ * If QIO_CHANNEL_WRITE_FLAG_ZERO_COPY is passed in flags, ++ * instead of waiting for all requested data to be written, ++ * this function will wait until it's all queued for writing. ++ * In this case, if the buffer gets changed between queueing and ++ * sending, the updated buffer will be sent. If this is not a ++ * desired behavior, it's suggested to call qio_channel_flush() ++ * before reusing the buffer. ++ * + * Returns: 0 if all bytes were written, or -1 on error + */ + +@@ -853,6 +870,25 @@ int qio_channel_writev_full_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int *fds, size_t nfds, +- Error **errp); ++ int flags, Error **errp); ++ ++/** ++ * qio_channel_flush: ++ * @ioc: the channel object ++ * @errp: pointer to a NULL-initialized error object ++ * ++ * Will block until every packet queued with ++ * qio_channel_writev_full() + QIO_CHANNEL_WRITE_FLAG_ZERO_COPY ++ * is sent, or return in case of any error. ++ * ++ * If not implemented, acts as a no-op, and returns 0. ++ * ++ * Returns -1 if any error is found, ++ * 1 if every send failed to use zero copy. ++ * 0 otherwise. ++ */ ++ ++int qio_channel_flush(QIOChannel *ioc, ++ Error **errp); + + #endif /* QIO_CHANNEL_H */ +diff --git a/io/channel-buffer.c b/io/channel-buffer.c +index baa4e2b089..bf52011be2 100644 +--- a/io/channel-buffer.c ++++ b/io/channel-buffer.c +@@ -81,6 +81,7 @@ static ssize_t qio_channel_buffer_writev(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp) + { + QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc); +diff --git a/io/channel-command.c b/io/channel-command.c +index b2a9e27138..5ff1691bad 100644 +--- a/io/channel-command.c ++++ b/io/channel-command.c +@@ -258,6 +258,7 @@ static ssize_t qio_channel_command_writev(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp) + { + QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); +diff --git a/io/channel-file.c b/io/channel-file.c +index c4bf799a80..348a48545e 100644 +--- a/io/channel-file.c ++++ b/io/channel-file.c +@@ -114,6 +114,7 @@ static ssize_t qio_channel_file_writev(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp) + { + QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc); +diff --git a/io/channel-socket.c b/io/channel-socket.c +index 606ec97cf7..bfbd64787e 100644 +--- a/io/channel-socket.c ++++ b/io/channel-socket.c +@@ -525,6 +525,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp) + { + QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); +@@ -620,6 +621,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp) + { + QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); +diff --git a/io/channel-tls.c b/io/channel-tls.c +index 2ae1b92fc0..4ce890a538 100644 +--- a/io/channel-tls.c ++++ b/io/channel-tls.c +@@ -301,6 +301,7 @@ static ssize_t qio_channel_tls_writev(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp) + { + QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); +diff --git a/io/channel-websock.c b/io/channel-websock.c +index 70889bb54d..035dd6075b 100644 +--- a/io/channel-websock.c ++++ b/io/channel-websock.c +@@ -1127,6 +1127,7 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp) + { + QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); +diff --git a/io/channel.c b/io/channel.c +index e8b019dc36..0640941ac5 100644 +--- a/io/channel.c ++++ b/io/channel.c +@@ -72,18 +72,32 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp) + { + QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); + +- if ((fds || nfds) && +- !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) { ++ if (fds || nfds) { ++ if (!qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) { ++ error_setg_errno(errp, EINVAL, ++ "Channel does not support file descriptor passing"); ++ return -1; ++ } ++ if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { ++ error_setg_errno(errp, EINVAL, ++ "Zero Copy does not support file descriptor passing"); ++ return -1; ++ } ++ } ++ ++ if ((flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) && ++ !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { + error_setg_errno(errp, EINVAL, +- "Channel does not support file descriptor passing"); ++ "Requested Zero Copy feature is not available"); + return -1; + } + +- return klass->io_writev(ioc, iov, niov, fds, nfds, errp); ++ return klass->io_writev(ioc, iov, niov, fds, nfds, flags, errp); + } + + +@@ -217,14 +231,14 @@ int qio_channel_writev_all(QIOChannel *ioc, + size_t niov, + Error **errp) + { +- return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, errp); ++ return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, 0, errp); + } + + int qio_channel_writev_full_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int *fds, size_t nfds, +- Error **errp) ++ int flags, Error **errp) + { + int ret = -1; + struct iovec *local_iov = g_new(struct iovec, niov); +@@ -237,8 +251,10 @@ int qio_channel_writev_full_all(QIOChannel *ioc, + + while (nlocal_iov > 0) { + ssize_t len; +- len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds, nfds, +- errp); ++ ++ len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds, ++ nfds, flags, errp); ++ + if (len == QIO_CHANNEL_ERR_BLOCK) { + if (qemu_in_coroutine()) { + qio_channel_yield(ioc, G_IO_OUT); +@@ -277,7 +293,7 @@ ssize_t qio_channel_writev(QIOChannel *ioc, + size_t niov, + Error **errp) + { +- return qio_channel_writev_full(ioc, iov, niov, NULL, 0, errp); ++ return qio_channel_writev_full(ioc, iov, niov, NULL, 0, 0, errp); + } + + +@@ -297,7 +313,7 @@ ssize_t qio_channel_write(QIOChannel *ioc, + Error **errp) + { + struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen }; +- return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, errp); ++ return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, 0, errp); + } + + +@@ -473,6 +489,19 @@ off_t qio_channel_io_seek(QIOChannel *ioc, + return klass->io_seek(ioc, offset, whence, errp); + } + ++int qio_channel_flush(QIOChannel *ioc, ++ Error **errp) ++{ ++ QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); ++ ++ if (!klass->io_flush || ++ !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { ++ return 0; ++ } ++ ++ return klass->io_flush(ioc, errp); ++} ++ + + static void qio_channel_restart_read(void *opaque) + { +diff --git a/migration/rdma.c b/migration/rdma.c +index f5d3bbe7e9..54acd2000e 100644 +--- a/migration/rdma.c ++++ b/migration/rdma.c +@@ -2833,6 +2833,7 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, + size_t niov, + int *fds, + size_t nfds, ++ int flags, + Error **errp) + { + QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); +diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c +index 451c7631b7..3be52a98d5 100644 +--- a/scsi/pr-manager-helper.c ++++ b/scsi/pr-manager-helper.c +@@ -77,7 +77,7 @@ static int pr_manager_helper_write(PRManagerHelper *pr_mgr, + iov.iov_base = (void *)buf; + iov.iov_len = sz; + n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1, +- nfds ? &fd : NULL, nfds, errp); ++ nfds ? &fd : NULL, nfds, 0, errp); + + if (n_written <= 0) { + assert(n_written != QIO_CHANNEL_ERR_BLOCK); +diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c +index c49eec1f03..6713886d02 100644 +--- a/tests/unit/test-io-channel-socket.c ++++ b/tests/unit/test-io-channel-socket.c +@@ -444,6 +444,7 @@ static void test_io_channel_unix_fd_pass(void) + G_N_ELEMENTS(iosend), + fdsend, + G_N_ELEMENTS(fdsend), ++ 0, + &error_abort); + + qio_channel_readv_full(dst, +-- +2.35.3 + diff --git a/kvm-QIOChannelSocket-Add-support-for-MSG_ZEROCOPY-IPV6.patch b/kvm-QIOChannelSocket-Add-support-for-MSG_ZEROCOPY-IPV6.patch new file mode 100644 index 0000000..0dd4a82 --- /dev/null +++ b/kvm-QIOChannelSocket-Add-support-for-MSG_ZEROCOPY-IPV6.patch @@ -0,0 +1,56 @@ +From f81698b323294b330a5dfb7b9eabff025596bbde Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Thu, 4 Aug 2022 04:10:43 -0300 +Subject: [PATCH 34/34] QIOChannelSocket: Add support for MSG_ZEROCOPY + IPV6 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [34/34] 549d876ec7108bd11d01754bd1b893ba3e79deb9 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +For using MSG_ZEROCOPY, there are two steps: +1 - io_writev() the packet, which enqueues the packet for sending, and +2 - io_flush(), which gets confirmation that all packets got correctly sent + +Currently, if MSG_ZEROCOPY is used to send packets over IPV6, no error will +be reported in (1), but it will fail in the first time (2) happens. + +This happens because (2) currently checks for cmsg_level & cmsg_type +associated with IPV4 only, before reporting any error. + +Add checks for cmsg_level & cmsg_type associated with IPV6, and thus enable +support for MSG_ZEROCOPY + IPV6 + +Fixes: 2bc58ffc29 ("QIOChannelSocket: Implement io_writev zero copy flag & io_flush for CONFIG_LINUX") +Signed-off-by: Leonardo Bras +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 5258a7e2c0677d16e9e1d06845f60171adf0b290) +Signed-off-by: Leonardo Bras +--- + io/channel-socket.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/io/channel-socket.c b/io/channel-socket.c +index cf0d67c51b..6010ad7017 100644 +--- a/io/channel-socket.c ++++ b/io/channel-socket.c +@@ -747,8 +747,8 @@ static int qio_channel_socket_flush(QIOChannel *ioc, + } + + cm = CMSG_FIRSTHDR(&msg); +- if (cm->cmsg_level != SOL_IP && +- cm->cmsg_type != IP_RECVERR) { ++ if (cm->cmsg_level != SOL_IP && cm->cmsg_type != IP_RECVERR && ++ cm->cmsg_level != SOL_IPV6 && cm->cmsg_type != IPV6_RECVERR) { + error_setg_errno(errp, EPROTOTYPE, + "Wrong cmsg in errqueue"); + return -1; +-- +2.35.3 + diff --git a/kvm-QIOChannelSocket-Fix-zero-copy-flush-returning-code-.patch b/kvm-QIOChannelSocket-Fix-zero-copy-flush-returning-code-.patch new file mode 100644 index 0000000..4c25590 --- /dev/null +++ b/kvm-QIOChannelSocket-Fix-zero-copy-flush-returning-code-.patch @@ -0,0 +1,65 @@ +From 9995a5367d511f8597e4006841853eb9b5888065 Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Mon, 11 Jul 2022 18:11:11 -0300 +Subject: [PATCH 29/34] QIOChannelSocket: Fix zero-copy flush returning code 1 + when nothing sent +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [29/34] d383ee721a8b57a4c3b70e1307cbf7db9e22d395 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +If flush is called when no buffer was sent with MSG_ZEROCOPY, it currently +returns 1. This return code should be used only when Linux fails to use +MSG_ZEROCOPY on a lot of sendmsg(). + +Fix this by returning early from flush if no sendmsg(...,MSG_ZEROCOPY) +was attempted. + +Fixes: 2bc58ffc2926 ("QIOChannelSocket: Implement io_writev zero copy flag & io_flush for CONFIG_LINUX") +Signed-off-by: Leonardo Bras +Reviewed-by: Daniel P. Berrangé +Acked-by: Daniel P. Berrangé +Reviewed-by: Juan Quintela +Reviewed-by: Peter Xu +Message-Id: <20220711211112.18951-2-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 927f93e099c4f9184e60a1bc61624ac2d04d0223) +Signed-off-by: Leonardo Bras +--- + io/channel-socket.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/io/channel-socket.c b/io/channel-socket.c +index df858da924..cf0d67c51b 100644 +--- a/io/channel-socket.c ++++ b/io/channel-socket.c +@@ -717,12 +717,18 @@ static int qio_channel_socket_flush(QIOChannel *ioc, + struct cmsghdr *cm; + char control[CMSG_SPACE(sizeof(*serr))]; + int received; +- int ret = 1; ++ int ret; ++ ++ if (sioc->zero_copy_queued == sioc->zero_copy_sent) { ++ return 0; ++ } + + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + memset(control, 0, sizeof(control)); + ++ ret = 1; ++ + while (sioc->zero_copy_sent < sioc->zero_copy_queued) { + received = recvmsg(sioc->fd, &msg, MSG_ERRQUEUE); + if (received < 0) { +-- +2.35.3 + diff --git a/kvm-QIOChannelSocket-Fix-zero-copy-send-so-socket-flush-.patch b/kvm-QIOChannelSocket-Fix-zero-copy-send-so-socket-flush-.patch new file mode 100644 index 0000000..cab53b4 --- /dev/null +++ b/kvm-QIOChannelSocket-Fix-zero-copy-send-so-socket-flush-.patch @@ -0,0 +1,58 @@ +From 9a4ecf0b3cfccd31a1d41716e3a4249a1d53455c Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Mon, 20 Jun 2022 02:39:43 -0300 +Subject: [PATCH 25/34] QIOChannelSocket: Fix zero-copy send so socket flush + works +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [25/34] cf8dc62075bc8b9aa2621315842a2b2458e9cd82 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Somewhere between v6 and v7 the of the zero-copy-send patchset a crucial +part of the flushing mechanism got missing: incrementing zero_copy_queued. + +Without that, the flushing interface becomes a no-op, and there is no +guarantee the buffer is really sent. + +This can go as bad as causing a corruption in RAM during migration. + +Fixes: 2bc58ffc2926 ("QIOChannelSocket: Implement io_writev zero copy flag & io_flush for CONFIG_LINUX") +Reported-by: 徐闯 +Signed-off-by: Leonardo Bras +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Peter Xu +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 4f5a09714c983a3471fd12e3c7f3196e95c650c1) +Signed-off-by: Leonardo Bras +--- + io/channel-socket.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/io/channel-socket.c b/io/channel-socket.c +index 7d37b39de7..df858da924 100644 +--- a/io/channel-socket.c ++++ b/io/channel-socket.c +@@ -612,6 +612,11 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, + "Unable to write to socket"); + return -1; + } ++ ++ if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { ++ sioc->zero_copy_queued++; ++ } ++ + return ret; + } + #else /* WIN32 */ +-- +2.35.3 + diff --git a/kvm-QIOChannelSocket-Implement-io_writev-zero-copy-flag-.patch b/kvm-QIOChannelSocket-Implement-io_writev-zero-copy-flag-.patch new file mode 100644 index 0000000..a86096d --- /dev/null +++ b/kvm-QIOChannelSocket-Implement-io_writev-zero-copy-flag-.patch @@ -0,0 +1,249 @@ +From 118f6f61c9ca27bb112d1e39367510d2a45a72fb Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Wed, 18 May 2022 02:52:25 -0300 +Subject: [PATCH 18/34] QIOChannelSocket: Implement io_writev zero copy flag & + io_flush for CONFIG_LINUX +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [18/34] b7f50e8485dc5e01c69b2070915592b28bdafde6 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +For CONFIG_LINUX, implement the new zero copy flag and the optional callback +io_flush on QIOChannelSocket, but enables it only when MSG_ZEROCOPY +feature is available in the host kernel, which is checked on +qio_channel_socket_connect_sync() + +qio_channel_socket_flush() was implemented by counting how many times +sendmsg(...,MSG_ZEROCOPY) was successfully called, and then reading the +socket's error queue, in order to find how many of them finished sending. +Flush will loop until those counters are the same, or until some error occurs. + +Notes on using writev() with QIO_CHANNEL_WRITE_FLAG_ZERO_COPY: +1: Buffer +- As MSG_ZEROCOPY tells the kernel to use the same user buffer to avoid copying, +some caution is necessary to avoid overwriting any buffer before it's sent. +If something like this happen, a newer version of the buffer may be sent instead. +- If this is a problem, it's recommended to call qio_channel_flush() before freeing +or re-using the buffer. + +2: Locked memory +- When using MSG_ZERCOCOPY, the buffer memory will be locked after queued, and +unlocked after it's sent. +- Depending on the size of each buffer, and how often it's sent, it may require +a larger amount of locked memory than usually available to non-root user. +- If the required amount of locked memory is not available, writev_zero_copy +will return an error, which can abort an operation like migration, +- Because of this, when an user code wants to add zero copy as a feature, it +requires a mechanism to disable it, so it can still be accessible to less +privileged users. + +Signed-off-by: Leonardo Bras +Reviewed-by: Peter Xu +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Juan Quintela +Message-Id: <20220513062836.965425-4-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 2bc58ffc2926a4efdd03edfb5909861fefc68c3d) +Signed-off-by: Leonardo Bras +--- + include/io/channel-socket.h | 2 + + io/channel-socket.c | 116 ++++++++++++++++++++++++++++++++++-- + 2 files changed, 114 insertions(+), 4 deletions(-) + +diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h +index e747e63514..513c428fe4 100644 +--- a/include/io/channel-socket.h ++++ b/include/io/channel-socket.h +@@ -47,6 +47,8 @@ struct QIOChannelSocket { + socklen_t localAddrLen; + struct sockaddr_storage remoteAddr; + socklen_t remoteAddrLen; ++ ssize_t zero_copy_queued; ++ ssize_t zero_copy_sent; + }; + + +diff --git a/io/channel-socket.c b/io/channel-socket.c +index bfbd64787e..38a46ba213 100644 +--- a/io/channel-socket.c ++++ b/io/channel-socket.c +@@ -26,6 +26,14 @@ + #include "io/channel-watch.h" + #include "trace.h" + #include "qapi/clone-visitor.h" ++#ifdef CONFIG_LINUX ++#include ++#include ++ ++#if (defined(MSG_ZEROCOPY) && defined(SO_ZEROCOPY)) ++#define QEMU_MSG_ZEROCOPY ++#endif ++#endif + + #define SOCKET_MAX_FDS 16 + +@@ -55,6 +63,8 @@ qio_channel_socket_new(void) + + sioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET)); + sioc->fd = -1; ++ sioc->zero_copy_queued = 0; ++ sioc->zero_copy_sent = 0; + + ioc = QIO_CHANNEL(sioc); + qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); +@@ -154,6 +164,16 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc, + return -1; + } + ++#ifdef QEMU_MSG_ZEROCOPY ++ int ret, v = 1; ++ ret = setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &v, sizeof(v)); ++ if (ret == 0) { ++ /* Zero copy available on host */ ++ qio_channel_set_feature(QIO_CHANNEL(ioc), ++ QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY); ++ } ++#endif ++ + return 0; + } + +@@ -534,6 +554,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, + char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)]; + size_t fdsize = sizeof(int) * nfds; + struct cmsghdr *cmsg; ++ int sflags = 0; + + memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)); + +@@ -558,15 +579,31 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, + memcpy(CMSG_DATA(cmsg), fds, fdsize); + } + ++#ifdef QEMU_MSG_ZEROCOPY ++ if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { ++ sflags = MSG_ZEROCOPY; ++ } ++#endif ++ + retry: +- ret = sendmsg(sioc->fd, &msg, 0); ++ ret = sendmsg(sioc->fd, &msg, sflags); + if (ret <= 0) { +- if (errno == EAGAIN) { ++ switch (errno) { ++ case EAGAIN: + return QIO_CHANNEL_ERR_BLOCK; +- } +- if (errno == EINTR) { ++ case EINTR: + goto retry; ++#ifdef QEMU_MSG_ZEROCOPY ++ case ENOBUFS: ++ if (sflags & MSG_ZEROCOPY) { ++ error_setg_errno(errp, errno, ++ "Process can't lock enough memory for using MSG_ZEROCOPY"); ++ return -1; ++ } ++ break; ++#endif + } ++ + error_setg_errno(errp, errno, + "Unable to write to socket"); + return -1; +@@ -660,6 +697,74 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, + } + #endif /* WIN32 */ + ++ ++#ifdef QEMU_MSG_ZEROCOPY ++static int qio_channel_socket_flush(QIOChannel *ioc, ++ Error **errp) ++{ ++ QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); ++ struct msghdr msg = {}; ++ struct sock_extended_err *serr; ++ struct cmsghdr *cm; ++ char control[CMSG_SPACE(sizeof(*serr))]; ++ int received; ++ int ret = 1; ++ ++ msg.msg_control = control; ++ msg.msg_controllen = sizeof(control); ++ memset(control, 0, sizeof(control)); ++ ++ while (sioc->zero_copy_sent < sioc->zero_copy_queued) { ++ received = recvmsg(sioc->fd, &msg, MSG_ERRQUEUE); ++ if (received < 0) { ++ switch (errno) { ++ case EAGAIN: ++ /* Nothing on errqueue, wait until something is available */ ++ qio_channel_wait(ioc, G_IO_ERR); ++ continue; ++ case EINTR: ++ continue; ++ default: ++ error_setg_errno(errp, errno, ++ "Unable to read errqueue"); ++ return -1; ++ } ++ } ++ ++ cm = CMSG_FIRSTHDR(&msg); ++ if (cm->cmsg_level != SOL_IP && ++ cm->cmsg_type != IP_RECVERR) { ++ error_setg_errno(errp, EPROTOTYPE, ++ "Wrong cmsg in errqueue"); ++ return -1; ++ } ++ ++ serr = (void *) CMSG_DATA(cm); ++ if (serr->ee_errno != SO_EE_ORIGIN_NONE) { ++ error_setg_errno(errp, serr->ee_errno, ++ "Error on socket"); ++ return -1; ++ } ++ if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) { ++ error_setg_errno(errp, serr->ee_origin, ++ "Error not from zero copy"); ++ return -1; ++ } ++ ++ /* No errors, count successfully finished sendmsg()*/ ++ sioc->zero_copy_sent += serr->ee_data - serr->ee_info + 1; ++ ++ /* If any sendmsg() succeeded using zero copy, return 0 at the end */ ++ if (serr->ee_code != SO_EE_CODE_ZEROCOPY_COPIED) { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++#endif /* QEMU_MSG_ZEROCOPY */ ++ + static int + qio_channel_socket_set_blocking(QIOChannel *ioc, + bool enabled, +@@ -789,6 +894,9 @@ static void qio_channel_socket_class_init(ObjectClass *klass, + ioc_klass->io_set_delay = qio_channel_socket_set_delay; + ioc_klass->io_create_watch = qio_channel_socket_create_watch; + ioc_klass->io_set_aio_fd_handler = qio_channel_socket_set_aio_fd_handler; ++#ifdef QEMU_MSG_ZEROCOPY ++ ioc_klass->io_flush = qio_channel_socket_flush; ++#endif + } + + static const TypeInfo qio_channel_socket_info = { +-- +2.35.3 + diff --git a/kvm-QIOChannelSocket-Introduce-assert-and-reduce-ifdefs-.patch b/kvm-QIOChannelSocket-Introduce-assert-and-reduce-ifdefs-.patch new file mode 100644 index 0000000..a63f0ee --- /dev/null +++ b/kvm-QIOChannelSocket-Introduce-assert-and-reduce-ifdefs-.patch @@ -0,0 +1,82 @@ +From f1e21f3d46e1481a5cdd2f297831742b5b2d8ecf Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Mon, 20 Jun 2022 02:39:42 -0300 +Subject: [PATCH 24/34] QIOChannelSocket: Introduce assert and reduce ifdefs to + improve readability +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [24/34] 0dcd79e1e89c881e56c3ef2e421910176b03d881 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +During implementation of MSG_ZEROCOPY feature, a lot of #ifdefs were +introduced, particularly at qio_channel_socket_writev(). + +Rewrite some of those changes so it's easier to read. + +Also, introduce an assert to help detect incorrect zero-copy usage is when +it's disabled on build. + +Signed-off-by: Leonardo Bras +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Juan Quintela +Reviewed-by: Peter Xu +Signed-off-by: Juan Quintela +Signed-off-by: Dr. David Alan Gilbert + dgilbert: Fixed up thinko'd g_assert_unreachable->g_assert_not_reached +(cherry picked from commit 803ca43e4c7fcf32f9f68c118301ccd0c83ece3f) +Signed-off-by: Leonardo Bras +--- + io/channel-socket.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/io/channel-socket.c b/io/channel-socket.c +index 38a46ba213..7d37b39de7 100644 +--- a/io/channel-socket.c ++++ b/io/channel-socket.c +@@ -579,11 +579,17 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, + memcpy(CMSG_DATA(cmsg), fds, fdsize); + } + +-#ifdef QEMU_MSG_ZEROCOPY + if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { ++#ifdef QEMU_MSG_ZEROCOPY + sflags = MSG_ZEROCOPY; +- } ++#else ++ /* ++ * We expect QIOChannel class entry point to have ++ * blocked this code path already ++ */ ++ g_assert_not_reached(); + #endif ++ } + + retry: + ret = sendmsg(sioc->fd, &msg, sflags); +@@ -593,15 +599,13 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc, + return QIO_CHANNEL_ERR_BLOCK; + case EINTR: + goto retry; +-#ifdef QEMU_MSG_ZEROCOPY + case ENOBUFS: +- if (sflags & MSG_ZEROCOPY) { ++ if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { + error_setg_errno(errp, errno, + "Process can't lock enough memory for using MSG_ZEROCOPY"); + return -1; + } + break; +-#endif + } + + error_setg_errno(errp, errno, +-- +2.35.3 + diff --git a/kvm-linux-aio-explain-why-max-batch-is-checked-in-laio_i.patch b/kvm-linux-aio-explain-why-max-batch-is-checked-in-laio_i.patch new file mode 100644 index 0000000..1266128 --- /dev/null +++ b/kvm-linux-aio-explain-why-max-batch-is-checked-in-laio_i.patch @@ -0,0 +1,49 @@ +From 286d9e4512a3b7ab6e2a1ce6b4a872e5defb0ffe Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Thu, 9 Jun 2022 17:47:12 +0100 +Subject: [PATCH 2/2] linux-aio: explain why max batch is checked in + laio_io_unplug() + +RH-Author: Stefan Hajnoczi +RH-MergeRequest: 209: linux-aio: fix unbalanced plugged counter in laio_io_unplug() +RH-Commit: [2/2] c6194a9929e7e3807c5402b5364ab9dc2edf420c +RH-Bugzilla: 2109570 +RH-Acked-by: Hanna Reitz +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefano Garzarella + +It may not be obvious why laio_io_unplug() checks max batch. I discussed +this with Stefano and have added a comment summarizing the reason. + +Cc: Stefano Garzarella +Cc: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +Reviewed-by: Stefano Garzarella +Message-id: 20220609164712.1539045-3-stefanha@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 99b969fbe105117f5af6060d3afef40ca39cc9c1) +Signed-off-by: Stefan Hajnoczi +--- + block/linux-aio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/block/linux-aio.c b/block/linux-aio.c +index 77f17ad596..85650c4222 100644 +--- a/block/linux-aio.c ++++ b/block/linux-aio.c +@@ -362,6 +362,12 @@ void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s, + assert(s->io_q.plugged); + s->io_q.plugged--; + ++ /* ++ * Why max batch checking is performed here: ++ * Another BDS may have queued requests with a higher dev_max_batch and ++ * therefore in_queue could now exceed our dev_max_batch. Re-check the max ++ * batch so we can honor our device's dev_max_batch. ++ */ + if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch) || + (!s->io_q.plugged && + !s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending))) { +-- +2.35.3 + diff --git a/kvm-linux-aio-fix-unbalanced-plugged-counter-in-laio_io_.patch b/kvm-linux-aio-fix-unbalanced-plugged-counter-in-laio_io_.patch new file mode 100644 index 0000000..d01fe33 --- /dev/null +++ b/kvm-linux-aio-fix-unbalanced-plugged-counter-in-laio_io_.patch @@ -0,0 +1,56 @@ +From ad1844e7e2294fa71bc07f9d1da6d10150ba9607 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Thu, 9 Jun 2022 17:47:11 +0100 +Subject: [PATCH 1/2] linux-aio: fix unbalanced plugged counter in + laio_io_unplug() + +RH-Author: Stefan Hajnoczi +RH-MergeRequest: 209: linux-aio: fix unbalanced plugged counter in laio_io_unplug() +RH-Commit: [1/2] 3a73bdb8237cf99c5264a6e1caac632494412953 +RH-Bugzilla: 2109570 +RH-Acked-by: Hanna Reitz +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefano Garzarella + +Every laio_io_plug() call has a matching laio_io_unplug() call. There is +a plugged counter that tracks the number of levels of plugging and +allows for nesting. + +The plugged counter must reflect the balance between laio_io_plug() and +laio_io_unplug() calls accurately. Otherwise I/O stalls occur since +io_submit(2) calls are skipped while plugged. + +Reported-by: Nikolay Tenev +Signed-off-by: Stefan Hajnoczi +Reviewed-by: Stefano Garzarella +Message-id: 20220609164712.1539045-2-stefanha@redhat.com +Cc: Stefano Garzarella +Fixes: 68d7946648 ("linux-aio: add `dev_max_batch` parameter to laio_io_unplug()") +[Stefano Garzarella suggested adding a Fixes tag. +--Stefan] +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit f387cac5af030a58ac5a0dacf64cab5e5a4fe5c7) +Signed-off-by: Stefan Hajnoczi +--- + block/linux-aio.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/block/linux-aio.c b/block/linux-aio.c +index f53ae72e21..77f17ad596 100644 +--- a/block/linux-aio.c ++++ b/block/linux-aio.c +@@ -360,8 +360,10 @@ void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s, + uint64_t dev_max_batch) + { + assert(s->io_q.plugged); ++ s->io_q.plugged--; ++ + if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch) || +- (--s->io_q.plugged == 0 && ++ (!s->io_q.plugged && + !s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending))) { + ioq_submit(s); + } +-- +2.35.3 + diff --git a/kvm-migration-Add-migrate_use_tls-helper.patch b/kvm-migration-Add-migrate_use_tls-helper.patch new file mode 100644 index 0000000..338ddb8 --- /dev/null +++ b/kvm-migration-Add-migrate_use_tls-helper.patch @@ -0,0 +1,106 @@ +From c7ff8b8916f28928185bbe937a5701e1770ab5f4 Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Wed, 18 May 2022 02:52:25 -0300 +Subject: [PATCH 20/34] migration: Add migrate_use_tls() helper +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [20/34] 41a1ec2f4ef5c873ed80cf055bb5a582e2273495 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +A lot of places check parameters.tls_creds in order to evaluate if TLS is +in use, and sometimes call migrate_get_current() just for that test. + +Add new helper function migrate_use_tls() in order to simplify testing +for TLS usage. + +Signed-off-by: Leonardo Bras +Reviewed-by: Juan Quintela +Reviewed-by: Peter Xu +Reviewed-by: Daniel P. Berrangé +Message-Id: <20220513062836.965425-6-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit d2fafb6a6814a8998607d0baf691265032996a0f) +Signed-off-by: Leonardo Bras +--- + migration/channel.c | 3 +-- + migration/migration.c | 9 +++++++++ + migration/migration.h | 1 + + migration/multifd.c | 5 +---- + 4 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/migration/channel.c b/migration/channel.c +index c4fc000a1a..086b5c0d8b 100644 +--- a/migration/channel.c ++++ b/migration/channel.c +@@ -38,8 +38,7 @@ void migration_channel_process_incoming(QIOChannel *ioc) + trace_migration_set_incoming_channel( + ioc, object_get_typename(OBJECT(ioc))); + +- if (s->parameters.tls_creds && +- *s->parameters.tls_creds && ++ if (migrate_use_tls() && + !object_dynamic_cast(OBJECT(ioc), + TYPE_QIO_CHANNEL_TLS)) { + migration_tls_channel_process_incoming(s, ioc, &local_err); +diff --git a/migration/migration.c b/migration/migration.c +index b0fc3f68bd..8e28f2ee41 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -2568,6 +2568,15 @@ bool migrate_use_zero_copy_send(void) + } + #endif + ++int migrate_use_tls(void) ++{ ++ MigrationState *s; ++ ++ s = migrate_get_current(); ++ ++ return s->parameters.tls_creds && *s->parameters.tls_creds; ++} ++ + int migrate_use_xbzrle(void) + { + MigrationState *s; +diff --git a/migration/migration.h b/migration/migration.h +index 908098939f..9396b7e90a 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -344,6 +344,7 @@ bool migrate_use_zero_copy_send(void); + #else + #define migrate_use_zero_copy_send() (false) + #endif ++int migrate_use_tls(void); + int migrate_use_xbzrle(void); + uint64_t migrate_xbzrle_cache_size(void); + bool migrate_colo_enabled(void); +diff --git a/migration/multifd.c b/migration/multifd.c +index 3725226400..e53811f04a 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -789,14 +789,11 @@ static bool multifd_channel_connect(MultiFDSendParams *p, + QIOChannel *ioc, + Error *error) + { +- MigrationState *s = migrate_get_current(); +- + trace_multifd_set_outgoing_channel( + ioc, object_get_typename(OBJECT(ioc)), p->tls_hostname, error); + + if (!error) { +- if (s->parameters.tls_creds && +- *s->parameters.tls_creds && ++ if (migrate_use_tls() && + !object_dynamic_cast(OBJECT(ioc), + TYPE_QIO_CHANNEL_TLS)) { + multifd_tls_channel_connect(p, ioc, &error); +-- +2.35.3 + diff --git a/kvm-migration-Add-zero-copy-send-parameter-for-QMP-HMP-f.patch b/kvm-migration-Add-zero-copy-send-parameter-for-QMP-HMP-f.patch new file mode 100644 index 0000000..bae187a --- /dev/null +++ b/kvm-migration-Add-zero-copy-send-parameter-for-QMP-HMP-f.patch @@ -0,0 +1,250 @@ +From c71da4b1c1c4cf089f74394ffc596d0fd0235800 Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Wed, 18 May 2022 02:52:25 -0300 +Subject: [PATCH 19/34] migration: Add zero-copy-send parameter for QMP/HMP for + Linux +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [19/34] 96e64f4beb41ffc6cf34341114666598d3d53aeb +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Add property that allows zero-copy migration of memory pages +on the sending side, and also includes a helper function +migrate_use_zero_copy_send() to check if it's enabled. + +No code is introduced to actually do the migration, but it allow +future implementations to enable/disable this feature. + +On non-Linux builds this parameter is compiled-out. + +Signed-off-by: Leonardo Bras +Reviewed-by: Peter Xu +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Juan Quintela +Acked-by: Markus Armbruster +Message-Id: <20220513062836.965425-5-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit abb6295b3ace5d17c3a65936913fc346616dbf14) +Signed-off-by: Leonardo Bras +--- + migration/migration.c | 32 ++++++++++++++++++++++++++++++++ + migration/migration.h | 5 +++++ + migration/socket.c | 11 +++++++++-- + monitor/hmp-cmds.c | 6 ++++++ + qapi/migration.json | 24 ++++++++++++++++++++++++ + 5 files changed, 76 insertions(+), 2 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 8a13294da6..b0fc3f68bd 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -888,6 +888,10 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) + params->multifd_zlib_level = s->parameters.multifd_zlib_level; + params->has_multifd_zstd_level = true; + params->multifd_zstd_level = s->parameters.multifd_zstd_level; ++#ifdef CONFIG_LINUX ++ params->has_zero_copy_send = true; ++ params->zero_copy_send = s->parameters.zero_copy_send; ++#endif + params->has_xbzrle_cache_size = true; + params->xbzrle_cache_size = s->parameters.xbzrle_cache_size; + params->has_max_postcopy_bandwidth = true; +@@ -1541,6 +1545,11 @@ static void migrate_params_test_apply(MigrateSetParameters *params, + if (params->has_multifd_compression) { + dest->multifd_compression = params->multifd_compression; + } ++#ifdef CONFIG_LINUX ++ if (params->has_zero_copy_send) { ++ dest->zero_copy_send = params->zero_copy_send; ++ } ++#endif + if (params->has_xbzrle_cache_size) { + dest->xbzrle_cache_size = params->xbzrle_cache_size; + } +@@ -1653,6 +1662,11 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) + if (params->has_multifd_compression) { + s->parameters.multifd_compression = params->multifd_compression; + } ++#ifdef CONFIG_LINUX ++ if (params->has_zero_copy_send) { ++ s->parameters.zero_copy_send = params->zero_copy_send; ++ } ++#endif + if (params->has_xbzrle_cache_size) { + s->parameters.xbzrle_cache_size = params->xbzrle_cache_size; + xbzrle_cache_resize(params->xbzrle_cache_size, errp); +@@ -2543,6 +2557,17 @@ int migrate_multifd_zstd_level(void) + return s->parameters.multifd_zstd_level; + } + ++#ifdef CONFIG_LINUX ++bool migrate_use_zero_copy_send(void) ++{ ++ MigrationState *s; ++ ++ s = migrate_get_current(); ++ ++ return s->parameters.zero_copy_send; ++} ++#endif ++ + int migrate_use_xbzrle(void) + { + MigrationState *s; +@@ -4193,6 +4218,10 @@ static Property migration_properties[] = { + DEFINE_PROP_UINT8("multifd-zstd-level", MigrationState, + parameters.multifd_zstd_level, + DEFAULT_MIGRATE_MULTIFD_ZSTD_LEVEL), ++#ifdef CONFIG_LINUX ++ DEFINE_PROP_BOOL("zero_copy_send", MigrationState, ++ parameters.zero_copy_send, false), ++#endif + DEFINE_PROP_SIZE("xbzrle-cache-size", MigrationState, + parameters.xbzrle_cache_size, + DEFAULT_MIGRATE_XBZRLE_CACHE_SIZE), +@@ -4290,6 +4319,9 @@ static void migration_instance_init(Object *obj) + params->has_multifd_compression = true; + params->has_multifd_zlib_level = true; + params->has_multifd_zstd_level = true; ++#ifdef CONFIG_LINUX ++ params->has_zero_copy_send = true; ++#endif + params->has_xbzrle_cache_size = true; + params->has_max_postcopy_bandwidth = true; + params->has_max_cpu_throttle = true; +diff --git a/migration/migration.h b/migration/migration.h +index d016cedd9d..908098939f 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -339,6 +339,11 @@ MultiFDCompression migrate_multifd_compression(void); + int migrate_multifd_zlib_level(void); + int migrate_multifd_zstd_level(void); + ++#ifdef CONFIG_LINUX ++bool migrate_use_zero_copy_send(void); ++#else ++#define migrate_use_zero_copy_send() (false) ++#endif + int migrate_use_xbzrle(void); + uint64_t migrate_xbzrle_cache_size(void); + bool migrate_colo_enabled(void); +diff --git a/migration/socket.c b/migration/socket.c +index 05705a32d8..3754d8f72c 100644 +--- a/migration/socket.c ++++ b/migration/socket.c +@@ -74,9 +74,16 @@ static void socket_outgoing_migration(QIOTask *task, + + if (qio_task_propagate_error(task, &err)) { + trace_migration_socket_outgoing_error(error_get_pretty(err)); +- } else { +- trace_migration_socket_outgoing_connected(data->hostname); ++ goto out; + } ++ ++ trace_migration_socket_outgoing_connected(data->hostname); ++ ++ if (migrate_use_zero_copy_send()) { ++ error_setg(&err, "Zero copy send not available in migration"); ++ } ++ ++out: + migration_channel_connect(data->s, sioc, data->hostname, err); + object_unref(OBJECT(sioc)); + } +diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c +index 2669156b28..e02da5008b 100644 +--- a/monitor/hmp-cmds.c ++++ b/monitor/hmp-cmds.c +@@ -1297,6 +1297,12 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) + p->has_multifd_zstd_level = true; + visit_type_uint8(v, param, &p->multifd_zstd_level, &err); + break; ++#ifdef CONFIG_LINUX ++ case MIGRATION_PARAMETER_ZERO_COPY_SEND: ++ p->has_zero_copy_send = true; ++ visit_type_bool(v, param, &p->zero_copy_send, &err); ++ break; ++#endif + case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE: + p->has_xbzrle_cache_size = true; + if (!visit_type_size(v, param, &cache_size, &err)) { +diff --git a/qapi/migration.json b/qapi/migration.json +index bbfd48cf0b..59b5c5780b 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -730,6 +730,13 @@ + # will consume more CPU. + # Defaults to 1. (Since 5.0) + # ++# @zero-copy-send: Controls behavior on sending memory pages on migration. ++# When true, enables a zero-copy mechanism for sending ++# memory pages, if host supports it. ++# Requires that QEMU be permitted to use locked memory ++# for guest RAM pages. ++# Defaults to false. (Since 7.1) ++# + # @block-bitmap-mapping: Maps block nodes and bitmaps on them to + # aliases for the purpose of dirty bitmap migration. Such + # aliases may for example be the corresponding names on the +@@ -769,6 +776,7 @@ + 'xbzrle-cache-size', 'max-postcopy-bandwidth', + 'max-cpu-throttle', 'multifd-compression', + 'multifd-zlib-level' ,'multifd-zstd-level', ++ { 'name': 'zero-copy-send', 'if' : 'CONFIG_LINUX'}, + 'block-bitmap-mapping' ] } + + ## +@@ -895,6 +903,13 @@ + # will consume more CPU. + # Defaults to 1. (Since 5.0) + # ++# @zero-copy-send: Controls behavior on sending memory pages on migration. ++# When true, enables a zero-copy mechanism for sending ++# memory pages, if host supports it. ++# Requires that QEMU be permitted to use locked memory ++# for guest RAM pages. ++# Defaults to false. (Since 7.1) ++# + # @block-bitmap-mapping: Maps block nodes and bitmaps on them to + # aliases for the purpose of dirty bitmap migration. Such + # aliases may for example be the corresponding names on the +@@ -949,6 +964,7 @@ + '*multifd-compression': 'MultiFDCompression', + '*multifd-zlib-level': 'uint8', + '*multifd-zstd-level': 'uint8', ++ '*zero-copy-send': { 'type': 'bool', 'if': 'CONFIG_LINUX' }, + '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } + + ## +@@ -1095,6 +1111,13 @@ + # will consume more CPU. + # Defaults to 1. (Since 5.0) + # ++# @zero-copy-send: Controls behavior on sending memory pages on migration. ++# When true, enables a zero-copy mechanism for sending ++# memory pages, if host supports it. ++# Requires that QEMU be permitted to use locked memory ++# for guest RAM pages. ++# Defaults to false. (Since 7.1) ++# + # @block-bitmap-mapping: Maps block nodes and bitmaps on them to + # aliases for the purpose of dirty bitmap migration. Such + # aliases may for example be the corresponding names on the +@@ -1147,6 +1170,7 @@ + '*multifd-compression': 'MultiFDCompression', + '*multifd-zlib-level': 'uint8', + '*multifd-zstd-level': 'uint8', ++ '*zero-copy-send': { 'type': 'bool', 'if': 'CONFIG_LINUX' }, + '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } + + ## +-- +2.35.3 + diff --git a/kvm-migration-All-this-fields-are-unsigned.patch b/kvm-migration-All-this-fields-are-unsigned.patch new file mode 100644 index 0000000..390ab62 --- /dev/null +++ b/kvm-migration-All-this-fields-are-unsigned.patch @@ -0,0 +1,329 @@ +From 4fead335ef5aca7c70296c082b0abc872e053d30 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:23 -0300 +Subject: [PATCH 10/34] migration: All this fields are unsigned +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [10/34] 59e3378a852a31a9942d1dd8255a9c08e442f53b +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +So printing it as %d is wrong. Notice that for the channel id, that +is an uint8_t, but I changed it anyways for consistency. + +Signed-off-by: Juan Quintela +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Peter Xu +(cherry picked from commit 04e114049406dbb69fc9043c795ddd28fdba31a6) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zlib.c | 20 ++++++++++---------- + migration/multifd-zstd.c | 24 ++++++++++++------------ + migration/multifd.c | 16 ++++++++-------- + migration/trace-events | 26 +++++++++++++------------- + 4 files changed, 43 insertions(+), 43 deletions(-) + +diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c +index a1950a4588..a987e4a26c 100644 +--- a/migration/multifd-zlib.c ++++ b/migration/multifd-zlib.c +@@ -52,7 +52,7 @@ static int zlib_send_setup(MultiFDSendParams *p, Error **errp) + zs->opaque = Z_NULL; + if (deflateInit(zs, migrate_multifd_zlib_level()) != Z_OK) { + g_free(z); +- error_setg(errp, "multifd %d: deflate init failed", p->id); ++ error_setg(errp, "multifd %u: deflate init failed", p->id); + return -1; + } + /* We will never have more than page_count pages */ +@@ -62,7 +62,7 @@ static int zlib_send_setup(MultiFDSendParams *p, Error **errp) + if (!z->zbuff) { + deflateEnd(&z->zs); + g_free(z); +- error_setg(errp, "multifd %d: out of memory for zbuff", p->id); ++ error_setg(errp, "multifd %u: out of memory for zbuff", p->id); + return -1; + } + p->data = z; +@@ -134,12 +134,12 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) + ret = deflate(zs, flush); + } while (ret == Z_OK && zs->avail_in && zs->avail_out); + if (ret == Z_OK && zs->avail_in) { +- error_setg(errp, "multifd %d: deflate failed to compress all input", ++ error_setg(errp, "multifd %u: deflate failed to compress all input", + p->id); + return -1; + } + if (ret != Z_OK) { +- error_setg(errp, "multifd %d: deflate returned %d instead of Z_OK", ++ error_setg(errp, "multifd %u: deflate returned %d instead of Z_OK", + p->id, ret); + return -1; + } +@@ -193,7 +193,7 @@ static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp) + zs->avail_in = 0; + zs->next_in = Z_NULL; + if (inflateInit(zs) != Z_OK) { +- error_setg(errp, "multifd %d: inflate init failed", p->id); ++ error_setg(errp, "multifd %u: inflate init failed", p->id); + return -1; + } + /* We will never have more than page_count pages */ +@@ -203,7 +203,7 @@ static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp) + z->zbuff = g_try_malloc(z->zbuff_len); + if (!z->zbuff) { + inflateEnd(zs); +- error_setg(errp, "multifd %d: out of memory for zbuff", p->id); ++ error_setg(errp, "multifd %u: out of memory for zbuff", p->id); + return -1; + } + return 0; +@@ -252,7 +252,7 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) + int i; + + if (flags != MULTIFD_FLAG_ZLIB) { +- error_setg(errp, "multifd %d: flags received %x flags expected %x", ++ error_setg(errp, "multifd %u: flags received %x flags expected %x", + p->id, flags, MULTIFD_FLAG_ZLIB); + return -1; + } +@@ -289,19 +289,19 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) + } while (ret == Z_OK && zs->avail_in + && (zs->total_out - start) < page_size); + if (ret == Z_OK && (zs->total_out - start) < page_size) { +- error_setg(errp, "multifd %d: inflate generated too few output", ++ error_setg(errp, "multifd %u: inflate generated too few output", + p->id); + return -1; + } + if (ret != Z_OK) { +- error_setg(errp, "multifd %d: inflate returned %d instead of Z_OK", ++ error_setg(errp, "multifd %u: inflate returned %d instead of Z_OK", + p->id, ret); + return -1; + } + } + out_size = zs->total_out - out_size; + if (out_size != expected_size) { +- error_setg(errp, "multifd %d: packet size received %d size expected %d", ++ error_setg(errp, "multifd %u: packet size received %u size expected %u", + p->id, out_size, expected_size); + return -1; + } +diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c +index d9ed42622b..2185a83eac 100644 +--- a/migration/multifd-zstd.c ++++ b/migration/multifd-zstd.c +@@ -56,7 +56,7 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp) + z->zcs = ZSTD_createCStream(); + if (!z->zcs) { + g_free(z); +- error_setg(errp, "multifd %d: zstd createCStream failed", p->id); ++ error_setg(errp, "multifd %u: zstd createCStream failed", p->id); + return -1; + } + +@@ -64,7 +64,7 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp) + if (ZSTD_isError(res)) { + ZSTD_freeCStream(z->zcs); + g_free(z); +- error_setg(errp, "multifd %d: initCStream failed with error %s", ++ error_setg(errp, "multifd %u: initCStream failed with error %s", + p->id, ZSTD_getErrorName(res)); + return -1; + } +@@ -75,7 +75,7 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp) + if (!z->zbuff) { + ZSTD_freeCStream(z->zcs); + g_free(z); +- error_setg(errp, "multifd %d: out of memory for zbuff", p->id); ++ error_setg(errp, "multifd %u: out of memory for zbuff", p->id); + return -1; + } + return 0; +@@ -146,12 +146,12 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) + } while (ret > 0 && (z->in.size - z->in.pos > 0) + && (z->out.size - z->out.pos > 0)); + if (ret > 0 && (z->in.size - z->in.pos > 0)) { +- error_setg(errp, "multifd %d: compressStream buffer too small", ++ error_setg(errp, "multifd %u: compressStream buffer too small", + p->id); + return -1; + } + if (ZSTD_isError(ret)) { +- error_setg(errp, "multifd %d: compressStream error %s", ++ error_setg(errp, "multifd %u: compressStream error %s", + p->id, ZSTD_getErrorName(ret)); + return -1; + } +@@ -201,7 +201,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp) + z->zds = ZSTD_createDStream(); + if (!z->zds) { + g_free(z); +- error_setg(errp, "multifd %d: zstd createDStream failed", p->id); ++ error_setg(errp, "multifd %u: zstd createDStream failed", p->id); + return -1; + } + +@@ -209,7 +209,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp) + if (ZSTD_isError(ret)) { + ZSTD_freeDStream(z->zds); + g_free(z); +- error_setg(errp, "multifd %d: initDStream failed with error %s", ++ error_setg(errp, "multifd %u: initDStream failed with error %s", + p->id, ZSTD_getErrorName(ret)); + return -1; + } +@@ -222,7 +222,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp) + if (!z->zbuff) { + ZSTD_freeDStream(z->zds); + g_free(z); +- error_setg(errp, "multifd %d: out of memory for zbuff", p->id); ++ error_setg(errp, "multifd %u: out of memory for zbuff", p->id); + return -1; + } + return 0; +@@ -270,7 +270,7 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp) + int i; + + if (flags != MULTIFD_FLAG_ZSTD) { +- error_setg(errp, "multifd %d: flags received %x flags expected %x", ++ error_setg(errp, "multifd %u: flags received %x flags expected %x", + p->id, flags, MULTIFD_FLAG_ZSTD); + return -1; + } +@@ -302,19 +302,19 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp) + } while (ret > 0 && (z->in.size - z->in.pos > 0) + && (z->out.pos < page_size)); + if (ret > 0 && (z->out.pos < page_size)) { +- error_setg(errp, "multifd %d: decompressStream buffer too small", ++ error_setg(errp, "multifd %u: decompressStream buffer too small", + p->id); + return -1; + } + if (ZSTD_isError(ret)) { +- error_setg(errp, "multifd %d: decompressStream returned %s", ++ error_setg(errp, "multifd %u: decompressStream returned %s", + p->id, ZSTD_getErrorName(ret)); + return ret; + } + out_size += z->out.pos; + } + if (out_size != expected_size) { +- error_setg(errp, "multifd %d: packet size received %d size expected %d", ++ error_setg(errp, "multifd %u: packet size received %u size expected %u", + p->id, out_size, expected_size); + return -1; + } +diff --git a/migration/multifd.c b/migration/multifd.c +index 0533da154a..d0d19470f9 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -148,7 +148,7 @@ static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp) + uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; + + if (flags != MULTIFD_FLAG_NOCOMP) { +- error_setg(errp, "multifd %d: flags received %x flags expected %x", ++ error_setg(errp, "multifd %u: flags received %x flags expected %x", + p->id, flags, MULTIFD_FLAG_NOCOMP); + return -1; + } +@@ -212,8 +212,8 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp) + } + + if (msg.version != MULTIFD_VERSION) { +- error_setg(errp, "multifd: received packet version %d " +- "expected %d", msg.version, MULTIFD_VERSION); ++ error_setg(errp, "multifd: received packet version %u " ++ "expected %u", msg.version, MULTIFD_VERSION); + return -1; + } + +@@ -229,8 +229,8 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp) + } + + if (msg.id > migrate_multifd_channels()) { +- error_setg(errp, "multifd: received channel version %d " +- "expected %d", msg.version, MULTIFD_VERSION); ++ error_setg(errp, "multifd: received channel version %u " ++ "expected %u", msg.version, MULTIFD_VERSION); + return -1; + } + +@@ -303,7 +303,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + packet->version = be32_to_cpu(packet->version); + if (packet->version != MULTIFD_VERSION) { + error_setg(errp, "multifd: received packet " +- "version %d and expected version %d", ++ "version %u and expected version %u", + packet->version, MULTIFD_VERSION); + return -1; + } +@@ -317,7 +317,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + */ + if (packet->pages_alloc > pages_max * 100) { + error_setg(errp, "multifd: received packet " +- "with size %d and expected a maximum size of %d", ++ "with size %u and expected a maximum size of %u", + packet->pages_alloc, pages_max * 100) ; + return -1; + } +@@ -333,7 +333,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + p->pages->num = be32_to_cpu(packet->pages_used); + if (p->pages->num > packet->pages_alloc) { + error_setg(errp, "multifd: received packet " +- "with %d pages and expected maximum pages are %d", ++ "with %u pages and expected maximum pages are %u", + p->pages->num, packet->pages_alloc) ; + return -1; + } +diff --git a/migration/trace-events b/migration/trace-events +index b48d873b8a..5172cb3b3d 100644 +--- a/migration/trace-events ++++ b/migration/trace-events +@@ -115,23 +115,23 @@ ram_write_tracking_ramblock_start(const char *block_id, size_t page_size, void * + ram_write_tracking_ramblock_stop(const char *block_id, size_t page_size, void *addr, size_t length) "%s: page_size: %zu addr: %p length: %zu" + + # multifd.c +-multifd_new_send_channel_async(uint8_t id) "channel %d" +-multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %d packet_num %" PRIu64 " pages %d flags 0x%x next packet size %d" +-multifd_recv_new_channel(uint8_t id) "channel %d" ++multifd_new_send_channel_async(uint8_t id) "channel %u" ++multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " pages %u flags 0x%x next packet size %u" ++multifd_recv_new_channel(uint8_t id) "channel %u" + multifd_recv_sync_main(long packet_num) "packet num %ld" +-multifd_recv_sync_main_signal(uint8_t id) "channel %d" +-multifd_recv_sync_main_wait(uint8_t id) "channel %d" ++multifd_recv_sync_main_signal(uint8_t id) "channel %u" ++multifd_recv_sync_main_wait(uint8_t id) "channel %u" + multifd_recv_terminate_threads(bool error) "error %d" +-multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %d packets %" PRIu64 " pages %" PRIu64 +-multifd_recv_thread_start(uint8_t id) "%d" +-multifd_send(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %d packet_num %" PRIu64 " pages %d flags 0x%x next packet size %d" +-multifd_send_error(uint8_t id) "channel %d" ++multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %u packets %" PRIu64 " pages %" PRIu64 ++multifd_recv_thread_start(uint8_t id) "%u" ++multifd_send(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " pages %u flags 0x%x next packet size %u" ++multifd_send_error(uint8_t id) "channel %u" + multifd_send_sync_main(long packet_num) "packet num %ld" +-multifd_send_sync_main_signal(uint8_t id) "channel %d" +-multifd_send_sync_main_wait(uint8_t id) "channel %d" ++multifd_send_sync_main_signal(uint8_t id) "channel %u" ++multifd_send_sync_main_wait(uint8_t id) "channel %u" + multifd_send_terminate_threads(bool error) "error %d" +-multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %d packets %" PRIu64 " pages %" PRIu64 +-multifd_send_thread_start(uint8_t id) "%d" ++multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %u packets %" PRIu64 " pages %" PRIu64 ++multifd_send_thread_start(uint8_t id) "%u" + multifd_tls_outgoing_handshake_start(void *ioc, void *tioc, const char *hostname) "ioc=%p tioc=%p hostname=%s" + multifd_tls_outgoing_handshake_error(void *ioc, const char *err) "ioc=%p err=%s" + multifd_tls_outgoing_handshake_complete(void *ioc) "ioc=%p" +-- +2.35.3 + diff --git a/kvm-migration-Avoid-false-positive-on-non-supported-scen.patch b/kvm-migration-Avoid-false-positive-on-non-supported-scen.patch new file mode 100644 index 0000000..c69a941 --- /dev/null +++ b/kvm-migration-Avoid-false-positive-on-non-supported-scen.patch @@ -0,0 +1,93 @@ +From cfcde3507dd742c0e17cdfe3ac3bf076cc131a84 Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Tue, 19 Jul 2022 09:23:45 -0300 +Subject: [PATCH 32/34] migration: Avoid false-positive on non-supported + scenarios for zero-copy-send +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [32/34] 409d9f974c5d69cdb4df8ef44f45c6cb25638144 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Migration with zero-copy-send currently has it's limitations, as it can't +be used with TLS nor any kind of compression. In such scenarios, it should +output errors during parameter / capability setting. + +But currently there are some ways of setting this not-supported scenarios +without printing the error message: + +!) For 'compression' capability, it works by enabling it together with +zero-copy-send. This happens because the validity test for zero-copy uses +the helper unction migrate_use_compression(), which check for compression +presence in s->enabled_capabilities[MIGRATION_CAPABILITY_COMPRESS]. + +The point here is: the validity test happens before the capability gets +enabled. If all of them get enabled together, this test will not return +error. + +In order to fix that, replace migrate_use_compression() by directly testing +the cap_list parameter migrate_caps_check(). + +2) For features enabled by parameters such as TLS & 'multifd_compression', +there was also a possibility of setting non-supported scenarios: setting +zero-copy-send first, then setting the unsupported parameter. + +In order to fix that, also add a check for parameters conflicting with +zero-copy-send on migrate_params_check(). + +3) XBZRLE is also a compression capability, so it makes sense to also add +it to the list of capabilities which are not supported with zero-copy-send. + +Fixes: 1abaec9a1b2c ("migration: Change zero_copy_send from migration parameter to migration capability") +Signed-off-by: Leonardo Bras +Message-Id: <20220719122345.253713-1-leobras@redhat.com> +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 90eb69e4f1a16b388d0483543bf6bfc69a9966e4) +Signed-off-by: Leonardo Bras +--- + migration/migration.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/migration/migration.c b/migration/migration.c +index a3e0ac954c..b1fe50a749 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1254,7 +1254,9 @@ static bool migrate_caps_check(bool *cap_list, + #ifdef CONFIG_LINUX + if (cap_list[MIGRATION_CAPABILITY_ZERO_COPY_SEND] && + (!cap_list[MIGRATION_CAPABILITY_MULTIFD] || +- migrate_use_compression() || ++ cap_list[MIGRATION_CAPABILITY_COMPRESS] || ++ cap_list[MIGRATION_CAPABILITY_XBZRLE] || ++ migrate_multifd_compression() || + migrate_use_tls())) { + error_setg(errp, + "Zero copy only available for non-compressed non-TLS multifd migration"); +@@ -1491,6 +1493,17 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) + error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: "); + return false; + } ++ ++#ifdef CONFIG_LINUX ++ if (migrate_use_zero_copy_send() && ++ ((params->has_multifd_compression && params->multifd_compression) || ++ (params->has_tls_creds && params->tls_creds && *params->tls_creds))) { ++ error_setg(errp, ++ "Zero copy only available for non-compressed non-TLS multifd migration"); ++ return false; ++ } ++#endif ++ + return true; + } + +-- +2.35.3 + diff --git a/kvm-migration-Change-zero_copy_send-from-migration-param.patch b/kvm-migration-Change-zero_copy_send-from-migration-param.patch new file mode 100644 index 0000000..35a8958 --- /dev/null +++ b/kvm-migration-Change-zero_copy_send-from-migration-param.patch @@ -0,0 +1,289 @@ +From a1853831de58b56278ef02964fd8c86ed19c2007 Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Mon, 20 Jun 2022 02:39:45 -0300 +Subject: [PATCH 26/34] migration: Change zero_copy_send from migration + parameter to migration capability +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [26/34] 249c0aaac45b33db0ba2f6d2010d61947d4e96f9 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +When originally implemented, zero_copy_send was designed as a Migration +paramenter. + +But taking into account how is that supposed to work, and how +the difference between a capability and a parameter, it only makes sense +that zero-copy-send would work better as a capability. + +Taking into account how recently the change got merged, it was decided +that it's still time to make it right, and convert zero_copy_send into +a Migration capability. + +Signed-off-by: Leonardo Bras +Reviewed-by: Juan Quintela +Acked-by: Markus Armbruster +Acked-by: Peter Xu +Signed-off-by: Juan Quintela +Signed-off-by: Dr. David Alan Gilbert + dgilbert: always define the capability, even on non-Linux but error if +set; avoids build problems with the capability +(cherry picked from commit 1abaec9a1b2c23f7aa94709a422128d9e42c3e0b) +Signed-off-by: Leonardo Bras +--- + migration/migration.c | 58 +++++++++++++++++++------------------------ + monitor/hmp-cmds.c | 6 ----- + qapi/migration.json | 33 +++++++----------------- + 3 files changed, 34 insertions(+), 63 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 5357efd348..c8aa55d2fe 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -162,7 +162,8 @@ INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot, + MIGRATION_CAPABILITY_COMPRESS, + MIGRATION_CAPABILITY_XBZRLE, + MIGRATION_CAPABILITY_X_COLO, +- MIGRATION_CAPABILITY_VALIDATE_UUID); ++ MIGRATION_CAPABILITY_VALIDATE_UUID, ++ MIGRATION_CAPABILITY_ZERO_COPY_SEND); + + bool migrate_pre_2_2; + +@@ -888,10 +889,6 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) + params->multifd_zlib_level = s->parameters.multifd_zlib_level; + params->has_multifd_zstd_level = true; + params->multifd_zstd_level = s->parameters.multifd_zstd_level; +-#ifdef CONFIG_LINUX +- params->has_zero_copy_send = true; +- params->zero_copy_send = s->parameters.zero_copy_send; +-#endif + params->has_xbzrle_cache_size = true; + params->xbzrle_cache_size = s->parameters.xbzrle_cache_size; + params->has_max_postcopy_bandwidth = true; +@@ -1249,6 +1246,24 @@ static bool migrate_caps_check(bool *cap_list, + } + } + ++#ifdef CONFIG_LINUX ++ if (cap_list[MIGRATION_CAPABILITY_ZERO_COPY_SEND] && ++ (!cap_list[MIGRATION_CAPABILITY_MULTIFD] || ++ migrate_use_compression() || ++ migrate_use_tls())) { ++ error_setg(errp, ++ "Zero copy only available for non-compressed non-TLS multifd migration"); ++ return false; ++ } ++#else ++ if (cap_list[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) { ++ error_setg(errp, ++ "Zero copy currently only available on Linux"); ++ return false; ++ } ++#endif ++ ++ + /* incoming side only */ + if (runstate_check(RUN_STATE_INMIGRATE) && + !migrate_multifd_is_allowed() && +@@ -1471,16 +1486,6 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) + error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: "); + return false; + } +-#ifdef CONFIG_LINUX +- if (params->zero_copy_send && +- (!migrate_use_multifd() || +- params->multifd_compression != MULTIFD_COMPRESSION_NONE || +- (params->tls_creds && *params->tls_creds))) { +- error_setg(errp, +- "Zero copy only available for non-compressed non-TLS multifd migration"); +- return false; +- } +-#endif + return true; + } + +@@ -1554,11 +1559,6 @@ static void migrate_params_test_apply(MigrateSetParameters *params, + if (params->has_multifd_compression) { + dest->multifd_compression = params->multifd_compression; + } +-#ifdef CONFIG_LINUX +- if (params->has_zero_copy_send) { +- dest->zero_copy_send = params->zero_copy_send; +- } +-#endif + if (params->has_xbzrle_cache_size) { + dest->xbzrle_cache_size = params->xbzrle_cache_size; + } +@@ -1671,11 +1671,6 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) + if (params->has_multifd_compression) { + s->parameters.multifd_compression = params->multifd_compression; + } +-#ifdef CONFIG_LINUX +- if (params->has_zero_copy_send) { +- s->parameters.zero_copy_send = params->zero_copy_send; +- } +-#endif + if (params->has_xbzrle_cache_size) { + s->parameters.xbzrle_cache_size = params->xbzrle_cache_size; + xbzrle_cache_resize(params->xbzrle_cache_size, errp); +@@ -2573,7 +2568,7 @@ bool migrate_use_zero_copy_send(void) + + s = migrate_get_current(); + +- return s->parameters.zero_copy_send; ++ return s->enabled_capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND]; + } + #endif + +@@ -4236,10 +4231,6 @@ static Property migration_properties[] = { + DEFINE_PROP_UINT8("multifd-zstd-level", MigrationState, + parameters.multifd_zstd_level, + DEFAULT_MIGRATE_MULTIFD_ZSTD_LEVEL), +-#ifdef CONFIG_LINUX +- DEFINE_PROP_BOOL("zero_copy_send", MigrationState, +- parameters.zero_copy_send, false), +-#endif + DEFINE_PROP_SIZE("xbzrle-cache-size", MigrationState, + parameters.xbzrle_cache_size, + DEFAULT_MIGRATE_XBZRLE_CACHE_SIZE), +@@ -4277,6 +4268,10 @@ static Property migration_properties[] = { + DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD), + DEFINE_PROP_MIG_CAP("x-background-snapshot", + MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT), ++#ifdef CONFIG_LINUX ++ DEFINE_PROP_MIG_CAP("x-zero-copy-send", ++ MIGRATION_CAPABILITY_ZERO_COPY_SEND), ++#endif + + DEFINE_PROP_END_OF_LIST(), + }; +@@ -4337,9 +4332,6 @@ static void migration_instance_init(Object *obj) + params->has_multifd_compression = true; + params->has_multifd_zlib_level = true; + params->has_multifd_zstd_level = true; +-#ifdef CONFIG_LINUX +- params->has_zero_copy_send = true; +-#endif + params->has_xbzrle_cache_size = true; + params->has_max_postcopy_bandwidth = true; + params->has_max_cpu_throttle = true; +diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c +index e02da5008b..2669156b28 100644 +--- a/monitor/hmp-cmds.c ++++ b/monitor/hmp-cmds.c +@@ -1297,12 +1297,6 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) + p->has_multifd_zstd_level = true; + visit_type_uint8(v, param, &p->multifd_zstd_level, &err); + break; +-#ifdef CONFIG_LINUX +- case MIGRATION_PARAMETER_ZERO_COPY_SEND: +- p->has_zero_copy_send = true; +- visit_type_bool(v, param, &p->zero_copy_send, &err); +- break; +-#endif + case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE: + p->has_xbzrle_cache_size = true; + if (!visit_type_size(v, param, &cache_size, &err)) { +diff --git a/qapi/migration.json b/qapi/migration.json +index 59b5c5780b..fe70a0c4b2 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -452,6 +452,13 @@ + # procedure starts. The VM RAM is saved with running VM. + # (since 6.0) + # ++# @zero-copy-send: Controls behavior on sending memory pages on migration. ++# When true, enables a zero-copy mechanism for sending ++# memory pages, if host supports it. ++# Requires that QEMU be permitted to use locked memory ++# for guest RAM pages. ++# (since 7.1) ++# + # Features: + # @unstable: Members @x-colo and @x-ignore-shared are experimental. + # +@@ -465,7 +472,8 @@ + 'block', 'return-path', 'pause-before-switchover', 'multifd', + 'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate', + { 'name': 'x-ignore-shared', 'features': [ 'unstable' ] }, +- 'validate-uuid', 'background-snapshot'] } ++ 'validate-uuid', 'background-snapshot', ++ 'zero-copy-send'] } + + ## + # @MigrationCapabilityStatus: +@@ -730,12 +738,6 @@ + # will consume more CPU. + # Defaults to 1. (Since 5.0) + # +-# @zero-copy-send: Controls behavior on sending memory pages on migration. +-# When true, enables a zero-copy mechanism for sending +-# memory pages, if host supports it. +-# Requires that QEMU be permitted to use locked memory +-# for guest RAM pages. +-# Defaults to false. (Since 7.1) + # + # @block-bitmap-mapping: Maps block nodes and bitmaps on them to + # aliases for the purpose of dirty bitmap migration. Such +@@ -776,7 +778,6 @@ + 'xbzrle-cache-size', 'max-postcopy-bandwidth', + 'max-cpu-throttle', 'multifd-compression', + 'multifd-zlib-level' ,'multifd-zstd-level', +- { 'name': 'zero-copy-send', 'if' : 'CONFIG_LINUX'}, + 'block-bitmap-mapping' ] } + + ## +@@ -903,13 +904,6 @@ + # will consume more CPU. + # Defaults to 1. (Since 5.0) + # +-# @zero-copy-send: Controls behavior on sending memory pages on migration. +-# When true, enables a zero-copy mechanism for sending +-# memory pages, if host supports it. +-# Requires that QEMU be permitted to use locked memory +-# for guest RAM pages. +-# Defaults to false. (Since 7.1) +-# + # @block-bitmap-mapping: Maps block nodes and bitmaps on them to + # aliases for the purpose of dirty bitmap migration. Such + # aliases may for example be the corresponding names on the +@@ -964,7 +958,6 @@ + '*multifd-compression': 'MultiFDCompression', + '*multifd-zlib-level': 'uint8', + '*multifd-zstd-level': 'uint8', +- '*zero-copy-send': { 'type': 'bool', 'if': 'CONFIG_LINUX' }, + '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } + + ## +@@ -1111,13 +1104,6 @@ + # will consume more CPU. + # Defaults to 1. (Since 5.0) + # +-# @zero-copy-send: Controls behavior on sending memory pages on migration. +-# When true, enables a zero-copy mechanism for sending +-# memory pages, if host supports it. +-# Requires that QEMU be permitted to use locked memory +-# for guest RAM pages. +-# Defaults to false. (Since 7.1) +-# + # @block-bitmap-mapping: Maps block nodes and bitmaps on them to + # aliases for the purpose of dirty bitmap migration. Such + # aliases may for example be the corresponding names on the +@@ -1170,7 +1156,6 @@ + '*multifd-compression': 'MultiFDCompression', + '*multifd-zlib-level': 'uint8', + '*multifd-zstd-level': 'uint8', +- '*zero-copy-send': { 'type': 'bool', 'if': 'CONFIG_LINUX' }, + '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } + + ## +-- +2.35.3 + diff --git a/kvm-migration-Introduce-ram_transferred_add.patch b/kvm-migration-Introduce-ram_transferred_add.patch new file mode 100644 index 0000000..1339e20 --- /dev/null +++ b/kvm-migration-Introduce-ram_transferred_add.patch @@ -0,0 +1,122 @@ +From be7a79cd5eb65f9835593f353220a3fe4fa7f30c Mon Sep 17 00:00:00 2001 +From: David Edmondson +Date: Tue, 21 Dec 2021 09:34:40 +0000 +Subject: [PATCH 27/34] migration: Introduce ram_transferred_add() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [27/34] fdc6eea0f4cf5ace0a71d981218ce150e98654ff +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Replace direct manipulation of ram_counters.transferred with a +function. + +Signed-off-by: David Edmondson +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +(cherry picked from commit 4c2d0f6dca24f3396ab0718ad3f9f53cc53004df) +Signed-off-by: Leonardo Bras +--- + migration/ram.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 3e208efca7..3e82c4ff46 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -391,6 +391,11 @@ uint64_t ram_bytes_remaining(void) + + MigrationStats ram_counters; + ++static void ram_transferred_add(uint64_t bytes) ++{ ++ ram_counters.transferred += bytes; ++} ++ + /* used by the search for pages to send */ + struct PageSearchStatus { + /* Current block being searched */ +@@ -772,7 +777,7 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, + * RAM_SAVE_FLAG_CONTINUE. + */ + xbzrle_counters.bytes += bytes_xbzrle - 8; +- ram_counters.transferred += bytes_xbzrle; ++ ram_transferred_add(bytes_xbzrle); + + return 1; + } +@@ -1203,7 +1208,7 @@ static int save_zero_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) + + if (len) { + ram_counters.duplicate++; +- ram_counters.transferred += len; ++ ram_transferred_add(len); + return 1; + } + return -1; +@@ -1239,7 +1244,7 @@ static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, + } + + if (bytes_xmit) { +- ram_counters.transferred += bytes_xmit; ++ ram_transferred_add(bytes_xmit); + *pages = 1; + } + +@@ -1270,8 +1275,8 @@ static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, + static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, + uint8_t *buf, bool async) + { +- ram_counters.transferred += save_page_header(rs, rs->f, block, +- offset | RAM_SAVE_FLAG_PAGE); ++ ram_transferred_add(save_page_header(rs, rs->f, block, ++ offset | RAM_SAVE_FLAG_PAGE)); + if (async) { + qemu_put_buffer_async(rs->f, buf, TARGET_PAGE_SIZE, + migrate_release_ram() & +@@ -1279,7 +1284,7 @@ static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, + } else { + qemu_put_buffer(rs->f, buf, TARGET_PAGE_SIZE); + } +- ram_counters.transferred += TARGET_PAGE_SIZE; ++ ram_transferred_add(TARGET_PAGE_SIZE); + ram_counters.normal++; + return 1; + } +@@ -1378,7 +1383,7 @@ exit: + static void + update_compress_thread_counts(const CompressParam *param, int bytes_xmit) + { +- ram_counters.transferred += bytes_xmit; ++ ram_transferred_add(bytes_xmit); + + if (param->zero_page) { + ram_counters.duplicate++; +@@ -2303,7 +2308,7 @@ void acct_update_position(QEMUFile *f, size_t size, bool zero) + ram_counters.duplicate += pages; + } else { + ram_counters.normal += pages; +- ram_counters.transferred += size; ++ ram_transferred_add(size); + qemu_update_position(f, size); + } + } +@@ -3147,7 +3152,7 @@ out: + + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + qemu_fflush(f); +- ram_counters.transferred += 8; ++ ram_transferred_add(8); + + ret = qemu_file_get_error(f); + } +-- +2.35.3 + diff --git a/kvm-migration-Never-call-twice-qemu_target_page_size.patch b/kvm-migration-Never-call-twice-qemu_target_page_size.patch new file mode 100644 index 0000000..45d143c --- /dev/null +++ b/kvm-migration-Never-call-twice-qemu_target_page_size.patch @@ -0,0 +1,116 @@ +From 2bde4dfec804afa72a3b18e41798612256fe1722 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:22 -0300 +Subject: [PATCH 01/34] migration: Never call twice qemu_target_page_size() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [1/34] 0c99a1b9648103cfba65e724578e922ab05cce78 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 144fa06b3431e806057ce1438338395b35a3e544) +Signed-off-by: Leonardo Bras +--- + migration/migration.c | 7 ++++--- + migration/multifd.c | 7 ++++--- + migration/savevm.c | 5 +++-- + 3 files changed, 11 insertions(+), 8 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index a87ff01b81..8a13294da6 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -992,6 +992,8 @@ static void populate_time_info(MigrationInfo *info, MigrationState *s) + + static void populate_ram_info(MigrationInfo *info, MigrationState *s) + { ++ size_t page_size = qemu_target_page_size(); ++ + info->has_ram = true; + info->ram = g_malloc0(sizeof(*info->ram)); + info->ram->transferred = ram_counters.transferred; +@@ -1000,12 +1002,11 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) + /* legacy value. It is not used anymore */ + info->ram->skipped = 0; + info->ram->normal = ram_counters.normal; +- info->ram->normal_bytes = ram_counters.normal * +- qemu_target_page_size(); ++ info->ram->normal_bytes = ram_counters.normal * page_size; + info->ram->mbps = s->mbps; + info->ram->dirty_sync_count = ram_counters.dirty_sync_count; + info->ram->postcopy_requests = ram_counters.postcopy_requests; +- info->ram->page_size = qemu_target_page_size(); ++ info->ram->page_size = page_size; + info->ram->multifd_bytes = ram_counters.multifd_bytes; + info->ram->pages_per_second = s->pages_per_second; + +diff --git a/migration/multifd.c b/migration/multifd.c +index 7c9deb1921..8125d0015c 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -289,7 +289,8 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) + static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + { + MultiFDPacket_t *packet = p->packet; +- uint32_t pages_max = MULTIFD_PACKET_SIZE / qemu_target_page_size(); ++ size_t page_size = qemu_target_page_size(); ++ uint32_t pages_max = MULTIFD_PACKET_SIZE / page_size; + RAMBlock *block; + int i; + +@@ -358,14 +359,14 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + for (i = 0; i < p->pages->used; i++) { + uint64_t offset = be64_to_cpu(packet->offset[i]); + +- if (offset > (block->used_length - qemu_target_page_size())) { ++ if (offset > (block->used_length - page_size)) { + error_setg(errp, "multifd: offset too long %" PRIu64 + " (max " RAM_ADDR_FMT ")", + offset, block->used_length); + return -1; + } + p->pages->iov[i].iov_base = block->host + offset; +- p->pages->iov[i].iov_len = qemu_target_page_size(); ++ p->pages->iov[i].iov_len = page_size; + } + + return 0; +diff --git a/migration/savevm.c b/migration/savevm.c +index d59e976d50..0bef031acb 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -1685,6 +1685,7 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis, + { + PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE); + uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps; ++ size_t page_size = qemu_target_page_size(); + Error *local_err = NULL; + + trace_loadvm_postcopy_handle_advise(); +@@ -1741,13 +1742,13 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis, + } + + remote_tps = qemu_get_be64(mis->from_src_file); +- if (remote_tps != qemu_target_page_size()) { ++ if (remote_tps != page_size) { + /* + * Again, some differences could be dealt with, but for now keep it + * simple. + */ + error_report("Postcopy needs matching target page sizes (s=%d d=%zd)", +- (int)remote_tps, qemu_target_page_size()); ++ (int)remote_tps, page_size); + return -1; + } + +-- +2.35.3 + diff --git a/kvm-migration-Tally-pre-copy-downtime-and-post-copy-byte.patch b/kvm-migration-Tally-pre-copy-downtime-and-post-copy-byte.patch new file mode 100644 index 0000000..c9ff787 --- /dev/null +++ b/kvm-migration-Tally-pre-copy-downtime-and-post-copy-byte.patch @@ -0,0 +1,122 @@ +From 849a82a35629d480cdfa451310b77edd5ee00aa4 Mon Sep 17 00:00:00 2001 +From: David Edmondson +Date: Tue, 21 Dec 2021 09:34:41 +0000 +Subject: [PATCH 28/34] migration: Tally pre-copy, downtime and post-copy bytes + independently +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [28/34] a6e61ae2f016d020b2456be6087aeb7d4b9f9387 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Provide information on the number of bytes copied in the pre-copy, +downtime and post-copy phases of migration. + +Signed-off-by: David Edmondson +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +(cherry picked from commit ae6806688016711bb9ec7541266d76ab511c5e3b) +Signed-off-by: Leonardo Bras +--- + migration/migration.c | 3 +++ + migration/ram.c | 7 +++++++ + monitor/hmp-cmds.c | 12 ++++++++++++ + qapi/migration.json | 13 ++++++++++++- + 4 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/migration/migration.c b/migration/migration.c +index c8aa55d2fe..87b4a6c3f9 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1010,6 +1010,9 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) + info->ram->page_size = page_size; + info->ram->multifd_bytes = ram_counters.multifd_bytes; + info->ram->pages_per_second = s->pages_per_second; ++ info->ram->precopy_bytes = ram_counters.precopy_bytes; ++ info->ram->downtime_bytes = ram_counters.downtime_bytes; ++ info->ram->postcopy_bytes = ram_counters.postcopy_bytes; + + if (migrate_use_xbzrle()) { + info->has_xbzrle_cache = true; +diff --git a/migration/ram.c b/migration/ram.c +index 3e82c4ff46..e7173da217 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -393,6 +393,13 @@ MigrationStats ram_counters; + + static void ram_transferred_add(uint64_t bytes) + { ++ if (runstate_is_running()) { ++ ram_counters.precopy_bytes += bytes; ++ } else if (migration_in_postcopy()) { ++ ram_counters.postcopy_bytes += bytes; ++ } else { ++ ram_counters.downtime_bytes += bytes; ++ } + ram_counters.transferred += bytes; + } + +diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c +index 2669156b28..8c384dc1b2 100644 +--- a/monitor/hmp-cmds.c ++++ b/monitor/hmp-cmds.c +@@ -293,6 +293,18 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) + monitor_printf(mon, "postcopy request count: %" PRIu64 "\n", + info->ram->postcopy_requests); + } ++ if (info->ram->precopy_bytes) { ++ monitor_printf(mon, "precopy ram: %" PRIu64 " kbytes\n", ++ info->ram->precopy_bytes >> 10); ++ } ++ if (info->ram->downtime_bytes) { ++ monitor_printf(mon, "downtime ram: %" PRIu64 " kbytes\n", ++ info->ram->downtime_bytes >> 10); ++ } ++ if (info->ram->postcopy_bytes) { ++ monitor_printf(mon, "postcopy ram: %" PRIu64 " kbytes\n", ++ info->ram->postcopy_bytes >> 10); ++ } + } + + if (info->has_disk) { +diff --git a/qapi/migration.json b/qapi/migration.json +index fe70a0c4b2..c8ec260ab0 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -46,6 +46,15 @@ + # @pages-per-second: the number of memory pages transferred per second + # (Since 4.0) + # ++# @precopy-bytes: The number of bytes sent in the pre-copy phase ++# (since 7.0). ++# ++# @downtime-bytes: The number of bytes sent while the guest is paused ++# (since 7.0). ++# ++# @postcopy-bytes: The number of bytes sent during the post-copy phase ++# (since 7.0). ++# + # Since: 0.14 + ## + { 'struct': 'MigrationStats', +@@ -54,7 +63,9 @@ + 'normal-bytes': 'int', 'dirty-pages-rate' : 'int', + 'mbps' : 'number', 'dirty-sync-count' : 'int', + 'postcopy-requests' : 'int', 'page-size' : 'int', +- 'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64' } } ++ 'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64', ++ 'precopy-bytes' : 'uint64', 'downtime-bytes' : 'uint64', ++ 'postcopy-bytes' : 'uint64' } } + + ## + # @XBZRLECacheStats: +-- +2.35.3 + diff --git a/kvm-migration-add-remaining-params-has_-true-in-migratio.patch b/kvm-migration-add-remaining-params-has_-true-in-migratio.patch new file mode 100644 index 0000000..a985c87 --- /dev/null +++ b/kvm-migration-add-remaining-params-has_-true-in-migratio.patch @@ -0,0 +1,62 @@ +From d40f63360fc8677ac2ac3a679bab4c1e3dbe334f Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Mon, 25 Jul 2022 22:02:35 -0300 +Subject: [PATCH 33/34] migration: add remaining params->has_* = true in + migration_instance_init() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [33/34] cc70a134ae27296e8a07dffd4dfccf1a329f27f1 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Some of params->has_* = true are missing in migration_instance_init, this +causes migrate_params_check() to skip some tests, allowing some +unsupported scenarios. + +Fix this by adding all missing params->has_* = true in +migration_instance_init(). + +Fixes: 69ef1f36b0 ("migration: define 'tls-creds' and 'tls-hostname' migration parameters") +Fixes: 1d58872a91 ("migration: do not wait for free thread") +Fixes: d2f1d29b95 ("migration: add support for a "tls-authz" migration parameter") +Signed-off-by: Leonardo Bras +Message-Id: <20220726010235.342927-1-leobras@redhat.com> +Reviewed-by: Peter Xu +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit df67aa3e61e2c83459da7d815962d9706f1528fc) +Signed-off-by: Leonardo Bras +--- + migration/migration.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/migration/migration.c b/migration/migration.c +index b1fe50a749..02f962ead0 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -4337,6 +4337,7 @@ static void migration_instance_init(Object *obj) + /* Set has_* up only for parameter checks */ + params->has_compress_level = true; + params->has_compress_threads = true; ++ params->has_compress_wait_thread = true; + params->has_decompress_threads = true; + params->has_throttle_trigger_threshold = true; + params->has_cpu_throttle_initial = true; +@@ -4357,6 +4358,9 @@ static void migration_instance_init(Object *obj) + params->has_announce_max = true; + params->has_announce_rounds = true; + params->has_announce_step = true; ++ params->has_tls_creds = true; ++ params->has_tls_hostname = true; ++ params->has_tls_authz = true; + + qemu_sem_init(&ms->postcopy_pause_sem, 0); + qemu_sem_init(&ms->postcopy_pause_rp_sem, 0); +-- +2.35.3 + diff --git a/kvm-migration-multifd-Report-to-user-when-zerocopy-not-w.patch b/kvm-migration-multifd-Report-to-user-when-zerocopy-not-w.patch new file mode 100644 index 0000000..c155736 --- /dev/null +++ b/kvm-migration-multifd-Report-to-user-when-zerocopy-not-w.patch @@ -0,0 +1,83 @@ +From e7497ea1a0fa4d4a10fb76f3a274df29e487a277 Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Mon, 11 Jul 2022 18:11:13 -0300 +Subject: [PATCH 31/34] migration/multifd: Report to user when zerocopy not + working +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [31/34] 5aa1b4e6cfc23dd8474844ef8ffa9eb996355e20 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Some errors, like the lack of Scatter-Gather support by the network +interface(NETIF_F_SG) may cause sendmsg(...,MSG_ZEROCOPY) to fail on using +zero-copy, which causes it to fall back to the default copying mechanism. + +After each full dirty-bitmap scan there should be a zero-copy flush +happening, which checks for errors each of the previous calls to +sendmsg(...,MSG_ZEROCOPY). If all of them failed to use zero-copy, then +increment dirty_sync_missed_zero_copy migration stat to let the user know +about it. + +Signed-off-by: Leonardo Bras +Reviewed-by: Daniel P. Berrangé +Acked-by: Peter Xu +Message-Id: <20220711211112.18951-4-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit d59c40cc483729f2e67c80e58df769ad19976fe9) +Signed-off-by: Leonardo Bras +--- + migration/multifd.c | 2 ++ + migration/ram.c | 5 +++++ + migration/ram.h | 2 ++ + 3 files changed, 9 insertions(+) + +diff --git a/migration/multifd.c b/migration/multifd.c +index 90ab4c4346..7c16523e6b 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -631,6 +631,8 @@ int multifd_send_sync_main(QEMUFile *f) + if (ret < 0) { + error_report_err(err); + return -1; ++ } else if (ret == 1) { ++ dirty_sync_missed_zero_copy(); + } + } + } +diff --git a/migration/ram.c b/migration/ram.c +index e7173da217..93cdb456ac 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -403,6 +403,11 @@ static void ram_transferred_add(uint64_t bytes) + ram_counters.transferred += bytes; + } + ++void dirty_sync_missed_zero_copy(void) ++{ ++ ram_counters.dirty_sync_missed_zero_copy++; ++} ++ + /* used by the search for pages to send */ + struct PageSearchStatus { + /* Current block being searched */ +diff --git a/migration/ram.h b/migration/ram.h +index c515396a9a..69c3ccb26a 100644 +--- a/migration/ram.h ++++ b/migration/ram.h +@@ -88,4 +88,6 @@ void ram_write_tracking_prepare(void); + int ram_write_tracking_start(void); + void ram_write_tracking_stop(void); + ++void dirty_sync_missed_zero_copy(void); ++ + #endif +-- +2.35.3 + diff --git a/kvm-multifd-Add-missing-documention.patch b/kvm-multifd-Add-missing-documention.patch new file mode 100644 index 0000000..a4efe49 --- /dev/null +++ b/kvm-multifd-Add-missing-documention.patch @@ -0,0 +1,81 @@ +From a5a03cd1ffc772c9d2bbf8e97e971b0cb8daa617 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:23 -0300 +Subject: [PATCH 03/34] multifd: Add missing documention +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [3/34] 3f73bc1414f80a3611c7a807671a04ddb16ec7da +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 18ede636bc29fd8bda628fe3e5c593f8c1b734f4) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zlib.c | 2 ++ + migration/multifd-zstd.c | 2 ++ + migration/multifd.c | 1 + + 3 files changed, 5 insertions(+) + +diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c +index ab4ba75d75..f403d2f031 100644 +--- a/migration/multifd-zlib.c ++++ b/migration/multifd-zlib.c +@@ -74,6 +74,7 @@ static int zlib_send_setup(MultiFDSendParams *p, Error **errp) + * Close the channel and return memory. + * + * @p: Params for the channel that we are using ++ * @errp: pointer to an error + */ + static void zlib_send_cleanup(MultiFDSendParams *p, Error **errp) + { +@@ -96,6 +97,7 @@ static void zlib_send_cleanup(MultiFDSendParams *p, Error **errp) + * + * @p: Params for the channel that we are using + * @used: number of pages used ++ * @errp: pointer to an error + */ + static int zlib_send_prepare(MultiFDSendParams *p, uint32_t used, Error **errp) + { +diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c +index 693bddf8c9..8d657f8860 100644 +--- a/migration/multifd-zstd.c ++++ b/migration/multifd-zstd.c +@@ -86,6 +86,7 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp) + * Close the channel and return memory. + * + * @p: Params for the channel that we are using ++ * @errp: pointer to an error + */ + static void zstd_send_cleanup(MultiFDSendParams *p, Error **errp) + { +@@ -109,6 +110,7 @@ static void zstd_send_cleanup(MultiFDSendParams *p, Error **errp) + * + * @p: Params for the channel that we are using + * @used: number of pages used ++ * @errp: pointer to an error + */ + static int zstd_send_prepare(MultiFDSendParams *p, uint32_t used, Error **errp) + { +diff --git a/migration/multifd.c b/migration/multifd.c +index 8ea86d81dc..cdeffdc4c5 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -66,6 +66,7 @@ static int nocomp_send_setup(MultiFDSendParams *p, Error **errp) + * For no compression this function does nothing. + * + * @p: Params for the channel that we are using ++ * @errp: pointer to an error + */ + static void nocomp_send_cleanup(MultiFDSendParams *p, Error **errp) + { +-- +2.35.3 + diff --git a/kvm-multifd-Fill-offset-and-block-for-reception.patch b/kvm-multifd-Fill-offset-and-block-for-reception.patch new file mode 100644 index 0000000..41ef14c --- /dev/null +++ b/kvm-multifd-Fill-offset-and-block-for-reception.patch @@ -0,0 +1,50 @@ +From ff3315e41f6e33e2ef7d764e064be60b3b7670e4 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:23 -0300 +Subject: [PATCH 07/34] multifd: Fill offset and block for reception +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [7/34] e1c460e910a7de2bbe21221b4c54da0bbc09b4c0 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +We were using the iov directly, but we will need this info on the +following patch. + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 01102a2ef6c97acc5cc8a2c3bb62b7665a20f51f) +Signed-off-by: Leonardo Bras +--- + migration/multifd.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/migration/multifd.c b/migration/multifd.c +index 55d99a8232..0533da154a 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -354,6 +354,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + return -1; + } + ++ p->pages->block = block; + for (i = 0; i < p->pages->num; i++) { + uint64_t offset = be64_to_cpu(packet->offset[i]); + +@@ -363,6 +364,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + offset, block->used_length); + return -1; + } ++ p->pages->offset[i] = offset; + p->pages->iov[i].iov_base = block->host + offset; + p->pages->iov[i].iov_len = page_size; + } +-- +2.35.3 + diff --git a/kvm-multifd-Implement-zero-copy-write-in-multifd-migrati.patch b/kvm-multifd-Implement-zero-copy-write-in-multifd-migrati.patch new file mode 100644 index 0000000..3243f19 --- /dev/null +++ b/kvm-multifd-Implement-zero-copy-write-in-multifd-migrati.patch @@ -0,0 +1,182 @@ +From fb4bec0c863fb397078ab6086e95d5401be04ef2 Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Wed, 18 May 2022 02:52:25 -0300 +Subject: [PATCH 23/34] multifd: Implement zero copy write in multifd migration + (multifd-zero-copy) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [23/34] ef7e8d02dde6570dc8cdf232f7ea03c997ee2e40 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Implement zero copy send on nocomp_send_write(), by making use of QIOChannel +writev + flags & flush interface. + +Change multifd_send_sync_main() so flush_zero_copy() can be called +after each iteration in order to make sure all dirty pages are sent before +a new iteration is started. It will also flush at the beginning and at the +end of migration. + +Also make it return -1 if flush_zero_copy() fails, in order to cancel +the migration process, and avoid resuming the guest in the target host +without receiving all current RAM. + +This will work fine on RAM migration because the RAM pages are not usually freed, +and there is no problem on changing the pages content between writev_zero_copy() and +the actual sending of the buffer, because this change will dirty the page and +cause it to be re-sent on a next iteration anyway. + +A lot of locked memory may be needed in order to use multifd migration +with zero-copy enabled, so disabling the feature should be necessary for +low-privileged users trying to perform multifd migrations. + +Signed-off-by: Leonardo Bras +Reviewed-by: Peter Xu +Reviewed-by: Daniel P. Berrangé +Message-Id: <20220513062836.965425-9-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 5b1d9bab2da4fca3a3caee97c430e5709cb32b7b) +Signed-off-by: Leonardo Bras +--- + migration/migration.c | 11 ++++++++++- + migration/multifd.c | 37 +++++++++++++++++++++++++++++++++++-- + migration/multifd.h | 2 ++ + migration/socket.c | 5 +++-- + 4 files changed, 50 insertions(+), 5 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 8e28f2ee41..5357efd348 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1471,7 +1471,16 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) + error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: "); + return false; + } +- ++#ifdef CONFIG_LINUX ++ if (params->zero_copy_send && ++ (!migrate_use_multifd() || ++ params->multifd_compression != MULTIFD_COMPRESSION_NONE || ++ (params->tls_creds && *params->tls_creds))) { ++ error_setg(errp, ++ "Zero copy only available for non-compressed non-TLS multifd migration"); ++ return false; ++ } ++#endif + return true; + } + +diff --git a/migration/multifd.c b/migration/multifd.c +index 193f70cdba..90ab4c4346 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -576,6 +576,7 @@ void multifd_save_cleanup(void) + int multifd_send_sync_main(QEMUFile *f) + { + int i; ++ bool flush_zero_copy; + + if (!migrate_use_multifd()) { + return 0; +@@ -586,6 +587,20 @@ int multifd_send_sync_main(QEMUFile *f) + return -1; + } + } ++ ++ /* ++ * When using zero-copy, it's necessary to flush the pages before any of ++ * the pages can be sent again, so we'll make sure the new version of the ++ * pages will always arrive _later_ than the old pages. ++ * ++ * Currently we achieve this by flushing the zero-page requested writes ++ * per ram iteration, but in the future we could potentially optimize it ++ * to be less frequent, e.g. only after we finished one whole scanning of ++ * all the dirty bitmaps. ++ */ ++ ++ flush_zero_copy = migrate_use_zero_copy_send(); ++ + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; + +@@ -607,6 +622,17 @@ int multifd_send_sync_main(QEMUFile *f) + ram_counters.transferred += p->packet_len; + qemu_mutex_unlock(&p->mutex); + qemu_sem_post(&p->sem); ++ ++ if (flush_zero_copy && p->c) { ++ int ret; ++ Error *err = NULL; ++ ++ ret = qio_channel_flush(p->c, &err); ++ if (ret < 0) { ++ error_report_err(err); ++ return -1; ++ } ++ } + } + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; +@@ -691,8 +717,8 @@ static void *multifd_send_thread(void *opaque) + p->iov[0].iov_base = p->packet; + } + +- ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num, +- &local_err); ++ ret = qio_channel_writev_full_all(p->c, p->iov, p->iovs_num, NULL, ++ 0, p->write_flags, &local_err); + if (ret != 0) { + break; + } +@@ -933,6 +959,13 @@ int multifd_save_setup(Error **errp) + /* We need one extra place for the packet header */ + p->iov = g_new0(struct iovec, page_count + 1); + p->normal = g_new0(ram_addr_t, page_count); ++ ++ if (migrate_use_zero_copy_send()) { ++ p->write_flags = QIO_CHANNEL_WRITE_FLAG_ZERO_COPY; ++ } else { ++ p->write_flags = 0; ++ } ++ + socket_send_channel_create(multifd_new_send_channel_async, p); + } + +diff --git a/migration/multifd.h b/migration/multifd.h +index 92de878155..11d5e273e6 100644 +--- a/migration/multifd.h ++++ b/migration/multifd.h +@@ -95,6 +95,8 @@ typedef struct { + uint32_t packet_len; + /* pointer to the packet */ + MultiFDPacket_t *packet; ++ /* multifd flags for sending ram */ ++ int write_flags; + /* multifd flags for each packet */ + uint32_t flags; + /* size of the next packet that contains pages */ +diff --git a/migration/socket.c b/migration/socket.c +index 3754d8f72c..4fd5e85f50 100644 +--- a/migration/socket.c ++++ b/migration/socket.c +@@ -79,8 +79,9 @@ static void socket_outgoing_migration(QIOTask *task, + + trace_migration_socket_outgoing_connected(data->hostname); + +- if (migrate_use_zero_copy_send()) { +- error_setg(&err, "Zero copy send not available in migration"); ++ if (migrate_use_zero_copy_send() && ++ !qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { ++ error_setg(&err, "Zero copy send feature not detected in host kernel"); + } + + out: +-- +2.35.3 + diff --git a/kvm-multifd-Make-zlib-compression-method-not-use-iovs.patch b/kvm-multifd-Make-zlib-compression-method-not-use-iovs.patch new file mode 100644 index 0000000..817f0de --- /dev/null +++ b/kvm-multifd-Make-zlib-compression-method-not-use-iovs.patch @@ -0,0 +1,98 @@ +From e74b927853e84b44f8047718020593939ad125ec Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:23 -0300 +Subject: [PATCH 09/34] multifd: Make zlib compression method not use iovs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [9/34] 37d70e2163ed982e2d8343c4ec1061fc59677688 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit a5ed22948873b50fcf1415d1ce15c71d61a9388d) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zlib.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c +index 330fc021c5..a1950a4588 100644 +--- a/migration/multifd-zlib.c ++++ b/migration/multifd-zlib.c +@@ -13,6 +13,7 @@ + #include "qemu/osdep.h" + #include + #include "qemu/rcu.h" ++#include "exec/ramblock.h" + #include "exec/target_page.h" + #include "qapi/error.h" + #include "migration.h" +@@ -100,8 +101,8 @@ static void zlib_send_cleanup(MultiFDSendParams *p, Error **errp) + */ + static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) + { +- struct iovec *iov = p->pages->iov; + struct zlib_data *z = p->data; ++ size_t page_size = qemu_target_page_size(); + z_stream *zs = &z->zs; + uint32_t out_size = 0; + int ret; +@@ -115,8 +116,8 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) + flush = Z_SYNC_FLUSH; + } + +- zs->avail_in = iov[i].iov_len; +- zs->next_in = iov[i].iov_base; ++ zs->avail_in = page_size; ++ zs->next_in = p->pages->block->host + p->pages->offset[i]; + + zs->avail_out = available; + zs->next_out = z->zbuff + out_size; +@@ -240,6 +241,7 @@ static void zlib_recv_cleanup(MultiFDRecvParams *p) + static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) + { + struct zlib_data *z = p->data; ++ size_t page_size = qemu_target_page_size(); + z_stream *zs = &z->zs; + uint32_t in_size = p->next_packet_size; + /* we measure the change of total_out */ +@@ -264,7 +266,6 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) + zs->next_in = z->zbuff; + + for (i = 0; i < p->pages->num; i++) { +- struct iovec *iov = &p->pages->iov[i]; + int flush = Z_NO_FLUSH; + unsigned long start = zs->total_out; + +@@ -272,8 +273,8 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) + flush = Z_SYNC_FLUSH; + } + +- zs->avail_out = iov->iov_len; +- zs->next_out = iov->iov_base; ++ zs->avail_out = page_size; ++ zs->next_out = p->pages->block->host + p->pages->offset[i]; + + /* + * Welcome to inflate semantics +@@ -286,8 +287,8 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) + do { + ret = inflate(zs, flush); + } while (ret == Z_OK && zs->avail_in +- && (zs->total_out - start) < iov->iov_len); +- if (ret == Z_OK && (zs->total_out - start) < iov->iov_len) { ++ && (zs->total_out - start) < page_size); ++ if (ret == Z_OK && (zs->total_out - start) < page_size) { + error_setg(errp, "multifd %d: inflate generated too few output", + p->id); + return -1; +-- +2.35.3 + diff --git a/kvm-multifd-Make-zlib-use-iov-s.patch b/kvm-multifd-Make-zlib-use-iov-s.patch new file mode 100644 index 0000000..7c0cc8e --- /dev/null +++ b/kvm-multifd-Make-zlib-use-iov-s.patch @@ -0,0 +1,53 @@ +From 9cc84ed4e52807912598f3cdef3ad08e9166cdea Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:24 -0300 +Subject: [PATCH 12/34] multifd: Make zlib use iov's +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [12/34] 7cca02fb1706db0b1336d43ef4b1b6a16acf21a1 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 48a4a44c1cde382c6b8e7792d01fe7d9b0a59c69) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zlib.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c +index a987e4a26c..96475e096e 100644 +--- a/migration/multifd-zlib.c ++++ b/migration/multifd-zlib.c +@@ -145,6 +145,9 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) + } + out_size += available - zs->avail_out; + } ++ p->iov[p->iovs_num].iov_base = z->zbuff; ++ p->iov[p->iovs_num].iov_len = out_size; ++ p->iovs_num++; + p->next_packet_size = out_size; + p->flags |= MULTIFD_FLAG_ZLIB; + +@@ -164,10 +167,7 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) + */ + static int zlib_send_write(MultiFDSendParams *p, uint32_t used, Error **errp) + { +- struct zlib_data *z = p->data; +- +- return qio_channel_write_all(p->c, (void *)z->zbuff, p->next_packet_size, +- errp); ++ return qio_channel_writev_all(p->c, p->iov, p->iovs_num, errp); + } + + /** +-- +2.35.3 + diff --git a/kvm-multifd-Make-zstd-compression-method-not-use-iovs.patch b/kvm-multifd-Make-zstd-compression-method-not-use-iovs.patch new file mode 100644 index 0000000..12d56a7 --- /dev/null +++ b/kvm-multifd-Make-zstd-compression-method-not-use-iovs.patch @@ -0,0 +1,94 @@ +From dc083c2407de0a668573e549b8357f451554e376 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:23 -0300 +Subject: [PATCH 08/34] multifd: Make zstd compression method not use iovs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [8/34] 953059f89f3b79f4c515c16877052522c3104753 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit f5ff548774c22b34a0c0e2fef85f1be11160d774) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zstd.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c +index f0d1105792..d9ed42622b 100644 +--- a/migration/multifd-zstd.c ++++ b/migration/multifd-zstd.c +@@ -13,6 +13,7 @@ + #include "qemu/osdep.h" + #include + #include "qemu/rcu.h" ++#include "exec/ramblock.h" + #include "exec/target_page.h" + #include "qapi/error.h" + #include "migration.h" +@@ -113,8 +114,8 @@ static void zstd_send_cleanup(MultiFDSendParams *p, Error **errp) + */ + static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) + { +- struct iovec *iov = p->pages->iov; + struct zstd_data *z = p->data; ++ size_t page_size = qemu_target_page_size(); + int ret; + uint32_t i; + +@@ -128,8 +129,8 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) + if (i == p->pages->num - 1) { + flush = ZSTD_e_flush; + } +- z->in.src = iov[i].iov_base; +- z->in.size = iov[i].iov_len; ++ z->in.src = p->pages->block->host + p->pages->offset[i]; ++ z->in.size = page_size; + z->in.pos = 0; + + /* +@@ -261,7 +262,8 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp) + { + uint32_t in_size = p->next_packet_size; + uint32_t out_size = 0; +- uint32_t expected_size = p->pages->num * qemu_target_page_size(); ++ size_t page_size = qemu_target_page_size(); ++ uint32_t expected_size = p->pages->num * page_size; + uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; + struct zstd_data *z = p->data; + int ret; +@@ -283,10 +285,8 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp) + z->in.pos = 0; + + for (i = 0; i < p->pages->num; i++) { +- struct iovec *iov = &p->pages->iov[i]; +- +- z->out.dst = iov->iov_base; +- z->out.size = iov->iov_len; ++ z->out.dst = p->pages->block->host + p->pages->offset[i]; ++ z->out.size = page_size; + z->out.pos = 0; + + /* +@@ -300,8 +300,8 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp) + do { + ret = ZSTD_decompressStream(z->zds, &z->out, &z->in); + } while (ret > 0 && (z->in.size - z->in.pos > 0) +- && (z->out.pos < iov->iov_len)); +- if (ret > 0 && (z->out.pos < iov->iov_len)) { ++ && (z->out.pos < page_size)); ++ if (ret > 0 && (z->out.pos < page_size)) { + error_setg(errp, "multifd %d: decompressStream buffer too small", + p->id); + return -1; +-- +2.35.3 + diff --git a/kvm-multifd-Make-zstd-use-iov-s.patch b/kvm-multifd-Make-zstd-use-iov-s.patch new file mode 100644 index 0000000..16dece0 --- /dev/null +++ b/kvm-multifd-Make-zstd-use-iov-s.patch @@ -0,0 +1,53 @@ +From a451644d96f572f5845d3ee523e54486da55d9ae Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:24 -0300 +Subject: [PATCH 13/34] multifd: Make zstd use iov's +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [13/34] 37929ac695c7bdfe6e2f798d4f5e43a5e7525acb +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 0a818b89eb8eaf79ae651405907d8110a0935cfd) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zstd.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c +index 2185a83eac..4e60cdbc54 100644 +--- a/migration/multifd-zstd.c ++++ b/migration/multifd-zstd.c +@@ -156,6 +156,9 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) + return -1; + } + } ++ p->iov[p->iovs_num].iov_base = z->zbuff; ++ p->iov[p->iovs_num].iov_len = z->out.pos; ++ p->iovs_num++; + p->next_packet_size = z->out.pos; + p->flags |= MULTIFD_FLAG_ZSTD; + +@@ -175,10 +178,7 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) + */ + static int zstd_send_write(MultiFDSendParams *p, uint32_t used, Error **errp) + { +- struct zstd_data *z = p->data; +- +- return qio_channel_write_all(p->c, (void *)z->zbuff, p->next_packet_size, +- errp); ++ return qio_channel_writev_all(p->c, p->iov, p->iovs_num, errp); + } + + /** +-- +2.35.3 + diff --git a/kvm-multifd-Move-iov-from-pages-to-params.patch b/kvm-multifd-Move-iov-from-pages-to-params.patch new file mode 100644 index 0000000..8c014a3 --- /dev/null +++ b/kvm-multifd-Move-iov-from-pages-to-params.patch @@ -0,0 +1,190 @@ +From faae5f3dd29a25607f34466b9cd11d17ff6a0db6 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:24 -0300 +Subject: [PATCH 11/34] multifd: Move iov from pages to params +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [11/34] 382f1d5db714944bd12f264db9ad0e37ddb2cfeb +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +This will allow us to reduce the number of system calls on the next patch. + +Signed-off-by: Juan Quintela +(cherry picked from commit 226468ba3dea950ab4bb0b729878dde25812da1c) +Signed-off-by: Leonardo Bras +--- + migration/multifd.c | 34 ++++++++++++++++++++++++---------- + migration/multifd.h | 8 ++++++-- + 2 files changed, 30 insertions(+), 12 deletions(-) + +diff --git a/migration/multifd.c b/migration/multifd.c +index d0d19470f9..5004f394aa 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -86,7 +86,16 @@ static void nocomp_send_cleanup(MultiFDSendParams *p, Error **errp) + */ + static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp) + { +- p->next_packet_size = p->pages->num * qemu_target_page_size(); ++ MultiFDPages_t *pages = p->pages; ++ size_t page_size = qemu_target_page_size(); ++ ++ for (int i = 0; i < p->pages->num; i++) { ++ p->iov[p->iovs_num].iov_base = pages->block->host + pages->offset[i]; ++ p->iov[p->iovs_num].iov_len = page_size; ++ p->iovs_num++; ++ } ++ ++ p->next_packet_size = p->pages->num * page_size; + p->flags |= MULTIFD_FLAG_NOCOMP; + return 0; + } +@@ -104,7 +113,7 @@ static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp) + */ + static int nocomp_send_write(MultiFDSendParams *p, uint32_t used, Error **errp) + { +- return qio_channel_writev_all(p->c, p->pages->iov, used, errp); ++ return qio_channel_writev_all(p->c, p->iov, p->iovs_num, errp); + } + + /** +@@ -146,13 +155,18 @@ static void nocomp_recv_cleanup(MultiFDRecvParams *p) + static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp) + { + uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; ++ size_t page_size = qemu_target_page_size(); + + if (flags != MULTIFD_FLAG_NOCOMP) { + error_setg(errp, "multifd %u: flags received %x flags expected %x", + p->id, flags, MULTIFD_FLAG_NOCOMP); + return -1; + } +- return qio_channel_readv_all(p->c, p->pages->iov, p->pages->num, errp); ++ for (int i = 0; i < p->pages->num; i++) { ++ p->iov[i].iov_base = p->pages->block->host + p->pages->offset[i]; ++ p->iov[i].iov_len = page_size; ++ } ++ return qio_channel_readv_all(p->c, p->iov, p->pages->num, errp); + } + + static MultiFDMethods multifd_nocomp_ops = { +@@ -242,7 +256,6 @@ static MultiFDPages_t *multifd_pages_init(size_t size) + MultiFDPages_t *pages = g_new0(MultiFDPages_t, 1); + + pages->allocated = size; +- pages->iov = g_new0(struct iovec, size); + pages->offset = g_new0(ram_addr_t, size); + + return pages; +@@ -254,8 +267,6 @@ static void multifd_pages_clear(MultiFDPages_t *pages) + pages->allocated = 0; + pages->packet_num = 0; + pages->block = NULL; +- g_free(pages->iov); +- pages->iov = NULL; + g_free(pages->offset); + pages->offset = NULL; + g_free(pages); +@@ -365,8 +376,6 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + return -1; + } + p->pages->offset[i] = offset; +- p->pages->iov[i].iov_base = block->host + offset; +- p->pages->iov[i].iov_len = page_size; + } + + return 0; +@@ -470,8 +479,6 @@ int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset) + + if (pages->block == block) { + pages->offset[pages->num] = offset; +- pages->iov[pages->num].iov_base = block->host + offset; +- pages->iov[pages->num].iov_len = qemu_target_page_size(); + pages->num++; + + if (pages->num < pages->allocated) { +@@ -564,6 +571,8 @@ void multifd_save_cleanup(void) + p->packet_len = 0; + g_free(p->packet); + p->packet = NULL; ++ g_free(p->iov); ++ p->iov = NULL; + multifd_send_state->ops->send_cleanup(p, &local_err); + if (local_err) { + migrate_set_error(migrate_get_current(), local_err); +@@ -651,6 +660,7 @@ static void *multifd_send_thread(void *opaque) + uint32_t used = p->pages->num; + uint64_t packet_num = p->packet_num; + uint32_t flags = p->flags; ++ p->iovs_num = 0; + + if (used) { + ret = multifd_send_state->ops->send_prepare(p, &local_err); +@@ -919,6 +929,7 @@ int multifd_save_setup(Error **errp) + p->packet->version = cpu_to_be32(MULTIFD_VERSION); + p->name = g_strdup_printf("multifdsend_%d", i); + p->tls_hostname = g_strdup(s->hostname); ++ p->iov = g_new0(struct iovec, page_count); + socket_send_channel_create(multifd_new_send_channel_async, p); + } + +@@ -1018,6 +1029,8 @@ int multifd_load_cleanup(Error **errp) + p->packet_len = 0; + g_free(p->packet); + p->packet = NULL; ++ g_free(p->iov); ++ p->iov = NULL; + multifd_recv_state->ops->recv_cleanup(p); + } + qemu_sem_destroy(&multifd_recv_state->sem_sync); +@@ -1158,6 +1171,7 @@ int multifd_load_setup(Error **errp) + + sizeof(uint64_t) * page_count; + p->packet = g_malloc0(p->packet_len); + p->name = g_strdup_printf("multifdrecv_%d", i); ++ p->iov = g_new0(struct iovec, page_count); + } + + for (i = 0; i < thread_count; i++) { +diff --git a/migration/multifd.h b/migration/multifd.h +index e57adc783b..c3f18af364 100644 +--- a/migration/multifd.h ++++ b/migration/multifd.h +@@ -62,8 +62,6 @@ typedef struct { + uint64_t packet_num; + /* offset of each page */ + ram_addr_t *offset; +- /* pointer to each page */ +- struct iovec *iov; + RAMBlock *block; + } MultiFDPages_t; + +@@ -110,6 +108,10 @@ typedef struct { + uint64_t num_pages; + /* syncs main thread and channels */ + QemuSemaphore sem_sync; ++ /* buffers to send */ ++ struct iovec *iov; ++ /* number of iovs used */ ++ uint32_t iovs_num; + /* used for compression methods */ + void *data; + } MultiFDSendParams; +@@ -149,6 +151,8 @@ typedef struct { + uint64_t num_pages; + /* syncs main thread and channels */ + QemuSemaphore sem_sync; ++ /* buffers to recv */ ++ struct iovec *iov; + /* used for de-compression methods */ + void *data; + } MultiFDRecvParams; +-- +2.35.3 + diff --git a/kvm-multifd-Remove-send_write-method.patch b/kvm-multifd-Remove-send_write-method.patch new file mode 100644 index 0000000..c37ef79 --- /dev/null +++ b/kvm-multifd-Remove-send_write-method.patch @@ -0,0 +1,160 @@ +From e93de1066dde56befa50d1466955c7b7432604d1 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:24 -0300 +Subject: [PATCH 14/34] multifd: Remove send_write() method +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [14/34] 483abd10c7cf11f27599ebcfb0586eb91b6519c1 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Everything use now iov's. + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 468fcb5dd0c965e1af0da9efab09b1462631da18) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zlib.c | 17 ----------------- + migration/multifd-zstd.c | 17 ----------------- + migration/multifd.c | 20 ++------------------ + migration/multifd.h | 2 -- + 4 files changed, 2 insertions(+), 54 deletions(-) + +diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c +index 96475e096e..8ed29b9633 100644 +--- a/migration/multifd-zlib.c ++++ b/migration/multifd-zlib.c +@@ -154,22 +154,6 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) + return 0; + } + +-/** +- * zlib_send_write: do the actual write of the data +- * +- * Do the actual write of the comprresed buffer. +- * +- * Returns 0 for success or -1 for error +- * +- * @p: Params for the channel that we are using +- * @used: number of pages used +- * @errp: pointer to an error +- */ +-static int zlib_send_write(MultiFDSendParams *p, uint32_t used, Error **errp) +-{ +- return qio_channel_writev_all(p->c, p->iov, p->iovs_num, errp); +-} +- + /** + * zlib_recv_setup: setup receive side + * +@@ -312,7 +296,6 @@ static MultiFDMethods multifd_zlib_ops = { + .send_setup = zlib_send_setup, + .send_cleanup = zlib_send_cleanup, + .send_prepare = zlib_send_prepare, +- .send_write = zlib_send_write, + .recv_setup = zlib_recv_setup, + .recv_cleanup = zlib_recv_cleanup, + .recv_pages = zlib_recv_pages +diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c +index 4e60cdbc54..25e1f517b5 100644 +--- a/migration/multifd-zstd.c ++++ b/migration/multifd-zstd.c +@@ -165,22 +165,6 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) + return 0; + } + +-/** +- * zstd_send_write: do the actual write of the data +- * +- * Do the actual write of the comprresed buffer. +- * +- * Returns 0 for success or -1 for error +- * +- * @p: Params for the channel that we are using +- * @used: number of pages used +- * @errp: pointer to an error +- */ +-static int zstd_send_write(MultiFDSendParams *p, uint32_t used, Error **errp) +-{ +- return qio_channel_writev_all(p->c, p->iov, p->iovs_num, errp); +-} +- + /** + * zstd_recv_setup: setup receive side + * +@@ -325,7 +309,6 @@ static MultiFDMethods multifd_zstd_ops = { + .send_setup = zstd_send_setup, + .send_cleanup = zstd_send_cleanup, + .send_prepare = zstd_send_prepare, +- .send_write = zstd_send_write, + .recv_setup = zstd_recv_setup, + .recv_cleanup = zstd_recv_cleanup, + .recv_pages = zstd_recv_pages +diff --git a/migration/multifd.c b/migration/multifd.c +index 5004f394aa..1e1551d78b 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -100,22 +100,6 @@ static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp) + return 0; + } + +-/** +- * nocomp_send_write: do the actual write of the data +- * +- * For no compression we just have to write the data. +- * +- * Returns 0 for success or -1 for error +- * +- * @p: Params for the channel that we are using +- * @used: number of pages used +- * @errp: pointer to an error +- */ +-static int nocomp_send_write(MultiFDSendParams *p, uint32_t used, Error **errp) +-{ +- return qio_channel_writev_all(p->c, p->iov, p->iovs_num, errp); +-} +- + /** + * nocomp_recv_setup: setup receive side + * +@@ -173,7 +157,6 @@ static MultiFDMethods multifd_nocomp_ops = { + .send_setup = nocomp_send_setup, + .send_cleanup = nocomp_send_cleanup, + .send_prepare = nocomp_send_prepare, +- .send_write = nocomp_send_write, + .recv_setup = nocomp_recv_setup, + .recv_cleanup = nocomp_recv_cleanup, + .recv_pages = nocomp_recv_pages +@@ -687,7 +670,8 @@ static void *multifd_send_thread(void *opaque) + } + + if (used) { +- ret = multifd_send_state->ops->send_write(p, used, &local_err); ++ ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num, ++ &local_err); + if (ret != 0) { + break; + } +diff --git a/migration/multifd.h b/migration/multifd.h +index c3f18af364..7496f951a7 100644 +--- a/migration/multifd.h ++++ b/migration/multifd.h +@@ -164,8 +164,6 @@ typedef struct { + void (*send_cleanup)(MultiFDSendParams *p, Error **errp); + /* Prepare the send packet */ + int (*send_prepare)(MultiFDSendParams *p, Error **errp); +- /* Write the send packet */ +- int (*send_write)(MultiFDSendParams *p, uint32_t used, Error **errp); + /* Setup for receiving side */ + int (*recv_setup)(MultiFDRecvParams *p, Error **errp); + /* Cleanup for receiving side */ +-- +2.35.3 + diff --git a/kvm-multifd-Rename-used-field-to-num.patch b/kvm-multifd-Rename-used-field-to-num.patch new file mode 100644 index 0000000..51bbfbe --- /dev/null +++ b/kvm-multifd-Rename-used-field-to-num.patch @@ -0,0 +1,177 @@ +From 030004b805604114aeaf8b9344b496332f433f71 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:22 -0300 +Subject: [PATCH 02/34] multifd: Rename used field to num +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [2/34] 5e411060b289cdabdf66c0774a55e109c0ef2906 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +We will need to split it later in zero_num (number of zero pages) and +normal_num (number of normal pages). This name is better. + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 90a3d2f9d5f729147b2827c177932603ae6e2d55) +Signed-off-by: Leonardo Bras +--- + migration/multifd.c | 38 +++++++++++++++++++------------------- + migration/multifd.h | 2 +- + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/migration/multifd.c b/migration/multifd.c +index 8125d0015c..8ea86d81dc 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -252,7 +252,7 @@ static MultiFDPages_t *multifd_pages_init(size_t size) + + static void multifd_pages_clear(MultiFDPages_t *pages) + { +- pages->used = 0; ++ pages->num = 0; + pages->allocated = 0; + pages->packet_num = 0; + pages->block = NULL; +@@ -270,7 +270,7 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) + + packet->flags = cpu_to_be32(p->flags); + packet->pages_alloc = cpu_to_be32(p->pages->allocated); +- packet->pages_used = cpu_to_be32(p->pages->used); ++ packet->pages_used = cpu_to_be32(p->pages->num); + packet->next_packet_size = cpu_to_be32(p->next_packet_size); + packet->packet_num = cpu_to_be64(p->packet_num); + +@@ -278,7 +278,7 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) + strncpy(packet->ramblock, p->pages->block->idstr, 256); + } + +- for (i = 0; i < p->pages->used; i++) { ++ for (i = 0; i < p->pages->num; i++) { + /* there are architectures where ram_addr_t is 32 bit */ + uint64_t temp = p->pages->offset[i]; + +@@ -332,18 +332,18 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + p->pages = multifd_pages_init(packet->pages_alloc); + } + +- p->pages->used = be32_to_cpu(packet->pages_used); +- if (p->pages->used > packet->pages_alloc) { ++ p->pages->num = be32_to_cpu(packet->pages_used); ++ if (p->pages->num > packet->pages_alloc) { + error_setg(errp, "multifd: received packet " + "with %d pages and expected maximum pages are %d", +- p->pages->used, packet->pages_alloc) ; ++ p->pages->num, packet->pages_alloc) ; + return -1; + } + + p->next_packet_size = be32_to_cpu(packet->next_packet_size); + p->packet_num = be64_to_cpu(packet->packet_num); + +- if (p->pages->used == 0) { ++ if (p->pages->num == 0) { + return 0; + } + +@@ -356,7 +356,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) + return -1; + } + +- for (i = 0; i < p->pages->used; i++) { ++ for (i = 0; i < p->pages->num; i++) { + uint64_t offset = be64_to_cpu(packet->offset[i]); + + if (offset > (block->used_length - page_size)) { +@@ -443,13 +443,13 @@ static int multifd_send_pages(QEMUFile *f) + } + qemu_mutex_unlock(&p->mutex); + } +- assert(!p->pages->used); ++ assert(!p->pages->num); + assert(!p->pages->block); + + p->packet_num = multifd_send_state->packet_num++; + multifd_send_state->pages = p->pages; + p->pages = pages; +- transferred = ((uint64_t) pages->used) * qemu_target_page_size() ++ transferred = ((uint64_t) pages->num) * qemu_target_page_size() + + p->packet_len; + qemu_file_update_transfer(f, transferred); + ram_counters.multifd_bytes += transferred; +@@ -469,12 +469,12 @@ int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset) + } + + if (pages->block == block) { +- pages->offset[pages->used] = offset; +- pages->iov[pages->used].iov_base = block->host + offset; +- pages->iov[pages->used].iov_len = qemu_target_page_size(); +- pages->used++; ++ pages->offset[pages->num] = offset; ++ pages->iov[pages->num].iov_base = block->host + offset; ++ pages->iov[pages->num].iov_len = qemu_target_page_size(); ++ pages->num++; + +- if (pages->used < pages->allocated) { ++ if (pages->num < pages->allocated) { + return 1; + } + } +@@ -586,7 +586,7 @@ void multifd_send_sync_main(QEMUFile *f) + if (!migrate_use_multifd()) { + return; + } +- if (multifd_send_state->pages->used) { ++ if (multifd_send_state->pages->num) { + if (multifd_send_pages(f) < 0) { + error_report("%s: multifd_send_pages fail", __func__); + return; +@@ -649,7 +649,7 @@ static void *multifd_send_thread(void *opaque) + qemu_mutex_lock(&p->mutex); + + if (p->pending_job) { +- uint32_t used = p->pages->used; ++ uint32_t used = p->pages->num; + uint64_t packet_num = p->packet_num; + flags = p->flags; + +@@ -665,7 +665,7 @@ static void *multifd_send_thread(void *opaque) + p->flags = 0; + p->num_packets++; + p->num_pages += used; +- p->pages->used = 0; ++ p->pages->num = 0; + p->pages->block = NULL; + qemu_mutex_unlock(&p->mutex); + +@@ -1091,7 +1091,7 @@ static void *multifd_recv_thread(void *opaque) + break; + } + +- used = p->pages->used; ++ used = p->pages->num; + flags = p->flags; + /* recv methods don't know how to handle the SYNC flag */ + p->flags &= ~MULTIFD_FLAG_SYNC; +diff --git a/migration/multifd.h b/migration/multifd.h +index 15c50ca0b2..86820dd028 100644 +--- a/migration/multifd.h ++++ b/migration/multifd.h +@@ -55,7 +55,7 @@ typedef struct { + + typedef struct { + /* number of used pages */ +- uint32_t used; ++ uint32_t num; + /* number of allocated pages */ + uint32_t allocated; + /* global number of generated multifd packets */ +-- +2.35.3 + diff --git a/kvm-multifd-Send-header-packet-without-flags-if-zero-cop.patch b/kvm-multifd-Send-header-packet-without-flags-if-zero-cop.patch new file mode 100644 index 0000000..cb12219 --- /dev/null +++ b/kvm-multifd-Send-header-packet-without-flags-if-zero-cop.patch @@ -0,0 +1,102 @@ +From 8a1b74503b17a1f48283eeec547579aad5bdb8f9 Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Wed, 18 May 2022 02:52:25 -0300 +Subject: [PATCH 22/34] multifd: Send header packet without flags if + zero-copy-send is enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [22/34] f8ea6e11134afe5291b6f404dc9b59557fbf1030 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Since d48c3a0445 ("multifd: Use a single writev on the send side"), +sending the header packet and the memory pages happens in the same +writev, which can potentially make the migration faster. + +Using channel-socket as example, this works well with the default copying +mechanism of sendmsg(), but with zero-copy-send=true, it will cause +the migration to often break. + +This happens because the header packet buffer gets reused quite often, +and there is a high chance that by the time the MSG_ZEROCOPY mechanism get +to send the buffer, it has already changed, sending the wrong data and +causing the migration to abort. + +It means that, as it is, the buffer for the header packet is not suitable +for sending with MSG_ZEROCOPY. + +In order to enable zero copy for multifd, send the header packet on an +individual write(), without any flags, and the remanining pages with a +writev(), as it was happening before. This only changes how a migration +with zero-copy-send=true works, not changing any current behavior for +migrations with zero-copy-send=false. + +Signed-off-by: Leonardo Bras +Reviewed-by: Peter Xu +Reviewed-by: Daniel P. Berrangé +Message-Id: <20220513062836.965425-8-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit b7dbdd8e76cd03453c234dbb9578d20969859d74) +Signed-off-by: Leonardo Bras +--- + migration/multifd.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/migration/multifd.c b/migration/multifd.c +index 1e34e01ebc..193f70cdba 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -624,6 +624,7 @@ static void *multifd_send_thread(void *opaque) + MultiFDSendParams *p = opaque; + Error *local_err = NULL; + int ret = 0; ++ bool use_zero_copy_send = migrate_use_zero_copy_send(); + + trace_multifd_send_thread_start(p->id); + rcu_register_thread(); +@@ -646,9 +647,14 @@ static void *multifd_send_thread(void *opaque) + if (p->pending_job) { + uint64_t packet_num = p->packet_num; + uint32_t flags = p->flags; +- p->iovs_num = 1; + p->normal_num = 0; + ++ if (use_zero_copy_send) { ++ p->iovs_num = 0; ++ } else { ++ p->iovs_num = 1; ++ } ++ + for (int i = 0; i < p->pages->num; i++) { + p->normal[p->normal_num] = p->pages->offset[i]; + p->normal_num++; +@@ -672,8 +678,18 @@ static void *multifd_send_thread(void *opaque) + trace_multifd_send(p->id, packet_num, p->normal_num, flags, + p->next_packet_size); + +- p->iov[0].iov_len = p->packet_len; +- p->iov[0].iov_base = p->packet; ++ if (use_zero_copy_send) { ++ /* Send header first, without zerocopy */ ++ ret = qio_channel_write_all(p->c, (void *)p->packet, ++ p->packet_len, &local_err); ++ if (ret != 0) { ++ break; ++ } ++ } else { ++ /* Send header using the same writev call */ ++ p->iov[0].iov_len = p->packet_len; ++ p->iov[0].iov_base = p->packet; ++ } + + ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num, + &local_err); +-- +2.35.3 + diff --git a/kvm-multifd-The-variable-is-only-used-inside-the-loop.patch b/kvm-multifd-The-variable-is-only-used-inside-the-loop.patch new file mode 100644 index 0000000..5f03ced --- /dev/null +++ b/kvm-multifd-The-variable-is-only-used-inside-the-loop.patch @@ -0,0 +1,48 @@ +From 8814fdd9eba7a69c2b5f7df8a8db49d7c2ac8378 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:23 -0300 +Subject: [PATCH 04/34] multifd: The variable is only used inside the loop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [4/34] ea2b915fa5e795d88edaa3e0cf39a9f2c3cc2050 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 1943c11a62bd0741e5d9fbba78404fe47ebea820) +Signed-off-by: Leonardo Bras +--- + migration/multifd.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/migration/multifd.c b/migration/multifd.c +index cdeffdc4c5..ce7101cf9d 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -629,7 +629,6 @@ static void *multifd_send_thread(void *opaque) + MultiFDSendParams *p = opaque; + Error *local_err = NULL; + int ret = 0; +- uint32_t flags = 0; + + trace_multifd_send_thread_start(p->id); + rcu_register_thread(); +@@ -652,7 +651,7 @@ static void *multifd_send_thread(void *opaque) + if (p->pending_job) { + uint32_t used = p->pages->num; + uint64_t packet_num = p->packet_num; +- flags = p->flags; ++ uint32_t flags = p->flags; + + if (used) { + ret = multifd_send_state->ops->send_prepare(p, used, +-- +2.35.3 + diff --git a/kvm-multifd-Use-a-single-writev-on-the-send-side.patch b/kvm-multifd-Use-a-single-writev-on-the-send-side.patch new file mode 100644 index 0000000..495e201 --- /dev/null +++ b/kvm-multifd-Use-a-single-writev-on-the-send-side.patch @@ -0,0 +1,80 @@ +From ef864989dbe480e952bb3c5ea3cd9dfcf97bd455 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:24 -0300 +Subject: [PATCH 15/34] multifd: Use a single writev on the send side +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [15/34] 3e421f67a5f69231280ed748318c0317da31ae95 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Until now, we wrote the packet header with write(), and the rest of the +pages with writev(). Just increase the size of the iovec and do a +single writev(). + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit d48c3a044537689866fe44e65d24c7d39a68868a) +Signed-off-by: Leonardo Bras +--- + migration/multifd.c | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +diff --git a/migration/multifd.c b/migration/multifd.c +index 1e1551d78b..d0f86542b1 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -643,7 +643,7 @@ static void *multifd_send_thread(void *opaque) + uint32_t used = p->pages->num; + uint64_t packet_num = p->packet_num; + uint32_t flags = p->flags; +- p->iovs_num = 0; ++ p->iovs_num = 1; + + if (used) { + ret = multifd_send_state->ops->send_prepare(p, &local_err); +@@ -663,20 +663,15 @@ static void *multifd_send_thread(void *opaque) + trace_multifd_send(p->id, packet_num, used, flags, + p->next_packet_size); + +- ret = qio_channel_write_all(p->c, (void *)p->packet, +- p->packet_len, &local_err); ++ p->iov[0].iov_len = p->packet_len; ++ p->iov[0].iov_base = p->packet; ++ ++ ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num, ++ &local_err); + if (ret != 0) { + break; + } + +- if (used) { +- ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num, +- &local_err); +- if (ret != 0) { +- break; +- } +- } +- + qemu_mutex_lock(&p->mutex); + p->pending_job--; + qemu_mutex_unlock(&p->mutex); +@@ -913,7 +908,8 @@ int multifd_save_setup(Error **errp) + p->packet->version = cpu_to_be32(MULTIFD_VERSION); + p->name = g_strdup_printf("multifdsend_%d", i); + p->tls_hostname = g_strdup(s->hostname); +- p->iov = g_new0(struct iovec, page_count); ++ /* We need one extra place for the packet header */ ++ p->iov = g_new0(struct iovec, page_count + 1); + socket_send_channel_create(multifd_new_send_channel_async, p); + } + +-- +2.35.3 + diff --git a/kvm-multifd-Use-normal-pages-array-on-the-send-side.patch b/kvm-multifd-Use-normal-pages-array-on-the-send-side.patch new file mode 100644 index 0000000..2bd055b --- /dev/null +++ b/kvm-multifd-Use-normal-pages-array-on-the-send-side.patch @@ -0,0 +1,261 @@ +From c70c97cd59fd22de0957ea1c0a655fb5ef270f1e Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:24 -0300 +Subject: [PATCH 16/34] multifd: Use normal pages array on the send side +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [16/34] 24f4ea3248f6ce883d57344600c8adbf51bd7d8c +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +We are only sending normal pages through multifd channels. +Later on this series, we are going to also send zero pages. +We are going to detect if a page is zero or non zero in the multifd +channel thread, not on the main thread. + +So we receive an array of pages page->offset[N] + +And we will end with: + +p->normal[N - zero_pages] +p->zero[zero_pages]. + +In this patch, we just copy all the pages in offset to normal. + +for (i = 0; i < pages->num; i++) { + p->narmal[p->normal_num] = pages->offset[i]; + p->normal_num++: +} + +Later in the series this becomes: + +for (i = 0; i < pages->num; i++) { + if (buffer_is_zero(page->offset[i])) { + p->zerol[p->zero_num] = pages->offset[i]; + p->zero_num++: + } else { + p->narmal[p->normal_num] = pages->offset[i]; + p->normal_num++: + } +} + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert + +--- + +Improving comment (dave) +Renaming num_normal_pages to total_normal_pages (peter) + +(cherry picked from commit 815956f03902980c771da64b17f7f791c1cb57b0) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zlib.c | 6 +++--- + migration/multifd-zstd.c | 6 +++--- + migration/multifd.c | 30 +++++++++++++++++++----------- + migration/multifd.h | 8 ++++++-- + migration/trace-events | 4 ++-- + 5 files changed, 33 insertions(+), 21 deletions(-) + +diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c +index 8ed29b9633..8508f26adf 100644 +--- a/migration/multifd-zlib.c ++++ b/migration/multifd-zlib.c +@@ -108,16 +108,16 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) + int ret; + uint32_t i; + +- for (i = 0; i < p->pages->num; i++) { ++ for (i = 0; i < p->normal_num; i++) { + uint32_t available = z->zbuff_len - out_size; + int flush = Z_NO_FLUSH; + +- if (i == p->pages->num - 1) { ++ if (i == p->normal_num - 1) { + flush = Z_SYNC_FLUSH; + } + + zs->avail_in = page_size; +- zs->next_in = p->pages->block->host + p->pages->offset[i]; ++ zs->next_in = p->pages->block->host + p->normal[i]; + + zs->avail_out = available; + zs->next_out = z->zbuff + out_size; +diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c +index 25e1f517b5..693af3a140 100644 +--- a/migration/multifd-zstd.c ++++ b/migration/multifd-zstd.c +@@ -123,13 +123,13 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) + z->out.size = z->zbuff_len; + z->out.pos = 0; + +- for (i = 0; i < p->pages->num; i++) { ++ for (i = 0; i < p->normal_num; i++) { + ZSTD_EndDirective flush = ZSTD_e_continue; + +- if (i == p->pages->num - 1) { ++ if (i == p->normal_num - 1) { + flush = ZSTD_e_flush; + } +- z->in.src = p->pages->block->host + p->pages->offset[i]; ++ z->in.src = p->pages->block->host + p->normal[i]; + z->in.size = page_size; + z->in.pos = 0; + +diff --git a/migration/multifd.c b/migration/multifd.c +index d0f86542b1..3725226400 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -89,13 +89,13 @@ static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp) + MultiFDPages_t *pages = p->pages; + size_t page_size = qemu_target_page_size(); + +- for (int i = 0; i < p->pages->num; i++) { +- p->iov[p->iovs_num].iov_base = pages->block->host + pages->offset[i]; ++ for (int i = 0; i < p->normal_num; i++) { ++ p->iov[p->iovs_num].iov_base = pages->block->host + p->normal[i]; + p->iov[p->iovs_num].iov_len = page_size; + p->iovs_num++; + } + +- p->next_packet_size = p->pages->num * page_size; ++ p->next_packet_size = p->normal_num * page_size; + p->flags |= MULTIFD_FLAG_NOCOMP; + return 0; + } +@@ -262,7 +262,7 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) + + packet->flags = cpu_to_be32(p->flags); + packet->pages_alloc = cpu_to_be32(p->pages->allocated); +- packet->pages_used = cpu_to_be32(p->pages->num); ++ packet->pages_used = cpu_to_be32(p->normal_num); + packet->next_packet_size = cpu_to_be32(p->next_packet_size); + packet->packet_num = cpu_to_be64(p->packet_num); + +@@ -270,9 +270,9 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) + strncpy(packet->ramblock, p->pages->block->idstr, 256); + } + +- for (i = 0; i < p->pages->num; i++) { ++ for (i = 0; i < p->normal_num; i++) { + /* there are architectures where ram_addr_t is 32 bit */ +- uint64_t temp = p->pages->offset[i]; ++ uint64_t temp = p->normal[i]; + + packet->offset[i] = cpu_to_be64(temp); + } +@@ -556,6 +556,8 @@ void multifd_save_cleanup(void) + p->packet = NULL; + g_free(p->iov); + p->iov = NULL; ++ g_free(p->normal); ++ p->normal = NULL; + multifd_send_state->ops->send_cleanup(p, &local_err); + if (local_err) { + migrate_set_error(migrate_get_current(), local_err); +@@ -640,12 +642,17 @@ static void *multifd_send_thread(void *opaque) + qemu_mutex_lock(&p->mutex); + + if (p->pending_job) { +- uint32_t used = p->pages->num; + uint64_t packet_num = p->packet_num; + uint32_t flags = p->flags; + p->iovs_num = 1; ++ p->normal_num = 0; ++ ++ for (int i = 0; i < p->pages->num; i++) { ++ p->normal[p->normal_num] = p->pages->offset[i]; ++ p->normal_num++; ++ } + +- if (used) { ++ if (p->normal_num) { + ret = multifd_send_state->ops->send_prepare(p, &local_err); + if (ret != 0) { + qemu_mutex_unlock(&p->mutex); +@@ -655,12 +662,12 @@ static void *multifd_send_thread(void *opaque) + multifd_send_fill_packet(p); + p->flags = 0; + p->num_packets++; +- p->num_pages += used; ++ p->total_normal_pages += p->normal_num; + p->pages->num = 0; + p->pages->block = NULL; + qemu_mutex_unlock(&p->mutex); + +- trace_multifd_send(p->id, packet_num, used, flags, ++ trace_multifd_send(p->id, packet_num, p->normal_num, flags, + p->next_packet_size); + + p->iov[0].iov_len = p->packet_len; +@@ -710,7 +717,7 @@ out: + qemu_mutex_unlock(&p->mutex); + + rcu_unregister_thread(); +- trace_multifd_send_thread_end(p->id, p->num_packets, p->num_pages); ++ trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages); + + return NULL; + } +@@ -910,6 +917,7 @@ int multifd_save_setup(Error **errp) + p->tls_hostname = g_strdup(s->hostname); + /* We need one extra place for the packet header */ + p->iov = g_new0(struct iovec, page_count + 1); ++ p->normal = g_new0(ram_addr_t, page_count); + socket_send_channel_create(multifd_new_send_channel_async, p); + } + +diff --git a/migration/multifd.h b/migration/multifd.h +index 7496f951a7..7823199dbe 100644 +--- a/migration/multifd.h ++++ b/migration/multifd.h +@@ -104,14 +104,18 @@ typedef struct { + /* thread local variables */ + /* packets sent through this channel */ + uint64_t num_packets; +- /* pages sent through this channel */ +- uint64_t num_pages; ++ /* non zero pages sent through this channel */ ++ uint64_t total_normal_pages; + /* syncs main thread and channels */ + QemuSemaphore sem_sync; + /* buffers to send */ + struct iovec *iov; + /* number of iovs used */ + uint32_t iovs_num; ++ /* Pages that are not zero */ ++ ram_addr_t *normal; ++ /* num of non zero pages */ ++ uint32_t normal_num; + /* used for compression methods */ + void *data; + } MultiFDSendParams; +diff --git a/migration/trace-events b/migration/trace-events +index 5172cb3b3d..171a83a55d 100644 +--- a/migration/trace-events ++++ b/migration/trace-events +@@ -124,13 +124,13 @@ multifd_recv_sync_main_wait(uint8_t id) "channel %u" + multifd_recv_terminate_threads(bool error) "error %d" + multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %u packets %" PRIu64 " pages %" PRIu64 + multifd_recv_thread_start(uint8_t id) "%u" +-multifd_send(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " pages %u flags 0x%x next packet size %u" ++multifd_send(uint8_t id, uint64_t packet_num, uint32_t normal, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " normal pages %u flags 0x%x next packet size %u" + multifd_send_error(uint8_t id) "channel %u" + multifd_send_sync_main(long packet_num) "packet num %ld" + multifd_send_sync_main_signal(uint8_t id) "channel %u" + multifd_send_sync_main_wait(uint8_t id) "channel %u" + multifd_send_terminate_threads(bool error) "error %d" +-multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %u packets %" PRIu64 " pages %" PRIu64 ++multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t normal_pages) "channel %u packets %" PRIu64 " normal pages %" PRIu64 + multifd_send_thread_start(uint8_t id) "%u" + multifd_tls_outgoing_handshake_start(void *ioc, void *tioc, const char *hostname) "ioc=%p tioc=%p hostname=%s" + multifd_tls_outgoing_handshake_error(void *ioc, const char *err) "ioc=%p err=%s" +-- +2.35.3 + diff --git a/kvm-multifd-multifd_send_sync_main-now-returns-negative-.patch b/kvm-multifd-multifd_send_sync_main-now-returns-negative-.patch new file mode 100644 index 0000000..a5b3747 --- /dev/null +++ b/kvm-multifd-multifd_send_sync_main-now-returns-negative-.patch @@ -0,0 +1,163 @@ +From 9d8968ae10e1724198c493646e2bdcd55f205e5e Mon Sep 17 00:00:00 2001 +From: Leonardo Bras +Date: Wed, 18 May 2022 02:52:25 -0300 +Subject: [PATCH 21/34] multifd: multifd_send_sync_main now returns negative on + error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [21/34] bef7acbe751fc4871a9ece72ab58b195658d6328 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +Even though multifd_send_sync_main() currently emits error_reports, it's +callers don't really check it before continuing. + +Change multifd_send_sync_main() to return -1 on error and 0 on success. +Also change all it's callers to make use of this change and possibly fail +earlier. + +(This change is important to next patch on multifd zero copy +implementation, to make it sure an error in zero-copy flush does not go +unnoticed. + +Signed-off-by: Leonardo Bras +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Peter Xu +Message-Id: <20220513062836.965425-7-leobras@redhat.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 33d70973a3a6e8c6b62bcbc64d9e488961981007) +Signed-off-by: Leonardo Bras +--- + migration/multifd.c | 10 ++++++---- + migration/multifd.h | 2 +- + migration/ram.c | 29 ++++++++++++++++++++++------- + 3 files changed, 29 insertions(+), 12 deletions(-) + +diff --git a/migration/multifd.c b/migration/multifd.c +index e53811f04a..1e34e01ebc 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -573,17 +573,17 @@ void multifd_save_cleanup(void) + multifd_send_state = NULL; + } + +-void multifd_send_sync_main(QEMUFile *f) ++int multifd_send_sync_main(QEMUFile *f) + { + int i; + + if (!migrate_use_multifd()) { +- return; ++ return 0; + } + if (multifd_send_state->pages->num) { + if (multifd_send_pages(f) < 0) { + error_report("%s: multifd_send_pages fail", __func__); +- return; ++ return -1; + } + } + for (i = 0; i < migrate_multifd_channels(); i++) { +@@ -596,7 +596,7 @@ void multifd_send_sync_main(QEMUFile *f) + if (p->quit) { + error_report("%s: channel %d has already quit", __func__, i); + qemu_mutex_unlock(&p->mutex); +- return; ++ return -1; + } + + p->packet_num = multifd_send_state->packet_num++; +@@ -615,6 +615,8 @@ void multifd_send_sync_main(QEMUFile *f) + qemu_sem_wait(&p->sem_sync); + } + trace_multifd_send_sync_main(multifd_send_state->packet_num); ++ ++ return 0; + } + + static void *multifd_send_thread(void *opaque) +diff --git a/migration/multifd.h b/migration/multifd.h +index 7823199dbe..92de878155 100644 +--- a/migration/multifd.h ++++ b/migration/multifd.h +@@ -22,7 +22,7 @@ int multifd_load_cleanup(Error **errp); + bool multifd_recv_all_channels_created(void); + bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp); + void multifd_recv_sync_main(void); +-void multifd_send_sync_main(QEMUFile *f); ++int multifd_send_sync_main(QEMUFile *f); + int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset); + + /* Multifd Compression flags */ +diff --git a/migration/ram.c b/migration/ram.c +index 863035d235..3e208efca7 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -2992,6 +2992,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + { + RAMState **rsp = opaque; + RAMBlock *block; ++ int ret; + + if (compress_threads_save_setup()) { + return -1; +@@ -3026,7 +3027,11 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + ram_control_before_iterate(f, RAM_CONTROL_SETUP); + ram_control_after_iterate(f, RAM_CONTROL_SETUP); + +- multifd_send_sync_main(f); ++ ret = multifd_send_sync_main(f); ++ if (ret < 0) { ++ return ret; ++ } ++ + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + qemu_fflush(f); + +@@ -3135,7 +3140,11 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) + out: + if (ret >= 0 + && migration_is_setup_or_active(migrate_get_current()->state)) { +- multifd_send_sync_main(rs->f); ++ ret = multifd_send_sync_main(rs->f); ++ if (ret < 0) { ++ return ret; ++ } ++ + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + qemu_fflush(f); + ram_counters.transferred += 8; +@@ -3193,13 +3202,19 @@ static int ram_save_complete(QEMUFile *f, void *opaque) + ram_control_after_iterate(f, RAM_CONTROL_FINISH); + } + +- if (ret >= 0) { +- multifd_send_sync_main(rs->f); +- qemu_put_be64(f, RAM_SAVE_FLAG_EOS); +- qemu_fflush(f); ++ if (ret < 0) { ++ return ret; + } + +- return ret; ++ ret = multifd_send_sync_main(rs->f); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ qemu_put_be64(f, RAM_SAVE_FLAG_EOS); ++ qemu_fflush(f); ++ ++ return 0; + } + + static void ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, +-- +2.35.3 + diff --git a/kvm-multifd-remove-used-parameter-from-send_prepare-meth.patch b/kvm-multifd-remove-used-parameter-from-send_prepare-meth.patch new file mode 100644 index 0000000..a3b973d --- /dev/null +++ b/kvm-multifd-remove-used-parameter-from-send_prepare-meth.patch @@ -0,0 +1,135 @@ +From 46c902b006cbf52341804e85f9246bdc8afc8611 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:23 -0300 +Subject: [PATCH 05/34] multifd: remove used parameter from send_prepare() + method +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [5/34] b4f1c9540bddd137756cab4bde4ba5d8eac09ab9 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +It is already there as p->pages->num. + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 02fb81043ecee338e4aeb8f5be09a46325dc5e43) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zlib.c | 7 +++---- + migration/multifd-zstd.c | 7 +++---- + migration/multifd.c | 9 +++------ + migration/multifd.h | 2 +- + 4 files changed, 10 insertions(+), 15 deletions(-) + +diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c +index f403d2f031..0c70a2dc78 100644 +--- a/migration/multifd-zlib.c ++++ b/migration/multifd-zlib.c +@@ -96,10 +96,9 @@ static void zlib_send_cleanup(MultiFDSendParams *p, Error **errp) + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using +- * @used: number of pages used + * @errp: pointer to an error + */ +-static int zlib_send_prepare(MultiFDSendParams *p, uint32_t used, Error **errp) ++static int zlib_send_prepare(MultiFDSendParams *p, Error **errp) + { + struct iovec *iov = p->pages->iov; + struct zlib_data *z = p->data; +@@ -108,11 +107,11 @@ static int zlib_send_prepare(MultiFDSendParams *p, uint32_t used, Error **errp) + int ret; + uint32_t i; + +- for (i = 0; i < used; i++) { ++ for (i = 0; i < p->pages->num; i++) { + uint32_t available = z->zbuff_len - out_size; + int flush = Z_NO_FLUSH; + +- if (i == used - 1) { ++ if (i == p->pages->num - 1) { + flush = Z_SYNC_FLUSH; + } + +diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c +index 8d657f8860..466b370cad 100644 +--- a/migration/multifd-zstd.c ++++ b/migration/multifd-zstd.c +@@ -109,10 +109,9 @@ static void zstd_send_cleanup(MultiFDSendParams *p, Error **errp) + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using +- * @used: number of pages used + * @errp: pointer to an error + */ +-static int zstd_send_prepare(MultiFDSendParams *p, uint32_t used, Error **errp) ++static int zstd_send_prepare(MultiFDSendParams *p, Error **errp) + { + struct iovec *iov = p->pages->iov; + struct zstd_data *z = p->data; +@@ -123,10 +122,10 @@ static int zstd_send_prepare(MultiFDSendParams *p, uint32_t used, Error **errp) + z->out.size = z->zbuff_len; + z->out.pos = 0; + +- for (i = 0; i < used; i++) { ++ for (i = 0; i < p->pages->num; i++) { + ZSTD_EndDirective flush = ZSTD_e_continue; + +- if (i == used - 1) { ++ if (i == p->pages->num - 1) { + flush = ZSTD_e_flush; + } + z->in.src = iov[i].iov_base; +diff --git a/migration/multifd.c b/migration/multifd.c +index ce7101cf9d..098ef8842c 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -82,13 +82,11 @@ static void nocomp_send_cleanup(MultiFDSendParams *p, Error **errp) + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using +- * @used: number of pages used + * @errp: pointer to an error + */ +-static int nocomp_send_prepare(MultiFDSendParams *p, uint32_t used, +- Error **errp) ++static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp) + { +- p->next_packet_size = used * qemu_target_page_size(); ++ p->next_packet_size = p->pages->num * qemu_target_page_size(); + p->flags |= MULTIFD_FLAG_NOCOMP; + return 0; + } +@@ -654,8 +652,7 @@ static void *multifd_send_thread(void *opaque) + uint32_t flags = p->flags; + + if (used) { +- ret = multifd_send_state->ops->send_prepare(p, used, +- &local_err); ++ ret = multifd_send_state->ops->send_prepare(p, &local_err); + if (ret != 0) { + qemu_mutex_unlock(&p->mutex); + break; +diff --git a/migration/multifd.h b/migration/multifd.h +index 86820dd028..7968cc5c20 100644 +--- a/migration/multifd.h ++++ b/migration/multifd.h +@@ -159,7 +159,7 @@ typedef struct { + /* Cleanup for sending side */ + void (*send_cleanup)(MultiFDSendParams *p, Error **errp); + /* Prepare the send packet */ +- int (*send_prepare)(MultiFDSendParams *p, uint32_t used, Error **errp); ++ int (*send_prepare)(MultiFDSendParams *p, Error **errp); + /* Write the send packet */ + int (*send_write)(MultiFDSendParams *p, uint32_t used, Error **errp); + /* Setup for receiving side */ +-- +2.35.3 + diff --git a/kvm-multifd-remove-used-parameter-from-send_recv_pages-m.patch b/kvm-multifd-remove-used-parameter-from-send_recv_pages-m.patch new file mode 100644 index 0000000..d019cf5 --- /dev/null +++ b/kvm-multifd-remove-used-parameter-from-send_recv_pages-m.patch @@ -0,0 +1,149 @@ +From 75ef79011b75d1024dc50a999d03ab90570e6533 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 18 May 2022 02:52:23 -0300 +Subject: [PATCH 06/34] multifd: remove used parameter from send_recv_pages() + method +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Leonardo Brás +RH-MergeRequest: 185: MSG_ZEROCOPY + Multifd @ rhel8.6 +RH-Commit: [6/34] fe59a7c794dd707cf71b2dc6104a0a89e2ac7d50 +RH-Bugzilla: 2117252 +RH-Acked-by: quintela1 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Peter Xu + +It is already there as p->pages->num. + +Signed-off-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +(cherry picked from commit 40a4bfe9d3f8ad35a9c3ffb4cbf7367e2777054b) +Signed-off-by: Leonardo Bras +--- + migration/multifd-zlib.c | 9 ++++----- + migration/multifd-zstd.c | 7 +++---- + migration/multifd.c | 7 +++---- + migration/multifd.h | 2 +- + 4 files changed, 11 insertions(+), 14 deletions(-) + +diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c +index 0c70a2dc78..330fc021c5 100644 +--- a/migration/multifd-zlib.c ++++ b/migration/multifd-zlib.c +@@ -235,17 +235,16 @@ static void zlib_recv_cleanup(MultiFDRecvParams *p) + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using +- * @used: number of pages used + * @errp: pointer to an error + */ +-static int zlib_recv_pages(MultiFDRecvParams *p, uint32_t used, Error **errp) ++static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp) + { + struct zlib_data *z = p->data; + z_stream *zs = &z->zs; + uint32_t in_size = p->next_packet_size; + /* we measure the change of total_out */ + uint32_t out_size = zs->total_out; +- uint32_t expected_size = used * qemu_target_page_size(); ++ uint32_t expected_size = p->pages->num * qemu_target_page_size(); + uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; + int ret; + int i; +@@ -264,12 +263,12 @@ static int zlib_recv_pages(MultiFDRecvParams *p, uint32_t used, Error **errp) + zs->avail_in = in_size; + zs->next_in = z->zbuff; + +- for (i = 0; i < used; i++) { ++ for (i = 0; i < p->pages->num; i++) { + struct iovec *iov = &p->pages->iov[i]; + int flush = Z_NO_FLUSH; + unsigned long start = zs->total_out; + +- if (i == used - 1) { ++ if (i == p->pages->num - 1) { + flush = Z_SYNC_FLUSH; + } + +diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c +index 466b370cad..f0d1105792 100644 +--- a/migration/multifd-zstd.c ++++ b/migration/multifd-zstd.c +@@ -255,14 +255,13 @@ static void zstd_recv_cleanup(MultiFDRecvParams *p) + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using +- * @used: number of pages used + * @errp: pointer to an error + */ +-static int zstd_recv_pages(MultiFDRecvParams *p, uint32_t used, Error **errp) ++static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp) + { + uint32_t in_size = p->next_packet_size; + uint32_t out_size = 0; +- uint32_t expected_size = used * qemu_target_page_size(); ++ uint32_t expected_size = p->pages->num * qemu_target_page_size(); + uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; + struct zstd_data *z = p->data; + int ret; +@@ -283,7 +282,7 @@ static int zstd_recv_pages(MultiFDRecvParams *p, uint32_t used, Error **errp) + z->in.size = in_size; + z->in.pos = 0; + +- for (i = 0; i < used; i++) { ++ for (i = 0; i < p->pages->num; i++) { + struct iovec *iov = &p->pages->iov[i]; + + z->out.dst = iov->iov_base; +diff --git a/migration/multifd.c b/migration/multifd.c +index 098ef8842c..55d99a8232 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -141,10 +141,9 @@ static void nocomp_recv_cleanup(MultiFDRecvParams *p) + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using +- * @used: number of pages used + * @errp: pointer to an error + */ +-static int nocomp_recv_pages(MultiFDRecvParams *p, uint32_t used, Error **errp) ++static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp) + { + uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; + +@@ -153,7 +152,7 @@ static int nocomp_recv_pages(MultiFDRecvParams *p, uint32_t used, Error **errp) + p->id, flags, MULTIFD_FLAG_NOCOMP); + return -1; + } +- return qio_channel_readv_all(p->c, p->pages->iov, used, errp); ++ return qio_channel_readv_all(p->c, p->pages->iov, p->pages->num, errp); + } + + static MultiFDMethods multifd_nocomp_ops = { +@@ -1099,7 +1098,7 @@ static void *multifd_recv_thread(void *opaque) + qemu_mutex_unlock(&p->mutex); + + if (used) { +- ret = multifd_recv_state->ops->recv_pages(p, used, &local_err); ++ ret = multifd_recv_state->ops->recv_pages(p, &local_err); + if (ret != 0) { + break; + } +diff --git a/migration/multifd.h b/migration/multifd.h +index 7968cc5c20..e57adc783b 100644 +--- a/migration/multifd.h ++++ b/migration/multifd.h +@@ -167,7 +167,7 @@ typedef struct { + /* Cleanup for receiving side */ + void (*recv_cleanup)(MultiFDRecvParams *p); + /* Read all pages */ +- int (*recv_pages)(MultiFDRecvParams *p, uint32_t used, Error **errp); ++ int (*recv_pages)(MultiFDRecvParams *p, Error **errp); + } MultiFDMethods; + + void multifd_register_ops(int method, MultiFDMethods *ops); +-- +2.35.3 + diff --git a/kvm-vhost-net-fix-improper-cleanup-in-vhost_net_start.patch b/kvm-vhost-net-fix-improper-cleanup-in-vhost_net_start.patch new file mode 100644 index 0000000..e736ac4 --- /dev/null +++ b/kvm-vhost-net-fix-improper-cleanup-in-vhost_net_start.patch @@ -0,0 +1,56 @@ +From 2206114457f3c575b2cf148ff643f78d5e67e8d2 Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:15 -0700 +Subject: [PATCH 4/7] vhost-net: fix improper cleanup in vhost_net_start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Cindy Lu +RH-MergeRequest: 203: vdpa :sync the Multiqueue fixes for vhost-vDPA +RH-Commit: [4/7] b09e0785b6e1c46da3ff59a8e4f4dea7d86e4f0b +RH-Bugzilla: 2095794 +RH-Acked-by: MST +RH-Acked-by: Eugenio Pérez +RH-Acked-by: Jason Wang + +vhost_net_start() missed a corresponding stop_one() upon error from +vhost_set_vring_enable(). While at it, make the error handling for +err_start more robust. No real issue was found due to this though. + +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-5-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 6f3910b5eee00b8cc959e94659c0d524c482a418) +Signed-off-by: Cindy Lu +--- + hw/net/vhost_net.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index 30379d2ca4..d6d7c51f62 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -381,6 +381,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, + r = vhost_set_vring_enable(peer, peer->vring_enable); + + if (r < 0) { ++ vhost_net_stop_one(get_vhost_net(peer), dev); + goto err_start; + } + } +@@ -390,7 +391,8 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, + + err_start: + while (--i >= 0) { +- peer = qemu_get_peer(ncs , i); ++ peer = qemu_get_peer(ncs, i < data_queue_pairs ? ++ i : n->max_queue_pairs); + vhost_net_stop_one(get_vhost_net(peer), dev); + } + e = k->set_guest_notifiers(qbus->parent, total_notifiers, false); +-- +2.31.1 + diff --git a/kvm-vhost-vdpa-backend-feature-should-set-only-once.patch b/kvm-vhost-vdpa-backend-feature-should-set-only-once.patch new file mode 100644 index 0000000..b4e1fd6 --- /dev/null +++ b/kvm-vhost-vdpa-backend-feature-should-set-only-once.patch @@ -0,0 +1,58 @@ +From 975046c44909eef91e8b3cfafe1c0dd55151937b Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:16 -0700 +Subject: [PATCH 5/7] vhost-vdpa: backend feature should set only once +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Cindy Lu +RH-MergeRequest: 203: vdpa :sync the Multiqueue fixes for vhost-vDPA +RH-Commit: [5/7] 8db716cb0cec794861c7a63c0b33ab7f8367232d +RH-Bugzilla: 2095794 +RH-Acked-by: MST +RH-Acked-by: Eugenio Pérez +RH-Acked-by: Jason Wang + +The vhost_vdpa_one_time_request() branch in +vhost_vdpa_set_backend_cap() incorrectly sends down +ioctls on vhost_dev with non-zero index. This may +end up with multiple VHOST_SET_BACKEND_FEATURES +ioctl calls sent down on the vhost-vdpa fd that is +shared between all these vhost_dev's. + +To fix it, send down ioctl only once via the first +vhost_dev with index 0. Toggle the polarity of the +vhost_vdpa_one_time_request() test should do the +trick. + +Fixes: 4d191cfdc7de ("vhost-vdpa: classify one time request") +Signed-off-by: Si-Wei Liu +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Acked-by: Eugenio Pérez +Message-Id: <1651890498-24478-6-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 6aee7e4233f6467f69531fcd352adff028f3f5ea) +Signed-off-by: Cindy Lu +--- + hw/virtio/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 78da48a333..a9be24776a 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -525,7 +525,7 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) + + features &= f; + +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_one_time_request(dev)) { + r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); + if (r) { + return -EFAULT; +-- +2.31.1 + diff --git a/kvm-vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch b/kvm-vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch new file mode 100644 index 0000000..9912a5f --- /dev/null +++ b/kvm-vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch @@ -0,0 +1,123 @@ +From 073595e503c4f13a7e598bdb83b2ea724d169cbf Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:17 -0700 +Subject: [PATCH 6/7] vhost-vdpa: change name and polarity for + vhost_vdpa_one_time_request() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Cindy Lu +RH-MergeRequest: 203: vdpa :sync the Multiqueue fixes for vhost-vDPA +RH-Commit: [6/7] 9ab7ee150e1876a170b56db36e94a5b3bbf09535 +RH-Bugzilla: 2095794 +RH-Acked-by: MST +RH-Acked-by: Eugenio Pérez +RH-Acked-by: Jason Wang + +The name vhost_vdpa_one_time_request() was confusing. No +matter whatever it returns, its typical occurrence had +always been at requests that only need to be applied once. +And the name didn't suggest what it actually checks for. +Change it to vhost_vdpa_first_dev() with polarity flipped +for better readibility of code. That way it is able to +reflect what the check is really about. + +This call is applicable to request which performs operation +only once, before queues are set up, and usually at the beginning +of the caller function. Document the requirement for it in place. + +Signed-off-by: Si-Wei Liu +Message-Id: <1651890498-24478-7-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +(cherry picked from commit d71b0609fc04217e28d17009f04d74b08be6f466) +Signed-off-by: Cindy Lu +--- + hw/virtio/vhost-vdpa.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index a9be24776a..38bbcb3c18 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -319,11 +319,18 @@ static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) + v->iova_range.last); + } + +-static bool vhost_vdpa_one_time_request(struct vhost_dev *dev) ++/* ++ * The use of this function is for requests that only need to be ++ * applied once. Typically such request occurs at the beginning ++ * of operation, and before setting up queues. It should not be ++ * used for request that performs operation until all queues are ++ * set, which would need to check dev->vq_index_end instead. ++ */ ++static bool vhost_vdpa_first_dev(struct vhost_dev *dev) + { + struct vhost_vdpa *v = dev->opaque; + +- return v->index != 0; ++ return v->index == 0; + } + + static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) +@@ -351,7 +358,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + + vhost_vdpa_get_iova_range(v); + +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -468,7 +475,7 @@ static int vhost_vdpa_memslots_limit(struct vhost_dev *dev) + static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, + struct vhost_memory *mem) + { +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -496,7 +503,7 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev, + { + int ret; + +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -525,7 +532,7 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) + + features &= f; + +- if (!vhost_vdpa_one_time_request(dev)) { ++ if (vhost_vdpa_first_dev(dev)) { + r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); + if (r) { + return -EFAULT; +@@ -670,7 +677,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log) + { +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -739,7 +746,7 @@ static int vhost_vdpa_get_features(struct vhost_dev *dev, + + static int vhost_vdpa_set_owner(struct vhost_dev *dev) + { +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +-- +2.31.1 + diff --git a/kvm-vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch b/kvm-vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch new file mode 100644 index 0000000..f258121 --- /dev/null +++ b/kvm-vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch @@ -0,0 +1,48 @@ +From 004f7409312c45f17eaaceac697637d3da257964 Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:14 -0700 +Subject: [PATCH 3/7] vhost-vdpa: fix improper cleanup in net_init_vhost_vdpa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Cindy Lu +RH-MergeRequest: 203: vdpa :sync the Multiqueue fixes for vhost-vDPA +RH-Commit: [3/7] 5f5e7577818744305f811667461e530acd9977d1 +RH-Bugzilla: 2095794 +RH-Acked-by: MST +RH-Acked-by: Eugenio Pérez +RH-Acked-by: Jason Wang + +... such that no memory leaks on dangling net clients in case of +error. + +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-4-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 9bd055073e375c8a0d7ebce925e05d914d69fc7f) +Signed-off-by: Cindy Lu +--- + net/vhost-vdpa.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 25dd6dd975..814f704687 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -306,7 +306,9 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + + err: + if (i) { +- qemu_del_net_client(ncs[0]); ++ for (i--; i >= 0; i--) { ++ qemu_del_net_client(ncs[i]); ++ } + } + qemu_close(vdpa_device_fd); + g_free(ncs); +-- +2.31.1 + diff --git a/kvm-virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch b/kvm-virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch new file mode 100644 index 0000000..d454622 --- /dev/null +++ b/kvm-virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch @@ -0,0 +1,143 @@ +From e1ff655fb1ca5812d0456e2054a5a9ab755d399b Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:13 -0700 +Subject: [PATCH 2/7] virtio-net: align ctrl_vq index for non-mq guest for + vhost_vdpa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Cindy Lu +RH-MergeRequest: 203: vdpa :sync the Multiqueue fixes for vhost-vDPA +RH-Commit: [2/7] bc60c58d6e36ea0698a72d806ac930e5cca199c7 +RH-Bugzilla: 2095794 +RH-Acked-by: MST +RH-Acked-by: Eugenio Pérez +RH-Acked-by: Jason Wang + +With MQ enabled vdpa device and non-MQ supporting guest e.g. +booting vdpa with mq=on over OVMF of single vqp, below assert +failure is seen: + +../hw/virtio/vhost-vdpa.c:560: vhost_vdpa_get_vq_index: Assertion `idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs' failed. + +0 0x00007f8ce3ff3387 in raise () at /lib64/libc.so.6 +1 0x00007f8ce3ff4a78 in abort () at /lib64/libc.so.6 +2 0x00007f8ce3fec1a6 in __assert_fail_base () at /lib64/libc.so.6 +3 0x00007f8ce3fec252 in () at /lib64/libc.so.6 +4 0x0000558f52d79421 in vhost_vdpa_get_vq_index (dev=, idx=) at ../hw/virtio/vhost-vdpa.c:563 +5 0x0000558f52d79421 in vhost_vdpa_get_vq_index (dev=, idx=) at ../hw/virtio/vhost-vdpa.c:558 +6 0x0000558f52d7329a in vhost_virtqueue_mask (hdev=0x558f55c01800, vdev=0x558f568f91f0, n=2, mask=) at ../hw/virtio/vhost.c:1557 +7 0x0000558f52c6b89a in virtio_pci_set_guest_notifier (d=d@entry=0x558f568f0f60, n=n@entry=2, assign=assign@entry=true, with_irqfd=with_irqfd@entry=false) + at ../hw/virtio/virtio-pci.c:974 +8 0x0000558f52c6c0d8 in virtio_pci_set_guest_notifiers (d=0x558f568f0f60, nvqs=3, assign=true) at ../hw/virtio/virtio-pci.c:1019 +9 0x0000558f52bf091d in vhost_net_start (dev=dev@entry=0x558f568f91f0, ncs=0x558f56937cd0, data_queue_pairs=data_queue_pairs@entry=1, cvq=cvq@entry=1) + at ../hw/net/vhost_net.c:361 +10 0x0000558f52d4e5e7 in virtio_net_set_status (status=, n=0x558f568f91f0) at ../hw/net/virtio-net.c:289 +11 0x0000558f52d4e5e7 in virtio_net_set_status (vdev=0x558f568f91f0, status=15 '\017') at ../hw/net/virtio-net.c:370 +12 0x0000558f52d6c4b2 in virtio_set_status (vdev=vdev@entry=0x558f568f91f0, val=val@entry=15 '\017') at ../hw/virtio/virtio.c:1945 +13 0x0000558f52c69eff in virtio_pci_common_write (opaque=0x558f568f0f60, addr=, val=, size=) at ../hw/virtio/virtio-pci.c:1292 +14 0x0000558f52d15d6e in memory_region_write_accessor (mr=0x558f568f19d0, addr=20, value=, size=1, shift=, mask=, attrs=...) + at ../softmmu/memory.c:492 +15 0x0000558f52d127de in access_with_adjusted_size (addr=addr@entry=20, value=value@entry=0x7f8cdbffe748, size=size@entry=1, access_size_min=, access_size_max=, access_fn=0x558f52d15cf0 , mr=0x558f568f19d0, attrs=...) at ../softmmu/memory.c:554 +16 0x0000558f52d157ef in memory_region_dispatch_write (mr=mr@entry=0x558f568f19d0, addr=20, data=, op=, attrs=attrs@entry=...) + at ../softmmu/memory.c:1504 +17 0x0000558f52d078e7 in flatview_write_continue (fv=fv@entry=0x7f8accbc3b90, addr=addr@entry=103079215124, attrs=..., ptr=ptr@entry=0x7f8ce6300028, len=len@entry=1, addr1=, l=, mr=0x558f568f19d0) at /home/opc/qemu-upstream/include/qemu/host-utils.h:165 +18 0x0000558f52d07b06 in flatview_write (fv=0x7f8accbc3b90, addr=103079215124, attrs=..., buf=0x7f8ce6300028, len=1) at ../softmmu/physmem.c:2822 +19 0x0000558f52d0b36b in address_space_write (as=, addr=, attrs=..., buf=buf@entry=0x7f8ce6300028, len=) + at ../softmmu/physmem.c:2914 +20 0x0000558f52d0b3da in address_space_rw (as=, addr=, attrs=..., + attrs@entry=..., buf=buf@entry=0x7f8ce6300028, len=, is_write=) at ../softmmu/physmem.c:2924 +21 0x0000558f52dced09 in kvm_cpu_exec (cpu=cpu@entry=0x558f55c2da60) at ../accel/kvm/kvm-all.c:2903 +22 0x0000558f52dcfabd in kvm_vcpu_thread_fn (arg=arg@entry=0x558f55c2da60) at ../accel/kvm/kvm-accel-ops.c:49 +23 0x0000558f52f9f04a in qemu_thread_start (args=) at ../util/qemu-thread-posix.c:556 +24 0x00007f8ce4392ea5 in start_thread () at /lib64/libpthread.so.0 +25 0x00007f8ce40bb9fd in clone () at /lib64/libc.so.6 + +The cause for the assert failure is due to that the vhost_dev index +for the ctrl vq was not aligned with actual one in use by the guest. +Upon multiqueue feature negotiation in virtio_net_set_multiqueue(), +if guest doesn't support multiqueue, the guest vq layout would shrink +to a single queue pair, consisting of 3 vqs in total (rx, tx and ctrl). +This results in ctrl_vq taking a different vhost_dev group index than +the default. We can map vq to the correct vhost_dev group by checking +if MQ is supported by guest and successfully negotiated. Since the +MQ feature is only present along with CTRL_VQ, we ensure the index +2 is only meant for the control vq while MQ is not supported by guest. + +Fixes: 22288fe ("virtio-net: vhost control virtqueue support") +Suggested-by: Jason Wang +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-3-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 68b0a6395f36a8f48f56f46d05f30be2067598b0) +Signed-off-by: Cindy Lu +--- + hw/net/virtio-net.c | 33 +++++++++++++++++++++++++++++++-- + 1 file changed, 31 insertions(+), 2 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index ec045c3f41..f118379bb4 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -14,6 +14,7 @@ + #include "qemu/osdep.h" + #include "qemu/atomic.h" + #include "qemu/iov.h" ++#include "qemu/log.h" + #include "qemu/main-loop.h" + #include "qemu/module.h" + #include "hw/virtio/virtio.h" +@@ -3163,8 +3164,22 @@ static NetClientInfo net_virtio_info = { + static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VirtIONet *n = VIRTIO_NET(vdev); +- NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ NetClientState *nc; + assert(n->vhost_started); ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { ++ /* Must guard against invalid features and bogus queue index ++ * from being set by malicious guest, or penetrated through ++ * buggy migration stream. ++ */ ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: bogus vq index ignored\n", __func__); ++ return false; ++ } ++ nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); ++ } else { ++ nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } + +@@ -3172,8 +3187,22 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + bool mask) + { + VirtIONet *n = VIRTIO_NET(vdev); +- NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ NetClientState *nc; + assert(n->vhost_started); ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { ++ /* Must guard against invalid features and bogus queue index ++ * from being set by malicious guest, or penetrated through ++ * buggy migration stream. ++ */ ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: bogus vq index ignored\n", __func__); ++ return; ++ } ++ nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); ++ } else { ++ nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ } + vhost_net_virtqueue_mask(get_vhost_net(nc->peer), + vdev, idx, mask); + } +-- +2.31.1 + diff --git a/kvm-virtio-net-don-t-handle-mq-request-in-userspace-hand.patch b/kvm-virtio-net-don-t-handle-mq-request-in-userspace-hand.patch new file mode 100644 index 0000000..42d8939 --- /dev/null +++ b/kvm-virtio-net-don-t-handle-mq-request-in-userspace-hand.patch @@ -0,0 +1,109 @@ +From 3cd90463553c2e0915940b17d9955b4b0cf5ed11 Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:18 -0700 +Subject: [PATCH 7/7] virtio-net: don't handle mq request in userspace handler + for vhost-vdpa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Cindy Lu +RH-MergeRequest: 203: vdpa :sync the Multiqueue fixes for vhost-vDPA +RH-Commit: [7/7] fc6f4e145f2d6abf96e75dd0d76ed04660a1f20a +RH-Bugzilla: 2095794 +RH-Acked-by: MST +RH-Acked-by: Eugenio Pérez +RH-Acked-by: Jason Wang + +virtio_queue_host_notifier_read() tends to read pending event +left behind on ioeventfd in the vhost_net_stop() path, and +attempts to handle outstanding kicks from userspace vq handler. +However, in the ctrl_vq handler, virtio_net_handle_mq() has a +recursive call into virtio_net_set_status(), which may lead to +segmentation fault as shown in below stack trace: + +0 0x000055f800df1780 in qdev_get_parent_bus (dev=0x0) at ../hw/core/qdev.c:376 +1 0x000055f800c68ad8 in virtio_bus_device_iommu_enabled (vdev=vdev@entry=0x0) at ../hw/virtio/virtio-bus.c:331 +2 0x000055f800d70d7f in vhost_memory_unmap (dev=) at ../hw/virtio/vhost.c:318 +3 0x000055f800d70d7f in vhost_memory_unmap (dev=, buffer=0x7fc19bec5240, len=2052, is_write=1, access_len=2052) at ../hw/virtio/vhost.c:336 +4 0x000055f800d71867 in vhost_virtqueue_stop (dev=dev@entry=0x55f8037ccc30, vdev=vdev@entry=0x55f8044ec590, vq=0x55f8037cceb0, idx=0) at ../hw/virtio/vhost.c:1241 +5 0x000055f800d7406c in vhost_dev_stop (hdev=hdev@entry=0x55f8037ccc30, vdev=vdev@entry=0x55f8044ec590) at ../hw/virtio/vhost.c:1839 +6 0x000055f800bf00a7 in vhost_net_stop_one (net=0x55f8037ccc30, dev=0x55f8044ec590) at ../hw/net/vhost_net.c:315 +7 0x000055f800bf0678 in vhost_net_stop (dev=dev@entry=0x55f8044ec590, ncs=0x55f80452bae0, data_queue_pairs=data_queue_pairs@entry=7, cvq=cvq@entry=1) + at ../hw/net/vhost_net.c:423 +8 0x000055f800d4e628 in virtio_net_set_status (status=, n=0x55f8044ec590) at ../hw/net/virtio-net.c:296 +9 0x000055f800d4e628 in virtio_net_set_status (vdev=vdev@entry=0x55f8044ec590, status=15 '\017') at ../hw/net/virtio-net.c:370 +10 0x000055f800d534d8 in virtio_net_handle_ctrl (iov_cnt=, iov=, cmd=0 '\000', n=0x55f8044ec590) at ../hw/net/virtio-net.c:1408 +11 0x000055f800d534d8 in virtio_net_handle_ctrl (vdev=0x55f8044ec590, vq=0x7fc1a7e888d0) at ../hw/net/virtio-net.c:1452 +12 0x000055f800d69f37 in virtio_queue_host_notifier_read (vq=0x7fc1a7e888d0) at ../hw/virtio/virtio.c:2331 +13 0x000055f800d69f37 in virtio_queue_host_notifier_read (n=n@entry=0x7fc1a7e8894c) at ../hw/virtio/virtio.c:3575 +14 0x000055f800c688e6 in virtio_bus_cleanup_host_notifier (bus=, n=n@entry=14) at ../hw/virtio/virtio-bus.c:312 +15 0x000055f800d73106 in vhost_dev_disable_notifiers (hdev=hdev@entry=0x55f8035b51b0, vdev=vdev@entry=0x55f8044ec590) + at ../../../include/hw/virtio/virtio-bus.h:35 +16 0x000055f800bf00b2 in vhost_net_stop_one (net=0x55f8035b51b0, dev=0x55f8044ec590) at ../hw/net/vhost_net.c:316 +17 0x000055f800bf0678 in vhost_net_stop (dev=dev@entry=0x55f8044ec590, ncs=0x55f80452bae0, data_queue_pairs=data_queue_pairs@entry=7, cvq=cvq@entry=1) + at ../hw/net/vhost_net.c:423 +18 0x000055f800d4e628 in virtio_net_set_status (status=, n=0x55f8044ec590) at ../hw/net/virtio-net.c:296 +19 0x000055f800d4e628 in virtio_net_set_status (vdev=0x55f8044ec590, status=15 '\017') at ../hw/net/virtio-net.c:370 +20 0x000055f800d6c4b2 in virtio_set_status (vdev=0x55f8044ec590, val=) at ../hw/virtio/virtio.c:1945 +21 0x000055f800d11d9d in vm_state_notify (running=running@entry=false, state=state@entry=RUN_STATE_SHUTDOWN) at ../softmmu/runstate.c:333 +22 0x000055f800d04e7a in do_vm_stop (state=state@entry=RUN_STATE_SHUTDOWN, send_stop=send_stop@entry=false) at ../softmmu/cpus.c:262 +23 0x000055f800d04e99 in vm_shutdown () at ../softmmu/cpus.c:280 +24 0x000055f800d126af in qemu_cleanup () at ../softmmu/runstate.c:812 +25 0x000055f800ad5b13 in main (argc=, argv=, envp=) at ../softmmu/main.c:51 + +For now, temporarily disable handling MQ request from the ctrl_vq +userspace hanlder to avoid the recursive virtio_net_set_status() +call. Some rework is needed to allow changing the number of +queues without going through a full virtio_net_set_status cycle, +particularly for vhost-vdpa backend. + +This patch will need to be reverted as soon as future patches of +having the change of #queues handled in userspace is merged. + +Fixes: 402378407db ("vhost-vdpa: multiqueue support") +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-8-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 2a7888cc3aa31faee839fa5dddad354ff8941f4c) +Signed-off-by: Cindy Lu +--- + hw/net/virtio-net.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index f118379bb4..7e172ef829 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1373,6 +1373,7 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + { + VirtIODevice *vdev = VIRTIO_DEVICE(n); + uint16_t queue_pairs; ++ NetClientState *nc = qemu_get_queue(n->nic); + + virtio_net_disable_rss(n); + if (cmd == VIRTIO_NET_CTRL_MQ_HASH_CONFIG) { +@@ -1404,6 +1405,18 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + return VIRTIO_NET_ERR; + } + ++ /* Avoid changing the number of queue_pairs for vdpa device in ++ * userspace handler. A future fix is needed to handle the mq ++ * change in userspace handler with vhost-vdpa. Let's disable ++ * the mq handling from userspace for now and only allow get ++ * done through the kernel. Ripples may be seen when falling ++ * back to userspace, but without doing it qemu process would ++ * crash on a recursive entry to virtio_net_set_status(). ++ */ ++ if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { ++ return VIRTIO_NET_ERR; ++ } ++ + n->curr_queue_pairs = queue_pairs; + /* stop the backend before changing the number of queue_pairs to avoid handling a + * disabled queue */ +-- +2.31.1 + diff --git a/kvm-virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch b/kvm-virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch new file mode 100644 index 0000000..12b119f --- /dev/null +++ b/kvm-virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch @@ -0,0 +1,52 @@ +From 60224ca528f32d3f8e7a5ec65c1851c9b698dfb6 Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:12 -0700 +Subject: [PATCH 1/7] virtio-net: setup vhost_dev and notifiers for cvq only + when feature is negotiated +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Cindy Lu +RH-MergeRequest: 203: vdpa :sync the Multiqueue fixes for vhost-vDPA +RH-Commit: [1/7] fe2e27958344b5d5089b383f36c5d9e08472a591 +RH-Bugzilla: 2095794 +RH-Acked-by: MST +RH-Acked-by: Eugenio Pérez +RH-Acked-by: Jason Wang + +When the control virtqueue feature is absent or not negotiated, +vhost_net_start() still tries to set up vhost_dev and install +vhost notifiers for the control virtqueue, which results in +erroneous ioctl calls with incorrect queue index sending down +to driver. Do that only when needed. + +Fixes: 22288fe ("virtio-net: vhost control virtqueue support") +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-2-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit aa8581945a13712ff3eed0ad3ba7a9664fc1604b) +Signed-off-by: Cindy Lu +--- + hw/net/virtio-net.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index e1f4748831..ec045c3f41 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -244,7 +244,8 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) + VirtIODevice *vdev = VIRTIO_DEVICE(n); + NetClientState *nc = qemu_get_queue(n->nic); + int queue_pairs = n->multiqueue ? n->max_queue_pairs : 1; +- int cvq = n->max_ncs - n->max_queue_pairs; ++ int cvq = virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) ? ++ n->max_ncs - n->max_queue_pairs : 0; + + if (!get_vhost_net(nc->peer)) { + return; +-- +2.31.1 + 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 3aa4f36a853b0d605d6a6dd61d933fa43084c580..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4190208 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�`g?nIrVio3c^K4|e-Jn(WOFsaNIT$_= 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

`M8>h>T9UpW70pJ}{!e1h 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

hI^)cd=(ja+ZLc@t_so-0Z{BH9 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%0Dx>I}JdaouZ^+8ouz)5DddnTkZnR*QwPRO>E zNhcqTWoHjP>6VREgD*7>y%nEo=nssXyyAm!cqDMT#pJ3_w{cJnImj96eXp*0+irAI(x7m`>Lkr6D=q2`D30VP<23+9Xq#Ya8w<2 z^EXii@buVuCSc~s9DZ(cUO-USgJMb zx3Rx4|2i2QSLhU!H=m?&ADFwy@bQO?K|4@782Rc>gk8j7}Ud4FG6R~8;$?f zQMCdQWhaeG`A7sZiYH;-mqfQ=QlN(;3rgT)ujk5Gi1fiRatTzGeBA9ocIT<>Kt8j!r%r5qBG>@r7+2? zsuN=bn;cz*{#6c_%FYTiq(;M!*>*g!^C0&>c;0~#@0pjF{KfX)ferB=PK{)>CAzp{ zhybR8MU)pJI5;qj_^Tgeb}z@*u!p1uz;}F%;vDSu0Um||HFCyEQFGJ9OD&4+ZtJmJ z>}Xx*Gu4hpeU?!}ZxoAA4l8Db=g_W0G0RA`_Up99-E~M=xbh#&k#QgE+;el4LLb|4 zYJ-))F-enWr|GO`swE&E8GCrJG{dJIcPd7?2H?|u6#(Qk|7#a!0Wb`h3 zMn9}Ropd(oMTse?5yS%G0jS+T$3y)4wfsa{5WM5dA6V?%tCLpoTKr=sKy!UIqoYe= zo0|ZeOwGh2i^i01TQ7)Xk@?&pHD>h(jMs9 zwCGcHY~$4{3^Iz|S$TYBXG(Yzu3}m-gmXi22*AK07$+Xd&V7G*oh;)PsGJ22s=1iZ z^)Oo`^#YMY>5aINq%f{`sNAfSC|QjKUU0xJL#inE|De}Ja%HNAA1kd3cDY7}Tbxy; zxnet$KJ`xu)6FpIakxlQ6mHY+Gf% zyReoK(6(!qS=HB>5&(7n=Y3Xa6BvPgeVORB;wD7q9L{?${mGyr+=Pl$efDG%NkfUp z(s0tIwv{qHoe93X_&_N&7*k#-*T-uV)G1MoMp|}Srt>}5soF>jyg>E_y1pJ>vPDvCKpyxpS({TuVNaG zF)N*p?ZBl5hP>kdUKZ11cC_%WyX@llYBT=VFXHs89)Kx7>(qx&`&G@?_7C8yREK#$ zTqjUIuTW-?pcGVVct^FmGPXwT<@H_J=*=)3kRX7z2znL;Od z1qI1c#jw4{7Yj-58DYICM8O1&Qv|hG{g?S#YX!U`Ay7s+`b()Vk6K&x26i1`*JTZA zBJ48aVVZ@!3@QpRA=osgJvE0qCwI{m5W_>b0%ufAKLE#9+iUX0aZp3X80%A3OPXJv z-5X8@T61o+uCX?2sJyx)HL^v}2yZL>Rc^9xPj8#uG-5hK(A3^oS{8G0uSHN@U(OTz z2tzG+gXQ?r`UBiScAo!b7NwDk{$d3;j+^f9+w9S*6End3e%(=Zn!Pp*wx`yj%b+I&Gg_kV9=X&JmY?>(=uipU zDPGA0oO1Km#$)N7`%Dj>CdFVq^aW9M0ArE%$8R#u!?T1dWXJG9 z9KVg|r1r<&ehd_hmm%}J;4QJg|C6Mt##*(VWfnrfqUejZqlEKk-%aEB^zHd^;I6=Ch9nSGd*l%&#)EcXL|Yah|U ztaGgCB+U=`{nr;zFpKjwH^}13CRAx#8Kn;YmP@FsSkX&IS-GI%9Bw_{k-5wBVIT1J zD7d@G2T0aMX@Dt~On%wXzuHJMK1Qk^N*TYga3^)Py!;D+DGP$A>w3{2aLwAZ$r9z6 zZs@dGLUJdLJ%7Jko|jNhHUe1QTOc{q)2q5_N5U!>!%!kQ9vDlT zKFTXJnD1`=r9*zv5EJz$vze`(Mirhe&E0*}k$6_SR3d5qn5+>Fe?d6&ZTFgRb%P`;+*4;G~?5^>@O61*-`tEk!2^NsiJD0d?ke?uuT+GjtP-wJt|C9=RRpT3XU;&v z%qwicZvh96tzpHSBI=LZvoFVGb;y@p(lS;5p22UvaB1Tad;&{T{Mbvp$y@rHSIlZ( z3A)9eUvXm0+n^*8`*hyxizw@Rv}|UaxGi1ft(Rv1$Dp(7ummyi{I9a|?^!NVdmLvu z=bqr_0iMR1CnI1WW6TUDtIwixh325%lo{^CNPdoiK#*^_)I_F*&*S0}aDg18h=+l* z>Biz5Pn8)Ym7{W8+~18JEb>;C;w@Z^O>WXNG>kCFUcxdK+|$xYn@P>e9{lU?-WzjE zNd;<(^VQ%h&V))gfGH$VVqDk_s*McvS-`Zj!*!&0$Lo}!s3mB+myD)~rz$&58r}y02KEdQr%_ zWlc6oNd|3wN7}Cx<+(RAUcqS3eq`V_g!3SZ&07fDtt4X296r~dn?oDYpdGfW`J0j)h}?Ir|0@w8 zjD0#{7A*rq3%-PP067;ze*ZB_xkp2SDt8BxV4o5~u?50Ul7Vq{4MI8y7o~Pa^evnSahpZ_H`kZEcyVyQM{DRuh;Ndv^Mrk_9QWJ93+)yvokZT@t`@6nG ziKo53e*H_|8j)9Uq(B}W+LSk3O+ z(qcT*25EXk8~YqV3v(D`xX@EbIn(+^XN#|D|01(ydnx~&JDe4qS_O^!r$@goIuj1t zzyx2`pAcs2QnQZ!=O&|&dE9W@{ZGH|KnKVm#JsOpF3l%TM~K%YRBS$36y@>p!rENg zOd}&Q&*$WJ$fzDI=9M=A^MpCFXye3wtxxvf}}?AHBq;C-*ktg z|9(R6LGbNS%sk1J25NWC8rXK^LG1ruq29o}LJ%Q_TThi5sr&G7Q-9(F;}Af{T9~8h z%Ug=)>aGDL+`^|aT1m!eKE!vaDSIKJoMw`qOvuMRQu$^Sde_`rLc*OM{Ji#mE4K2l z44uw_yY;=(?D}4MhTt)EFP@r7XmH4!Cf>@B4MnD9K;T0#Lxzs=uvbul4(!8CB@>6j z7IRl=n*W7setA1RUscL@R0x_bp-#G~UWD&DmC}?`vo90DrQdlz^;oTbj@WX`xtSCW zp5$nI2|LvRr+FemC@G!rHN49Lxfdg3O4d>ZzEK90z5q&6F`A@2=7p^0yXRceX97G zK$dj;XstBXHI1Fay1S%Se zmx#O6bZ!A)BzbmlF1p14SSwz{K|Qi|bq=Z-^HTrp`^uC3u2Q~AiXJb!&ZK~Da9%=- zN%V!z>qCI?)raM0BaWHPus>J5ca2NK;Y-BE->uO}^oV8;zL+L#K>H(!;&m%uzj0j% z=Yzx9v~GG@&_?NGuu&A4q}>y%Cm$F>g2iQ~O?m^yZ@kP5Y@2U_ZMD3%P>k?mD8hX8 zX37xmc5Q9CpK&WK2m!G=|5tA9|KtUG@RNx#Dnd0ytSSPR9%T-Wsqy5V-!}>mm#pFW zQ$D30-$$y36}}DlkV5f8ls2(~+OFC$9E6tpW{fq4w9CwK#<@$%vHu4_C(0AQw+JDd zOF?B00e=Zc;1~9>4_IO+4YRNcKZdRLutcc00BBO?#aCqfllkDhX7ysK_h5BohWHUF z6#O24cE$S#{^;-hrA3}?-EMsx6Sy)i4b_@@v(FngiGvgX3*r`aSBTby(n4I)Zf@g2 z@LV9s%csXNJ~4nlPdnrg$C4;rO>RivZt&6?ROa}fi|(Fdaan3iGecc zd8~osHjoj)gxn-(pNmoRz~+CIs{8$gJ-hV)0XArM=ImN&SY^ctvNlHBtph!$s4}Vi z;+B7o^>Rf;nno+y!H6k(yz?I%3|g^tvNX~!hDfKpspfp7JL%L1T{8;Lv5z$~Lwuj7 ziO#~XXARv%7d%Qv=a`MGQ|H8RDDlv|7atSirf(^CTWBKt^P31dMh*^KytV70Dy9%I z-_qz0K?B8N1IXA84nxaKeroiK?GLnXh^5CHO+rN7BBQL+GB_{uX5jyMDu3a!P>xZa z&xFxmfAHZ~W$Pxfig2{?L~{qea!()CnpZAJ%uIT@r8HwfzEP)vZwGx(S9LQ}Cbk|> z1-pi)2-c!u&f0870fp(H8**up$*N~rdLQ3F;hhW;Cya!FOjnWh9Qm%Jf5}j zw3>$DWz#BDOZd=o0tBQCFL!JmAS`Dufk_<7pmPx|TR3i=p9ZnHLKMfz9K+?wi$moj zi!gEBVvDezDA;@&i}$ge+r>@{`joo6Mb7yL6>h6pR$v0oc}9Ond~oMuMv{a_hvosK zh@Wpnq67k0fSh&Pa(ue8H3roj)_fSo@4XG@p(N@{UACeG+sg@*ce_~^WF+yT100j| zE1(-ga2TT(&oEBYo~Uc7R$Kuxu9}&L1cJqUGoDGeXY9|tW>c(_2SFhS81HfG@taC( zWh1$zdKd8h@(n{e8jMmLc5!$@VreZECR{neX=iO_rAq1GTeEzZZTU&5mx4O;>uF5aC zDOS)`od||2Jud*lWn8Zm z3@~@IOVGHDKR(IR!;Ub1D>**E2D}L$ zTDsxhrx^K}p8SdMYVlfjVL-6Y5QIR#kkrplRYlMr%+)z#{~nrdLdfxdn1AplU`2je zAZp%o4vJq7TuxG#d+wzIx54`TonLjd{d{DtLNmr6FA`qOXECF(Y!=ZNAC7IkJojh=fg~D0m<*b(<#D6_u8%|Nv_;Pg^sOH=DOsY0+>3vU zek={+Ucx%@Wtm1pBJZfAWv=ZJi99MK>+JZlL?f4_E1uPjQVLD?`A0_6JJS!-hPmfm zBrPYzon!>uNt_$!G);V)5&VnP;i5O!&mazE4{GGa!m48YMIEt1+qN{KIWs;uNGzfS z5+TYN#mDa)5La-Dk6%{+U*%o)z(TxLK4HbCk^j`l_53{@mKRLk3x~Ps)`QtE-!{^x z8)g)4#YF$0AaM`S2-b%vt(OO-4;h4ZtkI(q(fZMbZ-yo*>&GshB*5d6?R-SxaMr;G4%sE~j5qO~hZGaQTKFj*x0L&v_|{K2BQLU$Jq0EDm548DJEMLt z3aeV|{uB4RkHX&#ay@~7RS`B)9!+g-MH= zBmqH;NVJ#b)T2Ri&{$pIU#7#By4d1-2h{IzSKA~gDXjD_c-RuBt705}g zfFBx0+W|)4#mbJcseZ+<$oQGzPChIEwhcK+WWwm^b%?Wv#w^HgB!D+|2UfCzTul?$ z`>uRVSeSi(QzNp0U?T1ZOK!{YLMoR2L3E89VScDadlf7O=3LpeJq94SxvhYWQn;dx z5Pz&IbtM{P(4L8>tDg{=1 z+=T2#)QAyD%FiGP1;kOR$6I&gHNf|`IcnM`NU@|$w{(P4cUm^8!rXy3FI; zmNv@!b~7$+=iHYt=xzlQoR_5_8}(ef(>+flR`%1$GlVSJE&5UeVrV>14=5(Y;$LqW z>j$TqTn*7kGDpb5V^_uRY)wbV!^`^YW3r3LsGk5%G{s@oLei0T9C;6~iccI%nJb zo5t3KtA|eyfsox{RoXr+=^;ng(>db0CsZlZX3bpXq}PP5ZuRIq9jNUp;K8K-ulqOT zP?nXQ+`X`}U?~F;j8fb!zZ;`;IG%HU4HxF5h2Loy@OIS1C2V2QQWUk&7f8iW;ZvWl zgo%Os^JQA_0`=qy0LY1mz8;VWiyx4r@buYc0wJ{eck5->DNlwo^A^^^(ZD2)MDpTs zYRe=M>3xV)3LD%jOi1b0#A#wNl>y)(;Fd6jpN0`%Iz4e;KP2BVumfO>hqlsZInz(` zAMjX^dR_lp?p}ib{)B`zNJz;-4 zz++6Z>%hRWyYDPNk~bIgdz*ITGJ6jQ@_ba+?KG!Xm^$PKy_O~p3%*5KP$6iQv}M6W zQ~H{62uu6EO&;;6x;co?saLJw+EQhE)V6FX#jISf+y)Q&U@-kk2b)31!!YwZE&4E8 z>+wLY@4x(>0Kjm~TxYSs$6uVDT=9E~=YCPqewD-F5WnE~D4?NviFp{+{6o7aA9U5n zZ&pvEIzm5nrMdJ0L2%bJy5){;GD}Xy-0!jvDxtkVJiqndr;XEC&mfEzGaVeFCrXqr zw5AAXi6z=C+5~VwS-*s0|jYJ0qQNnLpub+ZQ8(1j0 z3n8tG?w|8z?A#vE+$ShMO_<2qoS~T9gCd|`@=5Dti|dRVAD-y%QSZi?GtEG^Luv2S zLX<~n=OPh;Ar8^MWG2xW^f#jfZHER)I>}|E%%XPdD)-_HF=Dh#--~4t*4!Z^@~mCr z$MuC`iZV7VZByE30`~8249S?QfYt&SsG%%w4x^V5>w@dv$6;9s$xdv&m)#zmunyho z9!rqnf)?N>-mCOQef)nvrP-ywJ2Tj}5UW4k{z6_kF$RT)eoO!l&yuNE584j(oD5xw zUyurL5KEC?RKHq`;$ypjxALZ~meL~!=iP0k$~fB_pNgVs`VEH7EE~A7oXSh?axHJX z?zK_iOWiPe<*$lpQoL!iN5JdJL^k3GZxURKHyboT8fOtW;@TdR+cdG6-sHz<+vPl? zV1AnNLe({Z5&y(+jrZ}_a?mO1;0jn`!tqzr7( z_9IqEJ!P#@XrZVJ7Nhdk*}{Vl`-tYf?9>Z?c)yF1V(TMEigj7M&>hF|>(v1`)EAdL zd~8O-S_l`<5%8?z?5gM}Ezh;tlehhTEnc!SLgd;&%O-Rm&_h5&-H+6aO)ekhl z$(ok+yz#!NuZ1wp0WHGK7o^Vn%MKC{d1wVMD064G>3&1r(^gW?hiN#WZs@_YSZy^< zp{VjWuJi5Qs?J(zlGjc2+ldtqs!Mn8(53ftDS$SbpgFn*;C!Y0&hRs{5946E@4qNb zrrw{7G<8UKT4Mwz+iIS8=vA2S#IQ^=XQ5AAsW~N7Q*U(cv@dw6yf_`RFfXUxWSt4@ z40-ql^Y@M(;dxAqP>!MeXHN|P@vo$fX^1U^9IXL6!;Yd0ne}$$053+<3)Rushhq$# zGZI~ryaj8cTPK&6X!y)Vs%?VXu<~j9zVP0=lAY4Ez{DEVXVtRlH1-RC?2!ew6(Qp= zN)~@JI<LVh?ks;QNBk170YssykbfW^2i6|HuPsVO(K%=^Y8;X36jE!Qcs zdf%F|k6nH$YioTmoMn-)2p(^pwXi=`ed1;#r6Vj`c!Uzc*eQg&eLpDA;@6B_K%or@ zCC^Z0G9JNVTwUN!tFYhH=Q(`-vng%4QkY`fB^z$Icd_t4t)P&bxR!>hw^BO4tWyB( zB(qK0zs0A({^${3Iz{~u6?_we z)5v4IRp$Dw_&0tmbzP6)A*;)a8bxuQ*RCS6XOppAYLo3A=SI+#ivd; zxNvrG56)q9qOqoiiny}$ru}YFq-w*zSI65y=i1(WHCNiwK`$D={KY>F8RVZlGhmCoVn9K79?|epbE#RQAD#Aw3D`-P zPl6SBj($y{uo7YTB^x{8W(K-VaS8+Q4hZ_}O@Lw8HG00odP02G(ztN&-x2mZqJuWA zSDx+)&?_KIdm*)QZ+!kT4zMmGU(+>jj>S#lCfz#k?;VziH8}d*tgHjtmgQ>vt2lwT zCSB1r0_heOMc|}&wa)zOgtof|=y-c|RNcs(Ftl|&dHckKk>(jZ^GG}qmI{_VjDP%u z5*O{HeDuS~Umvq`SB7zJSweA6Bq!r!tK9vjj|^goywdBxt5)?WWS~d|eoW7+#vO|wjCUh;ZGIDC@^T49EZkD0WBim!gAqJN2 z0cYxKj0k$mLnFBoO~4$~9wK_iMV_K&J^JX((V+(w2Mq{Xuf1->I7Pj}wA!-mdQj}j zW}Etc_;C8?VxiD(aFnTA4jjRW-bt}P9K*_x&n}cEofz4%mA`=&2nXM{ua>V9J6x@% z0-e}>QFo)tnMTMH4KEcD&SQfj@zj+oHQ22&Vadi&2RyAnQzL=4E_>1#K{uyA*hl=p zq-!XO#p+me0C_4*FGenW`QGw3(`{`06(WHfJkE*CkmahVF$0jQ+!X~hzgIBW8np#h zyzHF$L1$L_lTt zC@YXzxzZHnT@NFi{sQ0g^+-uLJM5&CXxYfkIYCnl=l0^2|UvF}* zx-Nb|MAAZ{=>ybpRXqj&RfrA>vQ*;@pl~}(@B?Hp+gg(eV>s?ri7tf^+9-0*xs*$g zKL~`S@_y`n_kg8Z8D2U9WHJ&~WSzv30-Ul zm4})Bo*B+r=#AWU2s&sMqU-1y%CAY=sbcj4&dk;8=(gXV=p~Uvm4u)bK2$bEqFl9p z4cS43s&;45sz?0ZZT4_eAgMvoUYb4dcff?(aG6g*=G;gd76roLri|e`{m{Xn?fCbk z4|(1g$j#Vv{BHbN07YPaqyakDhACrd$KL`F-%t zo3t|i^U-y6b%zG#$6K4^g2!4(QZ^jh@^XhD&1Rqf2P`$HEQKn!%hlKbieo~kQ<(wo zhWD>nrZQ6~PVmPAN7I?Jc?I!$^#5OHH831y(V4*@&h_TH;-hykggr#jAi@;b>N|~a z|7fN~#Jot*BC6t`B|}Fb%~bosM*VuLvNM|!Btvng`Eypi1O{|jhU|V$8={Kk#xfDN=C5i+fB^cly{L`RWZ8JRabH}8emXXEu$5|>J7rcS zGRGroZmtxxwa*K-!8G8J*(wdOy~cjsmQo9)^2+F0=Ai&E+ZTnA`t&qpm>T|Y|_HagPY3H z?oBy%;{VZ4N)1ttaZw5viO}#+FWe|+rQo%KmC}VNF=L~|+UfX(Q)B6I&FLOp(UYw3 zB|TnWj5-N0?V*IW?+``|G*F8fXPVk(vxD0#1U7R`$yw`WJO3 ziT@ya^D8b-9IkTbDZj`LrfQMJBW*9=6R4yoi>gu!bPI@<%dm4DVcOc~IZH@f9jjVp z?Hoc0V+iSElkK|NdDVhyx&VVq8wIRJQ+n>W3wL++7AOGiW;d;Kwt2zB4FC?QO~iBZ zgA6&1xva^_gR;iSZw>;8%=UlqC)Fl43A)FYM%o(YpRat38H$`=*9>k*+Hccje2B&t z#JH^mRhfi1J($9_i6}4jDsORJv0AXlRoFP#I-DIiC1#lBR+ja;_kSoj#)iEZql^2y zP=@*d5D}IE4`20E)(NAZmKcnZ|G!MY<0lcLl+eND06jy=@!5Fpv01E2a}HkQ?8&R3 z%pMet%Oyun%zQukpkrpZ5^+_N5*gpDLo^FdaV^msKx(ye%qbXps=9}r4w5r{5YdK$ zIx{+D=p#7CoxiZ7UmV>b(LcsZ2MusDnT_i>qH0@UYXcY-sM2wDoU5gE%%eso0W+J+RgoX%_P14n=GaK|WmRNGaxYcQdZ?}SBjtR) z@+prPm#{67`^ZqpE!ab?PjNwEOLi)tmaoN*D(F*pFCoSW9Z+-7L#1ZR-H?3|gO@@A z#r6L5af+OW^HT(WH8)wiC}X1RMH@Z_?{n(e^E>`PraWIel{1UPHN4LV(mXNmZP^)U zg5hHL3Hw3)ga0}@A`L=g7aLIV%AZdT{&zeZFclR{c4$1YHDq^$b@J|9|L#6WB9%lObbL`tN`xDV)(TLW~AE< z(P(~@EMh9lUW00Zzv^8sZ%!mx!3s(!eOaKBclLXOSh9^qJ0~W+`!4_IC2x`~68c|V z6etQu53bF-)6da85wM=m@WH7l^CGO|JQ9W@!M~SkJRD_>S4N$tB2l9=9j=^VqAf!j zr~d1O)(J#YKQQK0@_@~ChOaE>bEJC?WB{B^ES}>`K}_24f83z3)RpW@+7xpSS959< zCKxl@1XA8LGpvF(FVCZ@?rv@jGE{~tMQ5X5(2?PeFkB;+Opqw<%J$BsWyi3mZN!BG zWMSggnNO139me$tn3EgR(%h&obMwutnWvuj$W3|(?N#!93sBn;00GB$%L>#ISjuHUfkVt9fy#P=kVzv6h>=RPosnJNT2YwLA?kekJ$SvC3izqPv1 z=Jv)gmg**SaM*7v!3v^ML;3$ z#+tl#Wca)Cc>psh(Vhg1vn3t8m9sbJ{7)wy6kX18<_WyFh-Jspj z-p$2Pvx)}GhsLA{+eeS^N?MO-v0~sNl5xdEogp)F0Fb@)6)1=NHO$s+#D{ zo96|+w`3X#Hz+lkw1G63Ks9;T2!tx^06yh)QHZP6IZlK8s@6u*tp9%awEI3mKFm#pss>VNddZ)pjI5lfqMH1a5at&oB+XLV%gGMLbgG@+kkJ=xrv~;=D1i9u?3A8PP?x~XNRSpDW_XY!QFF8V zoWQg>@}pBGFRPM|9t-X))J4zh^rZzk=S~o)V(QmE<>Apw$p;KkwGkA^p4RH8d@h!A z0+SPe1v>rK;EJ_quxtv)gDe&BBDOhEh8=^pp4dsR-GvCqP(#+Hx#OtWgl0 zh+LMQ=3ydf0c*}ToAGNKTF7)UI$<~)EN65+wyC5#%AU2X^}2G>a$!b{gBX73!2!j^ zv+@QLcV;pymjcOMX^I7hFYR2}Cu>f3RWzz~K3hl{A2NVwIeE6QhF$hAN&#==`8AjD zv`ol;RFIr8K96sb2h-CM2Ee)K+CJQ?M=|yr+8o~Vn z0g)QWkfcXjnTH>iFM*#plT|Fi`YxAE7qo{HfQlhdL48GNB_{;de{ji30LrT$s`ixO z^5Y#svn#1onHc^wTvjj?yK03Fj}s+U+kfx-0p%b2v)wS8FdB?Tbn~INXF7zr;30Xs zUcIWdny7xuPX)>Ow#^!)=co)J`R(Qa#zd9t)QD1^ORf~ZmUvO}XvcS&G;2^G8nGCG zbn{Twpw*PB6Q?vfK5@ww+z57yUm@`p`JaC&4Ie4{KS{a(uEPw9A7a%}kQxcw-~1l%rd-DX?~->RqfkuywbiRTb<0L&B~Prw5b29-6!^s1PW49JBNKH}h3i%u^?NE@LG3qZbPh1IvS(4tK(FU`%&g4pz$)|&^*$h8)~ zVByB%Wbd4p{7*E~Xz)diwq@yu6bWP5s(2>TZ)FsN$GRv4@abS~Wmr)k+a}ojT%QOl zqbTm4r4K&6k0`SXE>mo^7j*ksYgZ$I67${auRVd^z@c0mVLMbKSL06l)Se5G;4{s| zYcLjV8o61WuRm?i+-K;OSk}XgjhO%H=$_RO2t-&bWNLZ&#@~OJl3>`&ywR5 zi8)R)>Won0&|I+GV^K@3j9OvVLd6n}=wsYT?q583=2oTL%c9jG#MW}KN1xKuKC<)8 zh8Y+2N*>rEeb^4lN{^jKuCJ=h*}p-yn3!8N#)Yi4&*10-7V-MuX$n0nI$48^(errF zqDL7XX4afOAzFD=FHRcp#F?~m`-?Xrj>u+sax1u&IsE3kWXMmwo4rbTuv46a$Gm?Z za}hvNru{?JetUFzANrRG!ZS?c5}it}L2%nVsFh{aN20<k;5uK!tU9vyX8c@5M?w2qgF zYUW^({McaiMF}w=0iE;)oDg(|%U%`$j1z`FB|7nLQ(vKB)e&NA3?YcEYFjW)L6wJt zB5-5*o7+;&-YRh~q8=W%Zs@EC-OzD+&br0xMSYryAglh003%2_H-&6|S!`iB4~;aX zgc3%n9pAozV|mZXHjqO}iM49jaE_weGWBdfA~HgutzY+AH8~GohGm?#HeL_&CVcrN z&=>|U9?~0V+HKeM@`z)vmP`W9J!7|;C5plTWvCiz+te&b${nA{=&Yy*Jh*oQ@;P_s z(?sk@WDrRh?L$KC1{3zsn_Y?BppSeui3fF;b~_k0Bz$K^PIN-r*g>ql08#c)I~W-# zVP-i8c)}zpQ>PKRtu|wq3IJjuND?=ws-tR<;0&C$@RC#GvV)-#m*97p3pRHkUFF#C zIy5U7yH9Jb-~#2mvUK!0n(%~3w|lFxoJct_AX7$x?~!<>ZGMQwXGCIKvPc$^J>s7L z1z8*0P_DXY1baqs!^NjOQnZt$A=U9>@w)j2-D>cxy&Nbm@&0*o)}Cv=$7)~epD{Ff z=dk>wY|Z-?!tsn!>_SQPk6?J}ZcCWOq4G9z-1w~4`7E}~TK0ns&RC!3*%dktjI0zK z+YDpCCmW*vbK!${KdM<3lUh@Tp$M=~)0O7K+3{z+>bP(Pt@nft18Oh3nWc-)XyvSU zN2gMkNjzAX9xF7naQ4HTPY!6Lk_fFMv-YpTxOY9NvwS0eDw^uU0}Z@dn!Ko1RhhD( zA6_7)y&)}#Hs3U#hRjuOH^4xgpNArIVx9eHAq>%qp@%=2l0lK8Fak9o!g>i+P!~*y z_vZRsib5ov;g{;EB`*iBPGI1nWJV0d8A^CUmZvnW*y8e7_9golo?~clM~Iccs4rIV z9asa#)l5i^uli!t564lj6s~PNY-uTuVkPWru_XGU{R>`w(82uXfZOO*Gynk^(4cJvN*-f5WJTw6alhVRZ8TnA-(x*d z%nt#ArsD@r2ME?6bpH)l7#-KWVAaKJ!lq0rc z3~ee{U+w2n_)M7t2h1$rLp0Ujds;y1>|X5lFM&Q@Eu=zXHr4!d*^+?-=H#(u`wbU5 z$RL=HqyXE?3q0rrL;Q$&doWe^RHA@cbN(RUlj&M5}6QNr=NdzV?nQ0e$1oBj{`>b z=@FPht|FE`L&LOh&;~34M?P(oWDNlXrr59OVvLPFYuqB+n9?q#K2SEUkP6w}D;xw0 zNliO_+W!yX1}w^I_RX%5VY(<7?Pf1gLg)ckdx^0`iLw%3CQCOK+mY!?b$%uJ7X^lB zUN7}-4;8-W7*?K>2oEsXj6??+B>4=`U}W(l5nY*0Au$2?-lL6l2TIh`T$Eu?4d5m{ z2L<|;$+Ye$oYg@fhqUh?m^L^Hem1Yz-S*Pgdw-%fjSK;fS@Bq4n1I|leXo^-3(1`* z>;>JE4078b_CFvOw7;E#ne*I7HqhHWLCnvM-&{4XGvA-hW z%kg3AQ(J1c@&VI4D@8i>v_aC?B0+KgxoMEXwuH9J=OUob^=4|F9i7eep(D=>Wv6)1 zN4fuk;U?=IT>_-5gfu=SD$ddXOWZ=;5X|#xHyL7C|10(Dz9%T%GyXGc)&H$yzbA}5 zcpt%Xn%SZ)dKk3%KYxL%Ewijlw832}0MRN6aO!+j8%QVw_Gb|K^9Yp8nAfofAmUVo-Dzfyx=_ruR4^=2P-p#IH!zm`J2Y1?CI4W0 zWMOHZF18iz7ky#gJUtSEsp+p?F0}M~e~53m9NCwgSSQSK13zeBYAm!OxYD1VxYyEQ zX>?IQ_OrCah;am~`aP5OfKGZI5&h}<(H3I#EhGR*R+M&|bxw95#^fyn4tzOmZf~}& zD_Ok~eeSi8jgwR6u(LCe8fs!@C#8sJ0YjgGfqnGCWacHGE>}{$-{32w*)}}uZ(Y4K zY~{TtZI`s?P7%sk4<9GY)>TjGMcGYd=mQ>m*VMZ0l$-at4;6#odZ^!WQwZfTv1`I9 z5s{$GeR4xa9&EIYfI2co{x3#-WpKP=C$2TZQ#_IApu|WZmG{bbZlwoRb$}FNtO~@j zm@p9#8CKJOOI6d4b*;XMA`8E2K)J|(El^-fS=St$>Mcz`YiEW;1q3-z32)=Hgy<3% zj4HwiFX4Sv5{8QhFn+FCzt()yOJ7a_aD+#EgY1PIlSjn)Uq>^)P-yBEo-s3s<_A~q zYZJtbj8gRzjgblFi!ZyMTBXeSIH!Li!ksPrBa%lc5Wl-R=2|gM2UPvnq`!AGjkpTS z>>Jl@oZR+5KG7}=kAi8B+1$@xv!xGv{k|iU&60|2pDhKRwZ%ALU7}niurR^)D-NMG zeuIp}bFyywjaG?7^Nbrw%r1j1N7W2CwL#)t)$AD>tM+~S^S3kVUXka(^Q}+pT0w9Ta)K<`72c>4T{uLX z>VUJHSi*uDLy4g@QM5aV!;%KR)?%a1F*?I;@cib47*#Jy#}k^VqmqyS+ST)IVQLQo zxJhQnYsS8Iem#brTG&Btr-2_&Z2!C{6q_3CO=N0~iiA&`Ubnwu#NT2vucjEI?VJ^~igb$v@J;6XRKYu=rM!W5-v8#59K+DwIQ8Mkbqz?lm$9v&AO5IWtDxv+k ze_M}|19hW7yXszFV!VN?#E}|&&Q)pJ6>}Z(6Z`WF# z24U6Ah(SK~Lzg~e-&Y0sd4q*~FPi`>RU*bh`>ae82X>`39VVli6QUc)_hESN-f4o| z24})AR1_J8QPW1;JVXL_N+2kxS{)y^Y&Nf5-{A&G$!GRnJ@d~UO#R5xS7SrRUpcywyM-C0J$7!_V<))KYG=9qMp@fEs-K6Ezylo(F*Y@d9yR_mkK zgCCgVlcIIK^@=7BChXmdKL*C|soFc)5uAw3 z0;WmMM8$%LIJwZAS5RVshVLJkJmXLgbjKJ75E)#%#<<-Xu3C!bsyjMt>OA~$9$G#GwgexwcdBv9pqh?_I#;%C~E~sfn{ymNixCo zN8T)~03GPE&ZqoBz4^y8069R$zxLTZOjv4kmYSUdzw7R}2nnbGrb9pi5*loBek?*H z3gwgmkPy)ZRwKb^D&f`^-sB~q;}3(Lo8#cN*Jo`m15#Ncsafxu=3edyC~>xk52>ypVsQ3nRg2-LafyRuhSi_<}hsboqYCz`%q#|O07na_#Oi<%|GEbjS zz^dJ9E?6EC@`nuUJ zdW0XV0p3i?VE5GtvRT&o@Z0}euvkbH6_^vC(-%XMg-9mtZFtjz37*W+(nuP-XV)ve z-#jWH<&E!t!ttDG5H&7JJ{4;sR8fIpUa%8?-x#H4eL{zbRM9iDhefj?QXk5=gmi(?WJ0 zI^cH!m>LvIRO{4dyI+PO^ z49xSZZeOF|Q+4GjKBmde-(w-ypas59Bi&Y8OhHz}j>8fibB`b{cJUd52)~EuvZQEm zs$8!}mz1+X7JM%StM*Xjolp}CQhm%t3?+Yxit$7S#>Y}@;VUVtw6~xz1Xx{YI>P`cgfA9ghd2N5#E`oKPUs=SccU@ zAKUWyn=iJ)!tyyZavVBkZO=mW_Vq!^`21}ot$rCFGgK|>b$iN)KS3y9qDUZ`v*BM( zhO&IMSp@_CaaD%4WEc2d{+aXB#&vST^qMPB!U0$+gwX%(d+Y_$U+CYijViY@!K&Xs zlxW$Gw)aFg9r#8Cq(?R^GJsz`G+Ou*VyGU80a1Za*IXlZcVdZ+K<-+KW0Jf-d3K|mC z>eqVwIF`}uRM%`#5=JE!Il!6rg{%R>T;ct%lprOBJBR366x-{GmR)K*y}~Ipe{K{M z)^JaEl<((jVHFZH&0-lR5Y;o?l9D*GBXq19z)Ko4oKCoTw~SKF)Tg3>s&!+hNnY)g zmP}zRAbJ=b8y%n#N^`WBB0%m^>+;0vgVY3RSkW9*d~DuTIgAo%QESG-5n_YKq->~W zT_~7TCi2@&Up|Yb2idpHI9C&Ai{NJz7MPw2nY?a>u{obeMG7CSDs{Flk}3b8Tom%8 zLHhf(?RnEvXp*vl?(#;<0(xbQ@ePm1MD{^-*;%up-6!Qg^Q686G|EEWEUweor^^A- zL2$O?l7(yaU@#asIi+WxjF45{C&NR(tXD{_Hd>amRxwQCio1|Nd0Xl)pcglQ7ATC5 zF@U^hmM*Xz2uv0Y;0e(Vh|#(dwQ9za?fZ&<1?o*gK-H;l->b0j80u$R~|CLwgG?xbSS((F z$F((e5PE-K-mvZGAo$&&CZkHbd)C5X)LYM6bJZ7bnD!zR2{HN!(K$oWs^nt!vU~L+ zeTb{uY^fBrV0(ha6$D9|))>&zcm*ND1^}o+exmw6HZ!y^w@7o_pOJv0!q3 zM_$^nsiPpldz7XE$_OAuWPzDNGW5aiZ?mygPS%Ey9UUaezh0KjUM3x~xnkf_cd+mt zcZ_#TzZdV$%vzz^O*CP`FzVi`#%$)n>1vg$SKO=Gzcb}It*@Nz|kb` zPng-(rhhMC5MOsmA##<;(!n3a?jTBtygWkkBDbL)u>L~U+4Oe!#HPz znFanF4yJ&RXTDnpH88d1ywfm|*rc7hmV#h8C+VE1!onfur8UZRC=< zYNyeIfhu_Dl4r5cI1!Y>X!XqU=96??@Gk8S?WzxBGG9P(jdu{^Vx$aaFoi{a_rL0L zOc?-iH;tQMP&T(-B9XC!^>5zzEn!nWY1$4^Qxk5aLmT#rL?X?b^oFada-~q!0r;pv zA91I?D$dqP`FZ8~9m>;yl9EYmY^AYd@Q@X$>-$Gem}oEXZf&Z8)k*FX)!Rnz;gc5a z+s$gpggwK6@>7;Luz7T8ekIfZVD#yU&gwj3ss-5U;(4+$)!Dwnf2daOUM!GZT#!q| z&B-yqbJL5omt13PWq&(p4fG9JuJkroSl|zQ7rC&H?pCQi>D1PI;^FCKuNjK2r|%WX z$`cG}HJS+QO1oRd)gMBc8 z^+Ev!|1=rSo;%x2^xRWRtR&g($eoYX4LK>^A5%k=2iQy zUX5uj#~30Y#?o@y2#73RmGA{aPB2FuZ%YBQPMN4v)0`BusYDda8TFDS8_R3(V=t~* zknS|e3mtG5)D^KkaeYN&1ZMoY8Kcy{E|40h!usNi-aGgLNf6UItmb-JlD;}B!sj8z zkcVlE8uK(Zp^AVWf~00?0(qs+L_nu6Ab`=}yp@76nuPei81cpQCT3jnQz07L;qt+) zZB!TJXPKdh_AG3q)d4cJjyW@VR{rm(Hb>2?#|XMoK)_BSkxJ4-3g!ubm6OM3=R-5D z3DoL02XkS0p<3?G4r+B>vdvFKjf(=%t#Au`ng^$~#X`9KSDY2RGb!a`?u1(gGq z=Ex<|-*(w|`@}% z(oGa(=s61G2l=}Wy4039Pw8KR06yxZnXmIr-NH?oJj$`|)oFT#Q=b9|>cXu2zk2~S zr1!t3g<6c5fiEXa;u#{`QRO`K&f1f@%7ug3JNO@gTDJ)SP5x7M6%V6~CbSZC z^4`$mX2gNRJ)MLT9fnfOG=rY7NR7*xx}t3Oig+5W5`av~Ef>PCgD{3Su-Zafnv{Zr zGSK=BB!#(vf&{XlELImTm`9d5(PtiuQ-=Hu-~(m|FytNG!Sqxs;LPV(7wc2#(jKkL z4rnm%!s&yxwDUW!ufjN7kjg|YZfMy;wkTqk?Xm721h>nre$^<=te-Q&3nV;DJ zr@P}`X<9VwY#u}9xNH6p|O`a z#3{k9D%ljI8C>L*6Ia#&DJ60V<;0^sG$n~Xm(YZJY$=#2w)S%`$p|O*+(2~)7{yyu z-j(Z%53HGa^crNXc4AjWzR$J4u9(S5DX|X(6q^sF@J1?is0f%}mRqRk{06gE0 zU}u_b!a}s~DgVEOm4E^TqzHGL+~o5umxO3}sewA^f5;iOt6$}J=8i${tK#nG6-*kE zTRgPS+?sEWV}ImXJ#^Xdd%>s0f^zpPZCO|?-JFl=h5}QJkmH02OAEUD zl5Qdk+Xe=0zufS>Sf-u(2L*jHy;`&ZRrBWK)zbIv0A^#&yEGB-EQBks0Q4JBH%D?! z6zqoXtFbSEh~yuOz%RMJieWdiFRdsl`PeQgCoHNvEiJDdMLfXdj13ba->xg*dW9Xc zFub@cbw7pBnFAwaElp{t^d1~29V3iRO-a`>dCB)Z5`=}GQvNqRKdQurvSDm=vE0AL zFYvb$kBLz@+>C$mvq^VSYWif-XL_2VgM(*bv~Obt2_-a>1sGprpA!EIQx`(9edmFe z(EX2aXz^$y&K;54qo1!rR(_1D9j4;Q^;uq zkn8GNKtk)cF>Q@p+x_PuXex(kbbIwengaiZdC*R{zD-w`33K3dfXwqk?)yUv2>#NV zUa>N43Qdzgv2Zc}g4Rb8d4f;$^xC{Qn2tNp$v}zqE8gp8SBLdQ`5(Y})_{g4$-i-7 zuym}OQQ-S%sTQIpg?8<}l3yNF`xcV8`!Z0rHhDw~%il#>)e^sHiFUyOZ~;+rv6fhp zArOx0$6F0|k_;_1{^;o>^*1t}>Eg!|VFOwC62*?9GXU%{8M35QmHjt!7B0C?>-eFmiaRG24^P zuBzvJk0E{VXpTn8vXX2)2cxis=v$n-eB>dAqhm=M0i5bO13J(I&hYWd1)E}XINz@H z3N0On`q5fL-)Vw`scRFZP70F>K;KK0;Acy|nitoS!IT;GYrA0lD4%Ei{AM@g^bEo9 z&o4MhQ}H~)wg*!Y+sjn3g@B}6+_^Iq2qJ|1VQp#j}@PZ;h)`pn)4>{k>6vCH*pQ8adh!&u|rX4d&l zPNiDOhz~tJ#(S;{>04T%B#MUoi{Y|nY)XK41&!D)F08sn?3C*vF!Bh4gF+E&iMAxf z_s&kAn44hobkVBfS*zdwmIm`U`il&X+$eN7dl8ELp_)vb9P?7FAIcm3i-!9BD`Qpz zR|_fh1Kwn_r$LG`ly6oKXBEiGfSo6=_lMLIcDQhI36dEpwqf}0Np=ob5sf6$z|K1G z(AZe$XdLr#E-m$PCLB)}T3DUg=tM&}D8;Mrd*JcvYOx1iPKZRopDrzo<8SvQ#w_I& zLc$`8#NM8X3X-ji#(KWLgy$K$rLtjrvX7WQEY7vjID_=)A$OCsc3}U*lRn+PMWXJ~ zo|u1UgL4^+F)~v|0v@*Bn1IjUiMYjlH?xh$_e8WXQJvHpmhvNB`&QYLJXS1);CASs z999?)-j4`S;`E%44%(#{z(v7wOVrsC@5)UeKIzhAwIQBk9H)0w^kz{pHu_Tq7NIOL zuhhVtTopB^pI(svp8cbu$W&IK`M?7mMjt$@LAwx)^ih4>8H)5VCI-2>S$inLQ-gMY z#Zn0qv1SrFfTxL+-v?}bZc7V=6dE5BErN+#&HC{wPi%u2raE|03Y*` zU1wyI*~1KiH0p(%d&1Q59*|;*q$LV13i-=9nsaHhd75kZj~2l${eLQa`8SF)c?GLJ zp*x4kJChE!{la-Ha*?+i0qfYkx#4B6=&yO(Fd(Y0MZ~_?^*Lhy)FjB-Sx%;)Veov$ zNBn#hI?2354`a@@I*gQ-e8j=KSRlU_mRv`+1PVXj0&zDJ%kR+7#?#<%R@x!;L2eKi zu+@YFZ|&heq^qa|G1{H5>4A)?*zi{0%kqrhENByRX_j!XWC)!Za{OfRGmy042zj%- zZ3M|`Dodov(!N0JwXLcub~ZOPgWVypjV50z778fX0ckPGK;&>24uN^fS~aizEE(W= zpA8^Y?(cq+KSBUP@?-ERg4UclrZaSaX~rC^B9WK6PBo6(R~tlrO}yJ8*xaxRHzCk` z7o_cxNp`e9!5GZa#_J7d+gncZ5mxpM8KT+^j`L&;*zCd++FQs~&@n)`V>#)1+EA2j zx}>}eT|i#;rFb*4+xB`hu}FiBNOJoCh;i^W-m>*YnsM#!UN;R4yktu;2Jb02HsoaQ zRpKOET5!i6wyNAX6N<}aX~+PuF;PC6$3f=%@?82e?nt!OPy#U=?yTw|a0{_^xN8#0 z6_Yv%XBs;-(!Z=(4HN!FEISc8@lTgf{x4qpG6{EiZVfCV*)86&^$X$)sgf*xyUe9y z)wW%ST!Lk9`*S<3Z&mm`JmSGzJK%6|J);p&YtuL00r&tG-lGss;sa5ox-0lT<&`NM zpvpK09H7_nD|U9+JVu+mqRlgqa{A2vQ~0J6LLWEqb^Y)kOznL^sIe4U@woDcW~ppS zLTa~`$S_hrc&sy}Ic}YEaSKOewK&Fz=_=aGnGBqW*jHCgNt5xXl{fi@b6-v$-}oEe zUR}s#N78+N?MjHY2A4Uu3ILeaR0)?}ViYt459zT~{n)_x^OMVE5F_wV_t~335;m~s z?SRwx^K5E;`=^tmlOF+?vDl)j&PT=7{|-4=awVUEJwcVD9y568yCFB9)B?R#1^qZ89Y)+;255VP+jIr@y+C> ztQ67|Cs77II{%(A$k1M~tvLV=>9;_+nN6`lsAg5Ovc7?&oep+1d*w*pvWH18vJm#f zM1~!!(yWNe=TjtI)ouG`yj;WF563!}8g{e)MQQ4LxdBlZma*&x>xs~E?1=;0AJqEg z0b?H+n10%HFK$r;h$b&#K2;IbaV|U8K9Gsh9iDfiLqjt(t;xpoXb@|w2P!$%)V9p{ zqPqN5Hyh`t7+N7~%(pvtNC~wJksjV*T>u-Gi-cBVR(Gj&?a@F^RPDBA2u0Q^9%%B9 zgqA|M>gUuS3o+H9YKL}DU~vsGHdy?Od7E9^H#%N|%af-cWGKk+?Mx|ULSq&wGi(BR zKVy3a0GY)(zRLP#(V#SspWJ>PJo7SnaH*i}AqJ96sbW#(eVw% zUmOo|+C^`%41udRetGOn6v>dOW8f>&aJH z;JK<0P&|oM2#qa=pw;^Wqhy#|3MVAwoak)pfN29IPYPnB^|Wz)y>)gbmZZ9zOq6Aq zSr|QV#Ub#upWUdJ39PTjnqxzQW<@TR5yf61H`l5qOk1jrYVA63Y2V}VY^Poa8^w*M zLOLvLpDvU(mXiC(BuK7Ea@3WqHK8wV?p>(O(K~ig$ z6hv{+k4p~BmQbXvHQE0&_4fqi8@G$9?#88V?}Ji`Iz;L#w5yk+<`bKby-jfngP z?jb9tmZE?j>AV90u4=gs32nV;etVvamHpNQL@@7bFv&%3py;elU1kyy_i-ipGOXsP zhIU^mu45;rs(eLS03hRijua_tdJ`liRmhAJKi{E<%}G6INKX5~N(J zkOliH5_jOztgBVFrxl`fYKQ*+u5$u!Xl)=wn4r1eSuO4U~N?_btDl^d|1b;)2M}&)Sv&4; zTb}n@XSM#D3sdM64s(dg59)Dpv8OpHgCR9-4Cl!0fC*}MYZzkWC%oN;x)cfQ7g>xk zu9(C?*?he1&y!jp|AIkOr+Q%Fm}OEcurT&lAV^QZfQ<5=S>XcYq#V$NljL-SkuKGY zKPT#EB-Yp9Sl9M^PQ=MMzhmgG8`Vc1=j94X{V9k{v>s-T?1U_r<=>bCca56tt#TCl*7{6@J0B?DBgGu{3dyo5 z{}QE+m*|OP4E65Ni#I$qm^U7criHR&sI{D|~Nt4rAm|hdwr`fS>BK zQ=SchC*MG)_bBUl3NIm_oa8u1wV(yTxBZEr98F^PQ>LM~L7#T06g^%fZn56$AB}rc z3D*q=d}?PH)R6vRIs(f~cJZ=ReYVZ^XmAAH;PNc26;Izs2E&$*?QqudAsOW35NHHQ z_km*C09CW?%hGF@L(%WzUyN2w;AK5?0wliTrhpS|@Z^106Xs8=?%W)$bnTWs;P3ag zg1Nsoc6^vmuonbK$vBp!-LZLE7HhrrI>E)IN;%@}e|PsRZ%FSj8!hZ&QF^nc9KxIf z-l~BP(Mpxqwi)%`c0*t`D=|of-5oUjB>g$ZJyiWnwmN-4jN|t!2T9u8j^FSQV`8GA zo~tWiG!ms`Bg2!7d`dcR*PQYCKYBhv%SIV@a)CvKC9&pa2nIvgSg=_d1smo=p2D=9 z?fnakG~73<@~5jm_j9E3dzbMcgeNg08*1CsCt5u_1mKEz*ITkj4y5#6JMAoX;$Fg4 ze@upFR|l>d%LZE1evhpa*Jf$xJX=#GlKY==9b|O6m!?Uv_?x-v`U%5XJp`YN3$jKO z%RnP^lIWN7u*AbXkQ<6`A-f@ia)vT82YikqMt-nc_+)Z}DI zs8bQ+mTFS71SH&zHp^I@#@Z@-2Jb_%v>?&y^HSwf?%8rXzlU{h_H3fufegZdoWb!| z6fOAK5-#hwwxU2Dd~*?oZL7-3(Tx7y#|l*SN-yjo6X(OI%FO*-1b_IOiH`AsWi!ih zV>ie`wb{IZQZ{;b-|WsAe;&5_55h)EpC6Sky2SMR)H93`B0#_Y3;%Kl=wlrU;N)E; z&co0UcJmYOlJ@9Af}8FZ!Rv9uV)b>(=V*&-aiCUjt_Jt@J4X^`e3cf8SVlJko*T~U zCV~(YN@F%B-2gt6uVK+nWB8a8&jbSHJf*Z+&6tr*AVkV9;@*x$QLpYU%r! zXeRFv8jdicnloxzZkTYnS=M}7(MI7AxgwTx83!HHw!{OQk5es}F`;Fxldga~#D6Rn|X&a8kqmB=eM}%oJvF8^09X;*!Liq>i`Ck+6aq8eJVf%mE2ux$AM8a82 z8^LJwa}MEG58n4#_DV!SZ|wTj5QRR0N8rk@xhIUswM;YJ7vh5bTxG##bDii>8W-x| zpYEiR_YF@{dpkntp%7lji~x}uQEjO_ig5z2z0Vj<9i|SYMG(xV8QmLj3MIPZFpIkW zRjztCQClT;4RXkw>5`spT&&MYH-q2(Kk)tJs#I@*J88xG9cZ<(kqh$oim7`*=BRq; z6iMOVCFlnFIoSjIu@4wn7?Obtk;#xgD18o=DTi1XuqVHrLl}36Gtva0H9?_iv@N(o zD}h?d2*}PWu$&vXn3zHszz`9|o$HlH$h0veDMtrEx=#kwv#hh0DVv+Ru{Ru6LLw5*{tEU~-Fh2-254&6uPF6802&u#PVP8Ky`CovMAF zSOVPs`T^zM-@^$0y&-yZ6Qn?vg^rNF0E(8#U({T-rj+1#C*srWnY4C#=w>A69Bo zXI{5-Beh(!9@q30?tc?)xsU!i)6`~-+bFf!Fl6?uswyxU0ck*A z%y8a)@wDckbx5I6?0Uj4VKm;M?0|CrzEPC9gbo?IZE`0I{;`NOF(QBDB;a6^H>(c{ zY56Jjbx|FZz0mXmC6qY{RCz;8j(s6bOG3V95Vk@@sx=5|oW52OT8j`y^qtly$L zYXMYrig5N><&i2*wGXnl3ZHU6hDaRI|2nf^Qc!^Rt3zfNdWUdM?ojB_5N??J3^Cm- zQ&~dhVDz_&H|{j#!<%a2R|BfJsFVoosbt>uA~>bt6;peNZau@k^w{-E1H@wSf%YJL z*8p>_Z0#DRifm=Fp;U2c^3qK0&!Eql$&ib+1LMHluj?v{fqRbvq;`%_U&4k1tO45E z%A!n1D>XmE8^6%g650dW5giBIt**737xS}XA|%$$FSiTc@vajVZ%DV50#VW7kzmad zK)$2i3`2y5;6h1e8G}Bxid9Iy)XGFfkpwW|n+@H#I<0`XPqPi2B2rq85)N)WA7w}J zFpi%;2phc6ZHlQ6DOO%GT^PP~oi+$xx$czwOV^y`FVkUvFZn(ZYSk6ck@`75FxM9W zN<`*D*s%QiOP*^_-he`8^*~X$VrP}RXekO-fYSvmpxrjT_1N)(&I{LmjHUlW`nmc2 zE@0aaUF4jH0FSMs>F4dGnZZt4j1p6Fn6LBY!Ia`niA;s{8RMcWYBc~kyc0-| zMT3(CI}taz^TGw&JERm;&9(0D?-`XVlxUdno8NWoEX6g?o={$kqCYhqw}t+T5ctFP zw(C7g!-nb+AY!)ng2OqM<=@*l15%{WNaIhDia`N3kf`?=2ef~!z4!9BI~Iwg_I3Jx zOPdvaye6kNTp6eg0SEb#Sz%$ZcWsy$L>1%Sue_q4a)b3Mx{6)4=JFZI66vo{9?3l9 z3mZTbBh197=^nlZlz|4)jPWOx=nk9T5nv5@Nr99$W))8G9FVZ0ke7;Q5GRhBhBsHb*k*J_$vuYOppN_ZV*kczBS*Gx(q z4}k%5>G8V9mfeA+G2GJ3NVvu zEE%wwwm$3|7rcP{$rd2YrO^xGO)3*FNa)^9A93P6+ut~5xxW7|CI5(s&XNQi?$a1C(_ z*S{PszF+>TeS=2QdR`FP8t7an4aBjT)0kmakZ;qJ5BZjotAQays)QVHodJ|6R{%`T z^Uw|9jD0RQ`6@)hx^tbgchk>kYhoiVKLr9Z?yJMz<2AMQr3US=fuBvkStL)h@{=Rk{etX03w=5_UmDU?`s{rpmJfghJ`Yb4)OBS^2pYE-|4)Wc2 zQ+7l>DCk3f3cG>d7@Rvb{bLat&g7&oM#U77Tlf(dpk5%>%3NRoxg#&rnaV(p^7YkJ za@qE;aZ=$xQ-xJNeM`PZ;l?@v z$Jr-IF*`DWVIkMoW7oLJluPn3KbGA>)&(d9p&R+|)B25aVWijrf#}EdO{XUJ+>I#5 za6UDBBsjJ)~^p+YOsc zwlzo4`)gebEz7<9dbpP~0dZma4`j-Czqo%0+{5-VOed7|tl-o)iFQfUi=BacT5YLt zHs}GaU|r;I3Sd39uYSj5>?9eb!$&ob|0yAeAFo)0-RcoYsdy8ZDAg%F&hX(s6l6_# z%zMM~@ZqWZm38hiCf{Kk*NwzqJ^Cc_ffm3IH;fRfwvLr;`nwwVuc{%#vkMd~Bo}c} z2-R<%BjaYWwgca3m^=gitt_+_05D-%MN@=wJ?jv0Cx8MhV;6^5^%R(_NGiI90W9R$ zf39^y6rxlo;?D>VV~*KO;Z^HR7&2B|y|rO*1^R}wMr9+NcMG{Pk~gh;B^ACP?Tvk} zn1H~ypCtDr4B7+3@CS0l6G;W2J%`o3uJnV69^^LIh)J$CV&;#pV|S6t8R~82{i32E)u$+5z7KNWAyH9VxB#Gy^ zKX42CZD(1H*+M>4Z%>UCcVU|^jkKY4!fN<;;$Q*X#5VtmIBCRhf z@p*FYlzq8fKiUsvHt*(mQ_x$#np9pQLTS*~TThv$-{5Pz#=ep*M)KeUhN8L9vScCz z^?1JukWy&lw-1OzEYfXeANExW9$Hd?H@nWqphd!g^!W>M^7PPljeI%@{@hjdf)kO2 zG7xB8>u^-UDDHb&zQrXFxGx=zMO-QMFi!C2x}iPO{Gf@N-U%c|~~ z3yImV*i@#}`y|izSGQ%)r$17(TOWqo@1ZHbe|Vszzej!<(aqf9p@0w*`3PFG%jK08 zE!lm(r=$}&0Y0)g8^-`ib>YiikxafdP6so)eG|q;@5FNWSAnNHKd2zX4-N1HV$DkP z8odv%RxZ0@{}$WY*}z)|A0{`pi9IDUylR_?Z0YS?qI8$P5RqNCdoAqc1leqhgl8P< zCf~}%Gztd$^_C9$j+xpoZd@Ha&d?jYiJ9pqE88-D+MO~ML5raRx#ZcURm%}#A3bd{ zB;BmSsOqO4uSH0yGPj3kj_aa{4QKtb?5Lpx(LvET12RVv6^W9BU>@LC24!FqZFJZk zgQ=*A>Gotxr$~V;bSVpucdAodE?6}}zjo=t)ay|=8Dqa8pn+8sqRLXYGLqQYlhLO+ zH9PS2FJwV62@Lh$G%GpF(vb=G8*boEAcT#Sz}2V=yl-%AUgv!gygVg=69m=7vDbJ< zG9$p*h7@7Y+uS+1} zxq9wFe|v98-A7ZGsyU>h&;JChna06ENdLg%m@9g^Uv-@GwKS=#PTj^NwD(x{pr9I% zRFdk3{{VZ2X%8!O>w!UDB2$*qzx{MH(lTDOsYS-z71=V}&G>Y{u7KN5 z^M(Fu!Uo{bKSqesX{08-OQaSzvsulVC7i26T^wmvy_TU zUL3^~ASVlziLv3DfBiybU>LSozn$sZ;7LNWlGfDh+fc{{faTOksub8M78WZZL(yzU z-DuAml+(f{&%FanE*o}yaqUSs0#}81JSDZdO7_n-2_j9dR!cR=T!-BG|9I|i%FFPf zJD2+asV%Z)BI_a8#UwVUxjA1O`+hQHI0P=8&ZBrJWe)e$?7%pKa zHh-w*79SYdz?UKBc`Zzf70O2r{97r>-ms&UqHIi4Xws3Rl7`7~zLBuZNm0+wykPLN zs&roSpxk3urTei^aZa?#H-e}QQ5qxb<4PNMf{0`^-1MBi8m-?p1T`@Nv89vchg!UaAbXxk zj+u$3662&mGM#fBUXWf^UwEQ37asK`r^o(xK&3eT#uo%*f=|0cLFj(T-06TNFO|#Z zDS99%+Cwp6q7g^DNnq+L2$5%2%u#>FU3WuXIJ9roTwXH7Dj-bF==OLSrB^K7cVu06 z=Eg+*&}1;_FUuLgX#EEH%&bIj;g2G{Y*s(yjQb_74tCIJNi3g7v7Y-fwPJ|MCIdkHdLu>YAS-S+^X%U9)x+9SgLxtvT|4* zs|i?2sE(Ect{63?w+o>t>1rrZ%fRFMIl8ENy*8;<^~dgkR473uft+2$`Q6AnU3G75 zVF^)^6l)Niuq9=Z>-hh&n1F=kujctlNE*)vFpponOfD?=Vth1IBP4giQB^9Io@Gt` zISk4u4+i!r{>Po?e~aRz=|``BoSI z{E}p3VeRqFwE0fZ38!4?oI3rF{s#O7u%^{;b29N zOCrPVPMMF4Z}q|(kq3~jUKP78W7v-pJatc8$(hgEDG)RO$PfdNs<@}YF6|x?hv7R2 z2(seC*#5j!3QlOHG9d>Y)nms>7CA3FZOsn@G~9tc;izqfDh?m}T|*=k20fFa-2c!N zul#Zvf<%2{FD6CQ9K7V*9O!Yc01acgePtc#r5hODK0vnjwSQk-Ez=EE)r9L&MH;j1w{XZ;a+3ROi{WX&%H z^>3c|pjHVuu%b0gSxN;`v+_MVJa|d$`+L{VN1u(PV~+$m4fQ7a1WA53wEjR#M610~4*1ew3YyRMvk7iJ6aNG{&vmZ>{QEYfx;<5nYEi#?Rm%=-4X;_lGH zQlcH#Ld9G`0{d5dQJ`siI!e_`0*lrgSsj;yUd-=AyN+W|`b%TF>ir(wsPU$u0S>9^x^|OO1=WnhYRJJ+%r}PuJ06 zAK~cxbgB0t;^dl#t}TQnoq+OqUjzxqxThqg?>PdK!`8w6c<>{YgPc+-*yc$upok?@cXaeTWO6OWFBba#! zki;zdxY|F`AM_$zxklXKrP6Co7LKoRu#P0oXXoXg04Ic=)FJA~Bz#^ld-K2L4c<&chFQuRAX42PqOc$)CdqQy@>g?{^F z*sI$N3K>#OVx{_zP1Zo&Ui)$11R12k&zS@jT)t$a35LE;EU zlHq9NQm#Sfap@?d9-}BWJ0!7JeU%Gp zeT~IR@~JG ze1KE{D1K~DJHfU|C?=O#u7XgL?&wlWQOG4eOv5h(@DHe4$f8(pU#?<@##x$;U@99O z$R58GRS_RiF<@SLV;-!e$_gXCGbfGD#(i+!58C>D$Wufga-}vr7jhri{eE+~gv?}< z$J~Gb=J6zl_4Hqknqfw`)9*bL!%_dXx7CTisYO&&KI1jhRmaNtI6hQ0@=Iw6<^Q)t z^Xfi%LEP&sP0L~iyi$~H^c6riP+USu!wRLVWi}wP{7dY44ip4B4i$r(24&(#^)a(o zH;!VPHr+=Gg;@p@D+mEvZMw>J_+(MA!Toq>Qjy}Rt7}msmk%8Gd~*<7kY&G<92_t< zyjMs=Z-Tvs(u1VkSesyM3uJMol!CvhfA5kttL#$Mi2o|fMISrrLbLpcX$5PhJ7WX^ z#1O#kwrQy{Uxj=1pPeL9&vY_%iou5>D=UyVdCDWU4^&9zSF~nkKb=%;jBDKHQYe&G zBGA2Tyh*i9C|9I5it%_my7F6xyed!EWG|$N7#gI5r1iA{(+Im5h1|ohBV>eQciDPU#v4@TK3p4%^ z>NiT=cBN`+K0X$d+}7WI3?beC2SLtziIi|JPATQ0MIo7c>4fdhF5 zmVY!616Yf$WUCG`K#pHb$<^(b*TdE_tTVSLj4GW?nH_ZTR4RJ4P$zHJ%nV?Fk=WDM z0ZjR{Q6bt}S5;VFJ`??z4DP zuIQRj3G8|DNDWTkA+bPmOPA;wMCf+|49;#%y2cV0hUl{^vLaJ0-flXkPBoa`ndVYg z+eQ-#bgmSL7>A#WYo|=MYnH)2<~Q-p@e^|@VuKZmCDV>pS3C04DPurH0cvQok!mR( zBK}$C`5Ck9*Ik9IgxE``I_LLpYl<%uJ~n>Mlm2NkGtA7gV@W=3m0Nl zoimiTUw`Q}8;ESIr%34U^5OMz=MeNsZ7GK<{p1R-T4JKNe5zPOX3B;I%YOA>xzJ|1c10?X@!u( zyEi937G4-K2BN64dY}}uW#X9Vx+Bb&4j{aM;$*+*X`;1A+hZhc6eERroB%UDE3$ha z{S+VY$1axWL|TdT85ari;V~W$1zFfJv{<_AA}9hXPoc{*UOcnQ`J)tg-u1Zt&QRYf z_O8l7fnA9%z*~16Jt{oai}ygKBghnoV%StSm`f_CzaTu#7ht!Gi&qjq@Z2r?)54b9ek4#szcikQO% z2&j}`*3R-XroY}HNH$N4vRy^ai~9$y4Ruvrpa|5DFwNQ84%xxbCuqOBj%85i{SP*< zuZTj+^8_j*l_G`29J2#8+B%Jgk2%>OScmlbL$?+>U!wWAAaDFkP{x|!%QL9C2%GmU z#rX=S=nP{!p_l&QR1a?F=$#u)b_yB59iyOs3PjBE^qG9 z7%$v@O4l{P?7lEB5OkmF0+^8?Zq&9TkP8pKQT^5HV{JT^^oOq9aaZ`4bPZJUlt~x< zfLdbH#|qp552Dg0PXXhqbXFKhgBeX6I4Q^_i5EYtn4g%9`5+2Gt@2igMt$x}>%R0% zrz*s=BvGrZ(YxRp^VE{gLT&an`St`;8+41?J4a;@HTHvlIbIxYt)8F)^cJ~*lEDl` zz}n3Ii;eEWE$ADmWQ*;Q;KMl~JiwbbY0@EtqksLGZV%Irk+)T=)hm4m`+72EN@|6z zHtw_m=?aWvWB`Hp)591{pFYz$;akQGE@v(!9bS=j76JHqPkV&a@2FLu?vYVqXaLpA zxvC}`yt7dHGzugh@!1iCZF2r+S)S@I@1pt?(*#ngC8vTX8im@)JC6F62#xWY<^m6r z>uHe;#YPATfB-LM52pnNGUtGJH#>PyawFFFpe8vo;!FL6`(Kgj{D>hIBs#vCAnMW{ z{KAvnN-xC+nSnYeR3~7XYz(tuwXcVep5<$7Jvy))Kx=XG+{FL-VuTfO$&VAgIu~H4 zz3o0JT$Vu#IH+N2`S?+WZPixoZ`orRQTfEU!@C7qieL(9haFrVhfZ{n0oF+@vhji} zJgex#{^$-d5F^B_fUk1z+Ugc=oq2%KQ^h3iRXf4BZGZwC+wxUT15xeV`M+X~{oeFpqN2-_hL)JSTEEpHp> zSUAIEN#)z})NIMzA6xJ2pxcYw*ML56k?HpH2S)kaXE-P~{B+wOq-7sa4J(YyDfF?` zl5X3(`2OX6_pI{F}%E&W=M!t>Wi1on%?onUCy|uFhYuGSX~(fi~@6I8kR&n z3^F4@9X)D8Iivm&pj|%34I3>oXLJf!dTl@5pIRVq(25iuFaILWRe%&wLfx=4Z^%|b zei|Li4JZwMa_3!DcM!HYnt9m(Pu2bCK*k#mFa@0F0#iykx|wh*PoFPskUFQ6Z!pM` z%$MDnK^@(X&C|)m05~K!ogaBee){&j+|-;UIP3sDK*GOKc|IKY-&UG@f8EbWsVxD2 z*)=UQx8}X*X~ZM!s;_MsfIZz32SuY3nTo9*8u*`}H=?te{AYj}uQ+HM590?;7zdd> z^o9FeomN%{KQHh1l%s*o0p!GpVka&U#|y&lhCz?!q^38HN) z)lz8MT_bZ+e+LwWM<8qay*jb9*`X3@zV8a=fkiymGyo!=-9-#9v0;EsiHH#+=hDqE zv4zQBOL&!5TY)Dc;DoDxA==^LVqSUJC|&kf%0Xpk&<6l^$oB}cSZlO*5kI^T0LrG%M^Q>Q1*u8XqQFSio zUean!0B@uz|5P^&1)UcGT;M1d2}!O-045cNFbR;`cE4~@Z4mQTsy=sfuLoSWBGkCKVU^YQ3~?Z{CoYBef$k_BNDYlb zod@ocQfpKXL>M=NcZ(C5Zl#2qSC|QFut^fzh$gva8Qdep9zjv12uFhU0{@B<;^89a zs)Ef!rCzc3RSlo3TujUWr<}w7{*|_S`#4mN3NdmDB_aoj0f|z3G&cC3rX|!5?V8_;?*bI%iZ&MQi zsT?NxT}5aPqqAY4a5xZb0IO@AK0?d@Dz=U- z#|u2`9PF(X$*cK+|DzFW%IqDxXDzvDnr-bu@)VfTM?*zHzsK#J%c|uTl0!sKXL>A0 zP>-ClUk3#{?}VI%w4B&Sq<7{+yd&P3aNYv9o7Y6 zqU8d?S={^asVXxpkIr4{mDmp8dI11)*0lxe$oDv}(>+8Dvzmr+1BhQclAyaF6OO2- zBF;;}UBqq^+b!Lpr!coYX!BhnkW z05^5AYzW{os_Y?D`m;6%IKwTMP6fCghZ5vjGaz|~RIh!rH*qNXcLu4~hvjM^U8OKt zy+P8WN~gSqH_|q^ysZWeWN~#9vuq}Du~;d1g)jT=y=#iJjPP0I$YkH}7uUE^!r!$Q z=yq->CbPBt2dQ-!#PJ)!V7UM4OB_#=1f6%FkN96SUX}f5biAYwLpB^ZlE_kqh(q~| z?CwH%p;zA#1rkiXIc%K;y9u*o(#gav2tKv!XJ40smUx|FQng zxGSG^b1A^_K$UqaSULRM0s6MuV|2Gbn@OS=l}@i&xcYhMP(srB1#3ZNbWvLq=wVH$ zJZxcOv^M)xKie67Q4ef-E7whbSqD=k1$^&NX@sgUwp76a?o9X!4{wqz&rmWLiw1LT zhvl}MLmtq^Ti<0h!j@uZh#NO=7+|W>p0!WG@D&n^J8_wLwUCUNTNN$@iZ!g-Y}p0K zyxSS@bCOLo#_Pr-9KWz0U%~C5N(Ac@fp&xQo~UmO{;3#&30l|NO(Iivw~`k;TykMH zHyue}Qd`ep%tL_5T*p^@YXKtsw`jh~^}ztC_M=Ts*5!yd*I53`prJr8<^&tO;f2Nz z91AUK&*8eqRPD7AKRgxuHXUK9jyK)+uIUirPq-mH8ehc*KLL+H4B<{Q3R3P0mjme@ zMmVlLgO?H3j?4<3PhgShs*#GxLKMNi`~Br|$}U)y!^L_Qy9oo?i(i>wZn+vJZ%ArO z&X~Fw?;G~~L<&ih)jY!1A=_hRK`M)1;RgA_7it~Y_{4K;;gvKEuL#ba1dP4rFR(_;bmeZ?5e zBb=w8HKy6+Ia3}E*h|CxmCq!a@`I&YV-N$jM~O$5lr62Y>8?am7r$|T&(okbMa;t9 zDQhf;o~&Es69q$QWV;82+&w(Vx2a54>;s?^tcN} zoNw33Z@u|4e@A1@6sz7QCdtO9*SBh4^t{%~J_!olW}N)1{JrbG_ItyKu;v=6XY9zH zw?0K&sDFt(*u}r|>Q2&b3x&A~i_=aCZ22C~yAZL&D+W^2alA*N0vrH5Ciw7%7W4=C z`Q<1mr`>wPNw!?!Kv74RTI1$Yt1QcAk@fZtVzgE$T=j{jFQuD9p;mk-54SeI%gj}w zF^X6f;}BM5=G6wX={QmcruJqzwBH-wh+$Qn1;WC6 z)*r0Savp7)WjuO7*C%DiMMfV z?g9=O@*0(3V-1n@IvUYt;~@K5Y1Q`EeUS`GCT*vtE}s_@&FqYQa-CE}sGeqaw(qVd zXno+Ed(w+gt>I~3w7-zL!`ngM4e1aQL&?X+CReQ6I2hDMc+iifrztB(E+z4-ZfPYh zI00^vRJ%QJ3A5|Vn(bN~hCKRqq=bh1M~6*@)6I*kB!;ln)Cp7}n9tQwS7*8g4Fe5Z zoXWGUkph#{Qdqq&JhT|{F_?6Tb3+~A6=pkOw&m$-!H}huNDg1gy~0jGg!D$00VHEh zGLCbr)j}xFYnVX5h88J4vwE#3A0_#J`Enoh_enR^A;|MQHh*cN_eRI!KMl^7uQvR; zmCm?{RCi(8)ZE$e0tBFO;kBhZLG1A-D+NQHvCxhDfno&+^3BBDmDyxydVU6V&H=Pv z@>N^v`Dt=E=E@xv!QL!8g}9hl#T3PXS;o6!szYEUxTfTsekR3HJ{grkgZb^gZ3Pe_4-Gn<|hZ`vVG$TUa4b2-PNdRQ5oNQ z>ivasS)Pn%(^O-yd-lE&zD_^jV0u~0r!z;`sUeD6)CDyviwd!cxRP5kf$;$h_<%0w zrzRT}FElY$A~d4h8Vhm>c;Oz7O6)jkY`W&AI{gc%-;C3Cg%$YMdrs*%%e8SRe1U+| zCKvp)_cn_{MQT|Q^V5+56+=iDiC4qWk59N+w^a(^6rZ5Zb)ElJRUa_^Lypd-AKPOo z_T0xH)klWJjMK-xB*xEO76TzWa}ip&j=vJuox(2A4$WbUZk)h5O_b`zSGFd&Ms-EZ zAAfYR5#O?#-PU!Y<_mFZ)=O?gSmpF8b(@qrkBI}z?&4)6D{vahpTFY_0{Os{XtDJ* z(A~^bhHM-!(QgYUEbLfvsuptN5VBhh6@3!Yfw-mKJejwK zm+~$V_!4wp`nskEyQJM!#GuaZH+?YqQe`_a5skipgO}onC^Nr#CcN1e$0le4%$uV0 z!=hChU$DF&_*exscipjg{ova?;6B;EX+Yqag#3rD$zj`&UcT^$10(jJ=t#0Oy*9iy z!ZY8uO_nW+(woR~QKpp5b7<^=t2n=x!E|g7JnN-YO-LZXG3Dc8@;N(dS|SD^WK{p- z)2kpk&uAzTHpt(5YAIA9+WM}2Q6i25n#DJC$nqE1|AEx0Z} zBvd>p1E^Q^{H{Ct>;0L?T~*RLvL>sh?>kO62J2XvR9y56U&JJNRJ(@_q!gJD=LR-( zt-h>^DXNc)c&W=ZQA{Cw+U2IG!?y$--~e%!N?$L8;Fp&`)9<6}v|-#kvt< zAGe2XndsG&Xo3f6q$X~c-nn)c`WUnlzbXrBB!WvDSa?$nuR1OcdOYe4R^A7z2_4x3 z$+4%WfT>126vzWPHg9XeZD1*21S2bfy-%FNO8$5m-#yJTEi?Yv`F3|M z6jNF&d>W+_pHkY&TA}O04?2Sc#guz{VM~*U*B)502<-9lAm}zYFri$Z+TZv705r29Ac+V;s_dzA|B1b z!WZPVtP*(#zw!89EvBb=>F5%JaBBYwk(KmoCN6^w^U}snI7b$G_=9)YFhfv<$VL3# zUJZGmVAsS$!%_t;b)Rs;iO(^awB5HyXcucNw!I&XRu%i>V6(-xktVr?;M{~XtAaC- zK2HLo;u>W-9ML59JuLWMc}dHKYCB}(0=*W~8Ya+*w1-m*5)dOMiwr)l3(+$Z-ll|5 z`&5LxKvxfhu;eI<>T?PFfNmOwn*d|n#G`B?O^q)FKsryM=1r^JBwyv-aU{nbx$x*F zFS0P88&sK-#-p)DB@Q+n#klqQ%i|RMaks%sI+}L63Y7+wgOAQD0#zmpC6sl}Y|I=J zH^zXD8`RAvF+nnB8LbDFp-i4ryQp(XjGb+86x!lH9*;8-R=bA*HOAtI5?^ZkD{Ssqc_!_^GpnM75l>R!K9WF~#G1*j2E_K;vP zM%agSj$o-Y@@ETTIsk#48=@a@l_cGT@6=-0#7;a~70J@!sZ1ptCpZKqola=(nU~H) znBhTU7Jhc*uQ(d3_zFs}XPuuTZtAI4GHY-DrQ-L(f*2xO@kmnld^lC2YbHB6PN8C( z^#rIJ$5njvBCN@df8ea=E69&;Ut^Vy6iLyDIqb2UG_4dargdN6hfqBkU6)27RotxaGy{zpuvh?+x&y^^<~@Ft0_>Hx|_T{mTLy& zs~kckqk2!4NrzQGY5IK8`QFx?u;DB6SOG{vC8D-uIi3@*80iKR=>zwNdw=C^3wls2kTTH`uR>$G1We!>kno`bizk(=$Qj+vH=9C0zv1GQsv!TN&JkPK^d`g5LGu6_sU*pu4nQ+Ll|%h{hgCQU!^ERe|~XTtwJM>t@ zMbS%##3_cwPz=6`G|~S4f1l#4so=_y;ipcxc-2JXQuS-kmu8g$4a@yk>5U~;b79OM9TN#4s-G? zCjpMd%J9QTDk7b%e)ir3wnF}lKQLue+0+r79$JObirXku{++~cr7KJz(qAAnkS;95 zpHPpOVv7E0_us+(QgfD4FDCR@n=$03)A}VcaZHH13qQ)~HY;jOHyRdYEuURPu&Bm6 zwBQtVt3y~SX|9c%Awkv^oZ4;YhilVatx?Rsxngm>8a1pi4}I505D>;l{|<(cHPXnv z{?@@Os0?&*w=H;nXlz@KiuG|?zN5&9KVRo)uV;Rf97*F1HAF`+bF7_nO|HKaG&%ZJ zb`zNDAy*`&SP@=X`ep{+WEhWkUR)E%G|*FB@u8F@Z`=m=(Z$O>T%rMTcOS2|^%TF#+#4g=b3ZIp?k)5jgJ+|p$#`opr*9nfQO1{O zlU zSCI_;+ytzij8ikX+XR9{#lx;aYbaAO#!&R|vxPWV$4aM};qxwOU%<<&=pSe!0`$m4 zc_JPpgv`iKWqwpI*h2C2re%o8b&n+#n`;E4eOoi^4v?4u_@nh!BGUsiM+XGU3De|D z8u2;Q7#Ds^S4?NYIy^bxV{{N~Pqm6M+;jhhOQ`(T0N;_Y7$F2H2;q|3JwQ99vm*K? z>jTqRS5a%rm8lbfyO_FR&|R1`*(-#*P^H}cIA;28E{slsMUdvC&^=~-u^A4SRJUsQ zN!=--*w?AI-nv3+Nf`|)CL?) ztgSGlqb9UJSB|aZeAHDQqW9#`>)=j5jnCJvSIp4%jciLCwq6|9$`5H z#4=+FeWs5^%RXX(H|y~w`?X=3U0T}Hx3(Hit&V<38ttHR8haA+`NFxs>CJFu;(XL( zovlf;@!&-eX#L_3|0XZAIqb4^+RA8umm&pQanYywRsrC|QGXcLtEGD9hj)Ne2tsT;_*Z!xjS!d3}gVpJGK` z$a1=5RBeC}1$wAp3Uj(n(#c9)`5Bjp=C`^iZ}o+k6yOt{kQcNjh(^RFRvXAu#0Avq zcBsQeq4^?MZ?0g=Vh)_YTp#;cyf8Q=04pgv1Bm7iWLS}DU z3v|^Ti2tClAd%&sSFRjwo_sE$m#<*wW~37HtrrkGYny8D)fvZi?eV3lAc62y z|ItsK3o-D6Ht*In&-_cY08In1OtZ)JvS3mFRi>?AU648~D!jMDHC9|%u4xK31y!?J zt}cWIbWjwX8%A1EYWF#3Z<&;@(2jpGvsW^jA{P6b$_)D9PodGof4_tA8e{_^v>eBZ z&fqstL^w2ory>uOnJ^tpK$9_%^Jyv!+ADyGrJ=r1P+TEF&Tn)VzbN5ngu36_y3Uk@5>)4+ii>b znZQymSrdA`;N)9KrpJvNN-Fo6Ln8!i??wtLPzM?zD$~K zCeE5`?4=)1$*eluPPc>7tbGH^j`n^Ro95DxSmx4|)&E)M#uGf;&A~2rFM$3rWSIns zT1qKv=R4c-#$177%<%ITii}Q(Z5-wp6E_qAn$|vA93|al^`PLCZoR{IDrnLe`%i)qPDtd?`$3m=GMu5qDA*;eWvgOwvd4A(CYdh=ZfkxTKXdWQeaWl?i8-g$4s_}+*W5fX;MyF;lOjYOmLYzV=*cHaF69=jXnN1&WKRkPej>=O zpP98pga5buQ#_OCs*MWK+d^Y-jnA%0T{d+?=6&LUHmIRs{fWrR!J0db`Gc+Dsvh3E;DJ<%qn(H z9`CkNDm$2+O5Xc9SBSGaZm`{xe0dinve&&Negjtw zJev;!m>pZl(5%g#RC1Pm|8y5t)vNQTU#EAO3;`x$-|kYPOk~G-CKP8hgO?u{hlRDa zpU)c110m<0yWIZ7u7GYslzzKX!`Y=%t^BEX{pIatWhQLD@04Y&m_-M0n!otQg!@Uq z(56M9Q+8%dY{*zYz zxHx)jz?@Hs0M9VrD5T?WfW8^_W4@SwgYPuzgUo&!;93h&CI+Ox=l`rJV-_c8asMN@ z`&C4~mJgEK9T+OyCoUJ-fqr#r;qQPU287$I&b$3Cra6kdoCWtF1GYiKiX{< zr7Uy>Jh_tk9{Ah&2Be?0Hg8VRx8G`cuTusXT)11khPGrH<6U+`%+>y`8!6KKF2~byp zgdmz)(sn>#^Bzm3t7kPDDDnAL#dc>hVpx1~cr+?vjlCQP8F>0hMrZT63WdpC5Ch7@ z5{Gy3bC)`YcO8lqrdj32`v zMI1!uh7OPbIaih$UX`HV7NCT@ApvVcSnA6+0&GHXj5kI&5{ac#`<)8In9tsRv?4yh z+`Th2@6T&%kz$Dz_58G`_t|Kfu#JE&0pj{3kZ5%iAcBK&V6;hv3Ulkv=|q;DPOPoj7kts z`p0p`$6#81A#&pqr?d4NK_@hrwysOUU`V_6(`o`B8J_$XrIikl_@?Rw12vlll^or3 z8mMAXURf1~H~IFs(cK$64VQGFHpb{6@AdQ_S|@T)BG^tCVGg7X_eX3w0#M8-t-Ck%B=JNhbOam* zRf|T#cl@!!c;LxSUkc2$ZRh(4RLuwBAV7M*5&U0a{Icy0Lf__p9Y|(E4~vhO6z&r6 zOMWO5opWAW_Wdv{h3_wNxn_RAk}nPUKY_<8`Y?f%4|)n(S19(7p)l({d}YhtN^~st z>net!lFfjD31WY+i0M)9-|b9@s6ZupICWc_i^b3an>R;A>6N$^(D;42Ry zC#7&q zudEs%Egn?cf9mdJdH&DiqX$DH%Fvj#tgFboSU*ZZaLt#eFyAfM>AjV1fa-tV)NGC` zlEdQq^8zG6(n)vxqFB2TJEYaLvETX+7RuwxKpCy|5Wl2_To%xA@v%Svk;oH3+q(=a z=P^kDjK(J})z+Q5lMv;;FV0f9q{%eh_NnhIH4H`1<~y5}MkqMdKE{#%+ewRh#5|IG z%A!|R4f3_=eJ_Sfd+~oyovJ+0N~;D8LhU;vDm~DrNPj4oiFpxAV-7;IgXG>RxRr0c z8ZtlE0{lu-fW2LXC&RSSr*dp%$|KYaDQIMKo9YZJQNE4DXq57=2kdft)rCF4oD&+7 zRb;JxRbSeO<|i@XZ1bOb+WOe-{BrpTQey@($7QU~;(ng%{MK@3l5SX$AQs*6ZBiF0 z42Gtfam=a_*H=UgSAd`enTvRUa|p)>1kZ+?dsU&nGo{g;><|wBQXf^JlzA+UJ-Jnn z`zpuVxVLjsEeJ-tuGdwnqE5IT)LO8n`Fe<;`9z9Xtxz?eE{KkaWGB1}}q z#wza;M(W9lEg&L#ePhcUP{)iG%46qwG;@XTbU&WS)(RWE;E&q=ZOE_TbSt)(vqS_W z2`)N&4=FM=j&P|>b*{-fSLwS&mR^*=I=Ic4GmPBsA$-^|brodLM$~2>;1v}rlV(BK zK+iFL$XO0Q-1vKx2r{m5fxF8C)H-Ix+XOwIzb0WGpuBh$ zR-6}Tx*_IQ5S8V?kSd+V>$X8(oT7BZrKc4gYDheF4QhY@N*&ooZv_c7gn(hpiv~jF zC@95A^gFYNWg-F$SZWAti|AF@j83mWxrnD~v+jjF$@5Bwldl~x5}A%UZ^zUdm^_iG z;oorMll@d{|23G!apD?AdsbrkR9o)K)m5k31G$Rtl6`XDPhO^C=LnT zP%cgx1mUsT>|>mW&99?@fkzCoYCVuPWYR3fIfnM$a9}^2^CzxfLr_l)m9T6 zSyw`DsxOlkPObj#^aXKP&n^66UFm>vbMgRWYb;mq$xDfq;~ik1l3z?n=&Q?f$+8G?CsPVBs&Ft{#?EJbGJJT262krmZLa#<7{ z12ueMt?|mSiFRwto2y&p!H1DT&U4ZuLW13sgvjJ;{%NvZAW&GjM^Ml|vQQQN`5sO8 zf$hCtu927#*iqv~ba}MnR)Bn*3s>hhP_R1K6wp?IY;eF4<5y8qS8;$3umE zFVmO7${Hw?X?p;Vig%t@GCD)Qyw1xM2zFBD45K4s*f)6Z1JCrgmgm{5?wP1&v>&{V z5B#m;5BA1Dkp}*3{t;%t-$c0TAsbGCp)j2%p6NDs;w2I95y}RN#VuILS)ra_@Y^xU zik(Ocgv!~VkRPdRngOQx$7?zm7@I*79uhw0IF$s_W{f?>@JN2DXWAA!J=VVU--xRz zPb%fO*`Z#F>y-u^ZFFm1{1xsdpard_;OK?bKG4iaB+8N*H*pC-`?swz@d^08Z2cyA zxVlyeP->noUyh>;AfkL$8|&FKG-!6s%-_V3jSUl8H*;W7uhpbx<;g~A8u4$5affU5 z;!sVU3m%P-AtUGSH#bx;3Taa{b)s*^mFyP4=;lgXaPrd^HU1=gLscKBp)w z5t=6*!6EkzPjC<+`z#9S_$7A#@glq4iXqvMu}drTX`!)af<) zav!IyCY_^6BMiU|E30znDs*pB{#g6MKT4o@ZgPZs_Vuh||RiXqf!w|$l44Z0do4UyU16&W5lRK15byYf- zTtlj4xZxQ?j2|vr5x~@M5b|_A85@v?3Xx-|4t?hxhS;Kf!vDC9BVU{NtTz_p!t`k) zcY4OFd%&bBNNsz8bYj6PKm^7Gk7%Y=oSiGoRPn#424jYB3b{R#0bR<_e_}}u^hiaM z_EAmTr24NQhMwG?T6eoCjz`*Xf!`E|@CAlf@zykjViPmKTy>mR>p)DN4#>XBPBFa#wSik^WyJnO(fS?$B15aXL)Kn)UIenY&2d%Hz8ThM|1@N~&*# za-!{d%_$6o|92l$PLD|H;W8S#m?m-WN)+m5h*HrWf7&*3(vOf?U8#LW74 zCQL-ii~P;^qDDCl<7KxBqq7G1r*iF(qe;|^MTlDSD!fBE(k0U^*PK#RRr*=(Bok%u z39=^!xCySM@SwD;KGfoEEPlOBheZjlpvhk-PC3jk?1-t{*USyM0@hq?uZb-R+25DowrcJNxp-(rf!W96@#(+`#{tEOO)pFbjL^}QZ9bh1M#KkwB;2l z4n$i0O6!&@1P^vlNM#IzWd&eVw&l6zfsMRskG)DPk+XKD* z<9Qpx6eO(ocA-cwNi9)ZjP}{`R}oNvbbv1!^5-7iysDLCOE{Y)*WKvIC6$$j z6!N@!4Hll%(9#7c5D%QS!fDkl*nw`syTfW$N0!as2iQ?8k4M=n_m|`qs_hd*y}D8Bb#TmDR8VO z@bcBZq3Do;R*(3I<1T9=mClpj;??x~!BN}=?va@w+ED~3MuB0Yb)JTnKcnVzq2%Da zsVL%_4wD#~yeU>104AXtM+cS6ZvwX>kGLzwa_}p%Dy;B3-jCny!z4{f$f3B!a}FiF zU&Hob2wfi&JG{TPt*eQwcQXI&ZhnWw+WBJn!Me;Sn`tT4``M^75DOA98_AUGAgl&L zW{@%$B3m}%#}AEl6KZ%Y_N)((NEiAm7qpd|gldG|G9`z>1w%>3;xrjx0}JJ>0Ns_F zyby{vsPPrX!j#6C1-9Gpcc?wEzvpPdjmT-zX0k4!;BbP|h{7A4?nm6eamozvmKyeG z-4oc`$OGbOEyxxjCJot2%LR%N-53!4D)Vg3UB}F2laI{DG9qPcou{o5{yN1xCy4NR z(0jiQpFX~X1~69-hQ80`4^iivD*`lpOzlYvX;9gH@$(*cILoysY)@hyS7;NXVMms) z#!s+&U2IMfURzkOUO2p_3jaW{Q8;!Y*%R&5nfA-G>V|+{ZJMFFuA$LD^ZWh%hcz|u z&`CJXb}{g^d@k4E+zr;nlkCtbAMfP8Bvlx*aq4tnEIO(#mlL~|ry8|+2a+e;z7UH$ zzuDeX&1@x%zaj9?E&U}}Ksz!YgS4fG2K^xxo;pClFZJOJbqt>=EVMs$+@RLxeg>(1 z*7=AFzQeH+)96;Lq&-29M{b2CHb9Ea+OLBAyJpTkNXriZ81HKNwix+*hlgF+yCk)% z!yUKY;5$Go6wKnIYjUWALq)2rAt=(20PTAaNYZ!%n&Tj)0oT{r_?Pq?BE?R_ zEw*YvZ+-P-epZ;V{U3UxW0xwhUJuGT5j}6DLUdg~J2$l;q`AY-8Oxvob*SSkbEF z2uxrMR11|Bq+wao+#na^E@C;{i8LKfP>Zv9vj1X;)^FUxNdG${?5q;yuhbMsN&N6C z@(p(9u>zbsTlNZdIfH@20Z!tRj+PC1g9ovpOoucU52s_>UVkdk0Q&~7&%xHo!6yOF_Ru~i&Z+F<#uwl%eS#;;9r8{I61>p2PAK_ z^rdz%vSXH`_DiD8^Uj1E!2!m7_VzbCWWQ)FJvOay{e+KsB3Q8K@*gy!QH(VWi7jw{ z2w7Ig-1=-DK$QRdHWG6IQ60yxss5{>ydN-_8!ahSd3upp0+8&>Sth;jqM(S+^q<^G z=>*eFN4(o-r3NU|>(m1v|NITaLF&=W7XME!p1LoalNOHgxjPm9nE}hHAJL6=VI!3$cBfcYdMLF9V>`5D4>~=nrA4Rw%s@+YzJ`uy@Uf;e~e=1g)6BD2m4z zR*jeZd2i($pO(k9j$OT441{l#OoThxkOJR1jZ=|@mnVn6r()QF%-kJlQ=h%D`+wE@ z{)oeDaSE?lv z))+-}1ZP#t6KkOs#1pR9(R!o+3jyI_{8%RbnT6GOj6ruJg>Rvq9m!$*=Hbk6y+F5^ z=J3q!W6zDU@T?$yndM@O+dXr>w;WbwEp~5RIp^S_&7$%~6u* zIjuF1|7A96g`DaIo038No7g6SMx-A3a(8tcoJ9`f5D6im*bvnC#uzSXG{4X9kdjD~ z3Wi*6SNwV?19#Wj!y6;Y=Ol0!0skaxOQW^|H;GAeoucVia{X?7P3lX~fL(Z8Q)YRY z7u(OOaDoqP?TzbT2WsT-bVh+LjxMM77*^mD0bM1EW|s}sw#?3E*b@6QODI+lx&vQ2 z890zG-^nKbrUKU3{8|&D4|_geE)m^e7ev!Du@qL#q~8HYlA-Kt@~;90zkL~5?et?u zs^Iy1Pg>-|smjV+$3rqQGIT{s+Cj@*dmK`aTxe`bB(Dw_@dkvp_8|91pCYt|`FPWl z*#2syDr1(xf3hfM zvi#c>n@W3IT-svDvoOL*+(uOGB@1c=_Q0XPeqT$JJ$Ej#iGK6eO#Y28v88?tsPm1N zv7&3I)dPr)EeujZ-WPFWdv8tU9CocnSw`u0K4*zMjH3n>yx=ZuI*#%ccG=ONr!`FJ zk*RVjZXoL?8rt;}iQe&lN_rUGVAP%^t!qeMg=~v5Fa|7A4pq`XPfv7Mji?eNW-Y2h z1oV1u72f&cpV|15fc)}xT+9tE=J((hVdTTdW=4;CL=Br4@X}}O#1T(xjj+%wpDEdi zYM|fY8w;WvKUH*i3JvhBGf z_S!X{0>~`=e=?g3@8ChdDxIY#3dZWx;;bJ1d`18`>HjRxK_pg^wI{Xdl6+rrKmI$_ z$cIrVyP&YLqLlKUI}k(-O*V~LXg)Pt7;srE5S4(wMN8v7M+4Gj=QKcMnSqWlTLicu zPcCdjmZ?wozVW2g4%5TQy59p-B-H|N1%2r{J6F>M*pN)$@Bop`xd|!s(=(^Gz*HMu zFryo!7hq1wkMoZzBVFB;JA_uhZiIm~UnIQ*r6DduyonNZjpzusKVKb;U2m?;feIG# z(?ArXDyG2YD)wfdB%UF_>t5i(GShaXB&!GnifG6;GRF!1lsmCDaK=PghIWc$7UKve zTn;sNiFVN3j;-*Vcn%@a2eoZEbyV`y9Ywd}adgL{bO+g|%%wpw4N4>jlT_H#W|yzUA1 zzw*R}oDg_u+=Z6zs(eWrge`d|kh8yZ9S|+d@EFU%;9HB7QfV8&0H9EY$#6n`<08rI zdSzl~^U(vf8eJhs$ZY7KLt$b^C+z7#H8XTUs7ftSQi6uoB8^ry2f+_CkS9V2EqC-5 z^r^-eWHH^7ag{6*MgRzjBNSC~31Er5Ug#s#B}q<1wJ1rps<5~yi{?MgF- zL|qWpHl#av@)c!hnIfS?fPyi7}zA7CoS%oNRzFQAgKdK-Y)6=-2x zH%iijA*NFxgoT5;RtsKMA~cY8b=%*89?M1!gTk%m=zZ!mhSo{N*=`Tnne|#Dm$)`Nnh1Ud~irk(V zd^^P{&f|RCX@Yb;w2&wvVio?OvJdDK-g~K7L9bFuTXIoKw)bfbZBJ&BbGPnLl@Y!_ zwqvRC28G`KeMED{D}43VVNCssN&WtRXJ$!}8@hxJaPy_I3~>@GUxuoD(kXM>k4eey z?gGU$c73UacrLPgCpt9RmKQJ<;C`aw!R<12Lf<`M=u zX+MC+J7SA4U9W>L>*}``3acKh_KNhB=lR`SFJl8GpCmzYIS&7m3ZpdF0IGGG>OPo9 zPHQSQ=w1in;EvOEQCMcYyaj5#-|J@YFEY!>ZEeMh^T8wdRLrG3+O|>H60`xeX`fn2 zNTZVmrls-$qMPDqxPvj2}H0lndV$BJVMIczW72+%)?mZVRJ9(*V@2upSYdK2PAED{Dq<%R)g>2fF zdI~(3I!pzvr4^DGj41zS?&!+Z&#kl1CMC_{*$pwSAoeoZNY ztpR6BaKihA0upJ?$yz*?`HE24DuSo&6vREuNa;}N!5$(E@A(m*@CqSahRnhx!&m+Tql24X8DDvAj~O)@GL>K~{AOL5ot0pT8zCoiVEVimJ2HV|b|@_$P~pm%4(^)Coae!) zMKbA`k${})Mo9T>U{rPzvP!g5F(|?GNu;HDMRXb9l}gR7Z-e0 z3LNSUwA;GU&IQZkjMQ&f^YGQIdhHldOpwS9^U$z8v~%tjc+_dswdmh6amlVxv$&@S zi(%2~?P_X0Rvb6^?T+Td+-c57^hw~;Sgm{LKZ|Nulml8IL&#gqV=@8^Ihq+`lXjQ2 zsx0M4-}~wgrVv|8!!#=-h0Pup@p#s;M;#mfKY(ip$`|X;V=>s;32CQ~9)NB^ek%gb zrODoN3u8*C8Zoo%af?BwGy0r6QcZ$*r;_B}G}pPAhH7foEkPEr3uG6KR9drD3Lxzd z)DCTL!l5roSowUtSe4`d3$>aBoZnM*#TSG<%PvMaywS@VO!J$$@(6n7=GvON06jp$ zzt-0PL}*oQ>VnJ<$~q~+g0ZqJhHIXzwEdU*7=kCD9+H|*-5tsU6^PI=jc1^mJJn}C z#G!;iS6A=8S`1V7(m@MoE@!xsiyp|&1ujUOc3q%l;hvRsC@wtmp%=wSV0?)-DVk0K zA#+P_ckiz~A2lE*j$?}P!t~a7yIM=9etuEP=jlYNA({e=laGhYnH~2hHA#7})9ahs z@$Gf1ic3$J4Hb`0O15uXf?N$@|rbF;$2O^>frlh?1Da^QJD_LEC@f%8D!bU`yaJo@^vA1bx z207-Sq@3T|9affGbnMx_bF>Z24W3z9O03Dnf6ri0fVh6tGqA9oyiPCjAR*nDc>2<> zAZVvq`GR1b@YYXwJb*x*gAj`-RT2f~bb|J+T z1g-n5k@QOj&zgq@vL3@Fc-Kojk?fI) zujnFYnIkT>1h!Z?%qwY39d$&LiCIpNpWuRUIPx@#XcoKlkwctqHYA^?d|O%|RBp>3 z9k^uBdZb?t`g|yn2umjL%7KHm`a8`7(J%-1xSLLS>=gqTd75xEIcH@P*HmMx?~Z2mCu{V4UmMDR>jxZZ z9er#Lc6SuM!3O~VV=dm3`#Q-nxi&SjVvsN;8kaQAbjqA|)ki3Tb|E2Ufn&DUrI!K-hp;1wCv!|5iw$Y&{)#837YSop@Ah5z=1~~B zn}F3bx^(6bg1~eO=$|T_K6Cr=Z<)pZ?mHK{Mbw~JW^v)(+f0-Gm)H0vxPmsvU&C(< z=+9a66)vI!=y)4B#9%YpD}uN|dhIo1B3n&hWKL4! z?lle|hTn&8O{&O}p2Qqf8J#Z0MxJhyoRBo|MM07pKxKpCglGJhCPL$Z~4MYq!EZvFGI|CDtoFEh4KO zPjWJ7h6tV+DG!nh*W<`=*$_Cj9&<=8E+0;WTTK@FCJZy)HQ13tWKS49#BG=Yp9Tv; z=%-zw=qcgd{CkTH^|?8FNp}dTnx&VZG3m=32}vqhLbGaBBK142B(9Q6B?3#*vk~9x zQ^{xLip!zbx!t34uFF+Hr>8quohEA+ta_y^;dPfVIN2~(ju&;ENh>y!ezw(x;HriM zadUQuewRG!QOk3%)J(K8vossJ8;4Do1T9>MIsIXnta0@GK87=1U*>{RD{lf$ z%6JgQwZT9g<(rbT zCGd1e7-&>>sGPP$Jj3lKh1tkKzRq%)r&qmjPuS+RvK2hC9^4xn|=k(++Y zX_5D@+_H|K@xb*`V;w=g-Tjrv;Nfp@SgyJY#8xv9bE(#-a>7k|rhDZNE%cVPSobGW687XJRqcv>u{Zu9WjeWalTSe@^tt| zf9lTn#k@ub)~qqkKz)PBC13-E%RlyQ`e&vTT$X7%GT|U(>#2LSfa8To$c_is&gE@S zi2@`#-xbTEV}D#^q!by`J1Fa?ScetANuw+;x44=cp$~XI!7{cm<<~hFc!+VR;&Ze_ zA6jG~Z)h%30&YO)_!OQ#uAd9F+cs_D=mjXLX5pfZ2dU_*l(e}^aF5FCTNAL5_p8Dh zAEY2D#YU%h=oo>ZstN9H|CE(Y&c6fZQY~DGc-0Kg_La0sxVF07)M*V8;fL!KR=r+Q zHrNBq%+g^bwEmHs4m7_G)f+io3v~6>B<=A%hPq%=Cv4xKcV*Gd$qOI(Y`|;I8YA)r z%nOU8;zU@_r<|Vt@K#T>G)~9-{ICQ0dD2X_`l+Rh7%&JoSiEJSR`wJH{9!$I(F)pa&p`!_}2{m^VWH-X@B6P-ibr z+^UmH(GmpV797x7l_Hi)eHCa#*7=(sZ*)zvRn4Z1llXUhxJC?(_ecCdc{pf}cim_- zv=NQ578l2-s;>Y7I?qag%JrYr?F_5wVEXkPEAIa%WM4Rsjy*-MJ`;)*i4K2bZqNOV zg18tTQZNBR<&e8>UVBNI(vJIC{p2jjdAtG9p$`)~57Qd{eC{j#&qZmUpg>#u=mMFk zgx{BGoiL+GjX-aYq@a=fN(HDf46j~aNhvSLIY#KyHQ)1dYH?0>7J>`(17hHkurBPz zw4bUS+-F^fDjF^{=)&MmPGoIdS6B^gmX{G`xlu0_3B1E4n`wNgrBeXD8(n?W=DlFU z6BQ6hBXw```jx* zy|OWr7Jr*`W{MVj`sB_(Ia>lnA``t2uE$eL0imq=Z)5Z3v@<*7hMy7HJ|i#=^HAok zQj}c3_k28Ef>MA?!g{;BEPc~%r0N$I+2ViHt=k8Hoe*mxIuhf$z?QTAEvy7nym! zW8V1N%5WVYzReewn=wfV5>dgw*+O3AXS}AZFBef5)x>J}jnlF+JxbI2NSg54DOY5$ z964Jef#ygZBDhcbV>>QR^srVgmdm&5* z^?0Tgx94#@I~6f!?R#;An;2*9hl#KIEpUz_X&*tbwWY0wO{ATuG3)ROpmbk+l-QCy z{8er%_Ew{!6nI5VMpPh@LesR+O-(+E$f=>%H>Qfe6I}|~mL9be&gn8PnbZP|f7B~4 zv>+ZWpg$M*o#`c7^2R~aEih0JjP7jsT=UOtPCY6nO!Y+z9O_f$JJ1k5(r@9EBWo&F zUY7ksf6C2rP`Dz25Mw~GtUM5GFLIi1p+s`O%wr8F%bYEP=}=S?R;Z7H*EMO*muM@WsKh(vl)Oi?O_~7C}WZ zaAT4to1#qxK)44$wi!H-C=SCNZ#e2ME=-Bd;17=~PamM_YRP;>^Zpt&YOUWr+TO8O zdnRZyo2xOoW^K2uQf-EjB8pNgSv`u~teVVQ9)vT);CVuBBkHYxha097A~Y3JxmF110ZRgFh2`domjKmOJeL+WQd2E(;H~4~+g}NdkgwUA8qpFWVfoVN zi@{_$qj{#zyhtUqIS0T_xFak}P(I1j=aI za0_}EZ37cA^GxDVvOm4Et*PHXOr>h1Gq;aqL}==bG!9HBIJC~iM0ad-5YS`e2E+NC zz_v8cp1fgH=BB1=@;3SSqiJlE(7s;mxQ)gO*m<6uk?EjDmG}470-5~$NNJXMzXT+F za3tggrB_|36+ewZMie&R$iJrX*nwvODl6p41G7sD8@4oJ;MABZ#nQ~Q(Ymec9vttSny9$b8HU{ zUh-TL?eleS_@%78b7CP@~_PM)tn*O>aklfhZql|K5GVdA{&GbAu`?r>;r|C|kFS8;W$1|D{<#{x*7@R|g-*gze+J6$hY(PJ) zSsN$Io`KpA7nh7_APRC2IzUZF#`PXLA!(&c37E>Xzkb{STc&9hMl>rr(*&sfQ-*+^ zj~VxCp#@uY|ItjS7f(FmLS!35O9b89W+?$3%1tE3kA#RN)1@NQPqJ%8#$@A0{)dcH zSA!#2Z6`d60XP|9kFJ&8PDJds@ zMB3Q1<7V`-nbr0k+>gL(uN1Fb$=HE2b{PYS=gAnsBjk?Vv8@)J7Wo)ekc$_ZPc z_D2Q6+npO$NvQVIG{9s?*qP0oqyXQ4q`HuI&rIS0=cw-5?e0cg*Z3NX=lyVoG$kDT z%{8Z0AmFlM{er^kFp=EioV%_H(+QKjj2Gll;eAo1I4`9v1^!NIcqh8r&<^FYgvWAa zCsJ0#06TCds7;&;!tJz)NTJ5+&1JHIHQG63aJ-&uhg!OU9!UR} zuNHs3DBC@4VJ1W^nz(Qg0q@JOGz=?1TuW}WMr&CNmMqsyXh2_&8ZuIMTg$^kjd8rD z3JFD^GQi%O8A9^2+ z=M{78gYTd#!fNz2Lwf;6pj5!Lebg?30xWI(HTlisboAm zw15pEiaR1(?5aV_mAH90gP#Rqb-11=VMpG~HOKle$WLqf{1>1j(pYjza5s~~T4ht$ z?@m4UtM+yGZ@0%P?h~g6BIzgdkoRO`%dLFNdc8N>5mxmI_0Xn$tP-;ObT+5cW3iG;qxABVC7s~~k(KHWVqzKV-?jzlo1bHE&7E1`!6*A_4h zeafVRX9}(?e-A~09~YgwVgMcaRCOu^?W=!I-!Q>wWelc$S|7HBJdIb#E5ll9xA>yE zsdCM!msjR?^yFHtpcTrTer^yccuU7jORwb+V*Z9AST`$N`Y0N5)+FKIrt7DZ*hmdD zPL3HWL7%1D(^OrIO^xrvw@8f~bHS;(>QN8`fK#VHD!(+(AFTgzq6^rO_N|)ztgak1 zg9&g$mOSWtm;F9K%hB`0v`D}vwZo?t_>4$5>k z)Gj}g8$d6)-u>uH4X#7PthW0{up8CMBGGqsZou}EjvZ=wBoLqn$UljA+p)t;4b5XI zD&K30MpW$W-}|*w=pxdm{M#{s=CVlGs9|?24_9BQYWjIp*I-e|MYHcB1#y=^Yq}e- zwkMj8fDCaG94C|cCkrCi##+!GQ*0X>CvR=*6HLIII3ul+KUmVl7Q7KD!sjHu=BPe4 zW{eFm{+!hGX4*NDkNn&9aI2CM!epIJNO$JpskMxL$%;$3iFxcc-@Hz3F#MWgcrJ*a zdwo7uApugK^jldD(shyw;*ym)d6&|~?1^$BA`s#V2p3T)xF;XWn9_7u1{g-JPsdew z2_zV^6Xwl&tmKiX5Mb$T)F`Ou<3!msIx7U99DeB>nBs?FJ#wJaKs+N3p|;>CbaJ~Z zAC#vuf*+^7nb$YYQ$hY4`I8Dt7GC!RaS%Pu@+-(-Y8x|?B~#-b2zqx_Po2BW?F((3 zJj&?*^{18Ka%I)RbztX{10H zpOe|N!*03=nOhQ5Vg0c+A7-MOselY`($xi4gpxdO-htDg2|OYPqlzecJ5KY_OKfC> z>=^lH((Sxg?vDifGn)^I-Oda01csL&0EhhV0-?l9_-HuV{moYc;5fE-RvBEY>X8c< zZQ}^u)fH&U^HL4-uq$0_D7MKyx6JbAONlG792d z>=yGr(K8&iJ6iRy&0QM#^*O=eOkVjb6wDFwP61e=h%fWYt7Y2xP5VX%#Hf$BY-zz- zjn0z;Y|zilO%|57>RZR?`h}n==7LOKik$18{#IYhC%#=yAs#$$2YCmQQ8md!(TT8O zEnSfXHaM=S_A=S#F}$;~NX=$VKH`dM?r!S$ctA#`xdj18u516Bqe7ZpP@irXpjlja zAc(kRIi)~WlcJcsuBMtjg>{4}D1edFvxNh$?qo+h-2;HnL|6oLY6MP3D9tVFF%3=POV~zZE!z*T@pg3_n%YRuLVWAzKnr z#7M_hrpVEq9tsGAb+D`6)RHLBWiELz31?CZ`4I(4pksv|J)~j;z^b{78YdLS)LNn~ zP_}12qQ`k?BETOOVl@)^UJ;h69LHQUz|HxCe4t`kCGk*P7+o6M@veGoDt<16Q)`mP zhaO8Ly_oC$daK;R)kHW94K%-n#`XuM>-VaQR)N@L#xw##g+5vbzhqLt`pS(MeMMIO zfjr8uANz0&n5#SnolhaEf+~aGB8ZWJ6zus~*n!b#h7kFqL$~LCLndSG+y@r3pX!(l zX?AOpT;zDb)s(RC!`#@nMAR$2o9~Rw;ZBXP=ig9`iX1+=I$a)M1aIP~Bf~D{Zh9LK zAQ^nB)$;Ije6c{pIiMZzrCBlSiO6#F5CNy$UQY~G5%N?y`81SCdRO4uC{!5znh(?@ zXR~?7V2)&c^w>F%X>-ynM0e5^ARdV-3<~FU*&Qx!)WD>b8aZ#7ER;3K0$1!uws05N zqJymUhd5he6o-8)SCP07zkv51Q-dm~4d z`ls5D8JS_A+2C;{gz5-t%Hs;aBBYT zwd~gWi4oaT2RklUpHSHdc!8v^hp}C1sl9?RLq){liN^4<>(8ZChPqBNfHq%vFq7vx zEQ0zQgD+#|rJW3T`)zvb&=j>BJ*V#|f=B2K8WK@vq^7QKd$Gul`_tQKA@>p8MJ-;`dVw6iE9W z;Dw(YS!x?oUe?6AV27Gxk&&oE3uR4ap-+%)X{sC4h_N42$sDO-L_8+1hi|bPOt<2S z1YV2v9Bu7-*<&HyDW=%o*)O1~s!6HM=xjQd2P=oXCmLlij*zoU}4q$%)*kscF ztV9j?UH-OLJBUb=O>TS1)j`Ff3#h zdOB;D@~AmQwZJmB-Xcd&Q^KrfpvHEQ`lVxQ-&!~zPMareTWt--$sSwbE8z!&nMns- zIUj8|tzReNgctP;Q)z};4$hbj_)kd0ZE)AAX!-Vg#$q#IG#ax`5&1TM2;KPBtvUY| zwl#nhkkoqOMZ*IpkEpOxAvu`-D`Gcn4YX^8NlIN<4M_2jsQ1prMVWUMZ+DWdKk8%# z=`G3w`W6vZvC1~J$a!qGz^|!Ps`m@KC+?LRafSQb(?N&Q0BErehIJ8G)XaUtQc`EA*lWfi6B`=B_K)kd+Sf8H^FX9G9%DHx?DS#NR#bh67aN* zEe}OphxkOzXK_?x*y)q&q7Y1Z-3MJ#pE%XJ=dS3zHkjRA*l?9%v#)OY z^gMkN_9<(ewO>)}#Z#ii>>{@Qmc@)VYZ<~L8B`p?k!L|&U!hdEh<9hVIYx}E6kaXj zu5oP{t9IliUsbGf{mrgTq(j;dqoV;Kx+ve}1$*l)QhVFC#$;U*ZpQNIVe_Qm;#fdZnvF~6j zQT1tikui!-lg^-Z+(b~deJ%0YNY_mwLh(Ig`#Io#_R?`>%C9sH`>q543FaG_a`&Mv zT0IS(gdi0!WSnUqME05YmssLI<_X>aHF^!ISDI55MckOX2uQ)VrIL^P#HLYs6XW6d zh5lz~<#F0PcO5^b0>4Vk4HDcz^V7^RnL(AwR7)_O;O|q1L;Ct|6;f6mmv|1hYzdP}T}gf`+wcXX{4%LeT6Uhp zTAJGn?bxeTcU6xYLw`kkHzr3(zmYc#8>|ua6S|Y@y{%jt=e1+yIB_A(!VHP}Hq=sD%&LL{!Uj8dgcZeQ0)+KhV;iz-{OAZ_cNs zI!7X>j7+uD^X|r{$v2*fV`a$K?vexudjfGf7Gg3O^>H?Fb-?r-$@l>skPq#DFwjK2 zzzRNc&Ad6m8}?(;x0p_aDqv!-#w*OTRZwxFOE1Inl<+&|DjJ@HcMWIVkF8@yxU!AJ zbKp{{hG_>+Zn81cxN>ykg?J~Rc5KwAMwGLa)A4q1?9|JHq!EsS@YoCJGM5HY^hcC7rU$xu7(7=Y-`<)mo z43ji5`lyxt7g*BTqZY_3vQKga)1jxfUlZI}wX%X+KH87yYsyGRaa4~GNW`ePmuU9Q z0{}LUcn1PY<|3ZC5j(~|aDxfCM_)s8MlQ0I+1Uu16R0HfxDyvnx{@Nb*z10oH+t~U z@T+`z`J>G7?94jTeV|y5Ym(Ru=S#uL2I?H{&f?}BWK~tG+GMhNjlsz^w!i%>t1Q=$ z0h;MEPXC^YH24Om$gj0MZgXr5=Z&&Bs!wfRn&7KHW15G=6d#hdV;;M75M?zq?2quL z)}nj0=1r0W!dS%iI+@Kxw0+jh{Y=_{%QfbCOsa059GPhGO&e?8+wXblbnpsI&V2kSQes?YiT7H2_BHe#X#=piMhb@ znN&AvwK)Q#so2B5J2qxgZb~v`TW+$lr|;1ybqa|8;!E*{M3R7#uum54I5WC}yzRfx zO?>;f*&eiH5=a+b0>ek9cDGN`1ydG0=jpm(4rgd8 zwJzRK^Jk9g7e>)pcZTagtv*YX0_kwf8AQ0}3LZW;l3msaqE_<4uF+@?@o()g`J2uR zOdwH!Ek}#w%Nt1bfn?eENlG|34nDk%i38>6&^D6)gVJhp!rW*=G2DN1YDySd#8d2n zuOG6E-ePT{8({s=Z^!`Ljb`q}&s@r(hhBC2Iz}tRShgrYSctJ<2veC`t`cEqynr-p3hZEc?#N_D^L(e^E){o7U0AR#~nm+ezOdAr&;(MJoijvZrrT zf9FFu{eN8kFI;w4k<%7SLfVhT_p?O?;UwHly9-@b4G?#)o$8tKdetYii+`t?)nFKS z7shPBzFy*fSSb&+(h@hn?prM;%NN*PyHbv=W)EvRjm6M*6<8Vvs0Ylwi3A)hC-53a z=WTAE2iPLej8!ai;o%sO$}-{w+Zm3i+oPPwiPJuQMmDX1R(fLGL}y}bYnzcgz;Bk5 zN9Ie_!=L=m+VE)dAcrt+h|3ji8q#$5<0asTa?~^Ci!)%Ny-A2V%en1H`Gyy{HR#ke z@k#gb$Q@+c#2!l5*7&r(i6cimiaiw)1Xgt2Xo;RA)BfoG8Wd#*7wJ8rFhyD_u>M(~ zv0gET=(0CRJF>FGlU_`qHzra?Cw0CQJvU&o)&-F{uM_@+ySjN1X2G zA(9~r-X;;%)8^Ux#%K@MVx3hFBQMqw|C`8%gx85BUF(U4(Vh_#^c$=(;G>!(=dbmr z;6zuy;7vj?oUqGmTCG+HZs3+$_q?JYWfP8#d`3#;--)~t6d7snY*-c_30~pA;8v&z zRR3gJZ*^Hb87z4`g}@=KCQUZWmSPB`YJ^>|rV;ED^CQUfVbhP@o1Y zJAvD7$yG2{F*PS4jjNZ2Pt9W_~1@IaHDN zAKS?&H|P^B3o9q1s54H_#YaR>N%#yE@vG`We~uOC*XlNm;TBqc%$ct019|294xf1q z;13NG{*W<_<;E;GHjvsGVN;}3T#o=Mq$Z3ZRVN9rIE5wOat72u15aGOrZ#GqNE{|W z891?%e(%1nk2^oWD9IdUqV@PkV)naw*Fd3f_JB|%Sqq0!-h>4qmYi3Ie-exhYI;%x z(^G2LtSia`eJed_9iY!J#ZpRakj}efv@%}=U|i5!`GjsP&lw+avOdyQFwqovhh(+B z_W8Vy2vlySe!iuAyUd+w1G_n}@0-l&E3;i7b~F-HI-^ph%@(~?YxMJCM)^FM^i)=W zxvH*`-0s$anlZ0}cW^xX#7hsPdBd8wj&^{z#tWf2R~2CQ*Y_FYa>h1 zw;n6zGp7EPWY~GZ2yQO`s|Xn{Q+G}5+b5Um%O-!=q&}U)65L|CyDxr7A0V947xzL` z;TCc#V6OvErZQjH1Lu^i{1ey{k%D|?*p%c+WcsYG!|qXoEm|4I%?_`m3QuWO8MUe) zDb~v|AVlgqGbmY3G@%e1m|5J@A83X8-|F*P@uJK6y}iKmt~qkY*E)?4X4Egoc&A}Y zal-?K-#hZFj}J-7k}>dnLU(&f=!&Yv?!9J0cM+g3t=nD=$Mi-&&zkcmIrhgGw9+`> z#K#ZYU(`5ogGfZDb3#G)DYv*<8teK9+(U$At*>63xZXPBFH%x{<*o_yT>3mGZ@>b& zO${e$=fFoFB2*fL_0%;`RFl>k=P4~z>n?r zqi0wRW~Y{~cP!niDb~F8O6C!=9Ws2+Bl&RL~jy*Q06O zp+Id4Eu2VA!e_ToJF=LW|Kf_?fZXC%H~bidB*9UT*9Q~+9!)T?DRlI^-KqU~=)rm9 zhV#o|F4@TVJ8z{EG8P2$ynp!+`gKa?rPKSHKO-s;4e*jRH05_^qhJ?$z`p;#6YCdd zifj(kqF#0{iRN{X%xaT3UT??iZ@A&#u2(1a^i(n(2`8X3@=Ag_boKqE1e5V^#OrBu z4tl6E3}(JWcgfcx#nmz&@VXJ_p9q{#^`!`AqvlJNsr*4Sgq8M*; z?&u>9(h*YQLRfkkysT7;O;szxDXqP?Qqhcc4pI%c7uN#!A${Dbbp=AuFi=xfvQeqR zeo8l@M(@#r2|CK2g3`7KHt&eecZ`!OLbO3L*So(OlS4Lv>IW@Y?TVS`oU3^+ted!% zs9!_~q0);D^Jy*mM*95rh)Uj$1oD`^HI5hE^;EyuLX>Y%>l(nThtf!wush(Ff~`qZuI=iwXM}eU-cGu*0vJ zeE^_Rs-o#y1V(voVU%n_GJ6`cbV2%^gW*aWY^RXRGmiP4>8*R^eC14bfvFz^vrv_p zl`kRgf&TOPJsw|%>+`4q6)ahWHM=w?^4=X5q$$7O!Zr zikQkbj*C3HA%=evg7Ds1YYh1w0O?-=D0G~F4$Ae3KXo#5^5>iKI&Iw($vr!Rk~==Hg4 zKz8nG?hEzD9sT>Woy#FtHEe1|Rum+7Q#fCns_ny6tHmEaQVD zm+0ygCWz#ezBPlsHshD>uepAkJu*~YhHF4ERJeFA%7Z%uZoq3R;)ZL`Nj797yuKK< zKz>uymZkN{Ae#0F(-nwA3%+E;#)OxL>Q;`=j)hNz(>l@{b5OF}lsMf-0@yelJ(q|E zIx~JjCM7J^;Lw3XFORgX#Xp9MojMF7_vT&E9%$fjMNiw5&13q!njYC5?>ueDsHf< zu=D3rSmZtkeJ2Y8r&nxk7c&)4%oH^Nr=JKwRH1teWakKa7t&uPrL{qKm9VwR&g_)$_1YHeh z+?tOpIfL{Wr{v>w)x*arGrAe6GA(S)A`rE0Y^5F2xyF;3vT_}yh)Ov8ZY!v%*fTuy zG@M=Wb&Z2QI->+BS@6IA+m)n)rc+hM&hPBc04%X&nAMbMR!t(G;BrF#aYq%s!zn zTJb}g^W-Af(m-{#_Q`0NK7K`GsO7}|I8^{J&Hx0%T7^yUA=;47^f1+sdVAs%@ZXGx z;!Ct1U3*&&*kICrLL+%#T+CL>mqJ5_9k?Rl%kivcqr{WI&+aOv0AdZYDoQXt0d_Fr zr2X;@_O=1w60!(b*v4TJe3MY9`zr1OMC3L~?+_~WwuU5N=!d}?u}a=}@BmKoesZ2T zPd@Ym(bPal^AH=Kx${JIo#!%66E=gJU!U1i$6SaGH=}U#UfedH*^#c}K*rMnv1#Kz zUV-cCXlo^@OSFk%_!by28n%L#v4}@|LX>+JUVLuTG+7&bzEI($nKK`0Rr+OG(O8vE zqH$RTyW@3s@oU}EJDYJqpHcHcNR~vNLGF|t=(P`bT^ArW2L)x zgd~9WCL>jag%%N^Fr3CbC1AEIe`{DkzkxO{!b?HFT|%uHC1{;5TY zS^r(&`AUNDfxsrs$o+#fGN4b1KLLJvsA>lqEk%FIyPe=)|aVPSme zEhQ}DIq#qV#J6C5zCbx)capzwy+iv?ckj?msc~Zu$(#Z-(NXqdfC8cE3FV0P!zQsO zwQ#FE^2)JFxLWhP9M$P!5*WcSi}3>Dz4*#pPWh(+5@dITl1=7V4rFc^`0Av|0V;L; zr*4VSgC#+%F7pxlO^lGSGC=@AzD>$`+paj?0x|>5J*8ZXl3rB4h~IHfotybavEoZq zgy-u7AE6W$pqQCXCV8=xCwolk;Z_d>Sh{!9kDkfw*_8$bFC=XPXh6GBT2`st1C*)G zpo2;42k8ARwZNXkK$NDeeOC4`NcY5|r3W%5K0v;-rZ8EbHJZqrIs?Zdc%=R`oBD?~ zpK;i#(t%|pL~nOYa$62`L`gkOGmCY2!hm z@r#J03G;Fvv9B>Y`oMqK$9aG>`Jo4HWZH*?kF?dAhV{I+>$ZyKfL6l42x8Xc`Z;kB z3=`|Z_r35vP?QIr@EYuLeek$vCtmpt_;xPX(8W>$As9e8D3PnpqjC^Dc4t;SRZwR( zxHvLu1G!}bJv;xPku*@!rg0=HQMdWITUYWYCOuTGB(}f0*<|~H^dfu8{H)(1o=Mx7 zxeY-o9opm(A{>=PSq7kNy8yuQ;XbV^1hKYgkEMopv-&8dS!aead==9}5Tfz{&YQh& zrwr_u(VL`2-dpPvSUquxk8D={eRB1UUf2daZN+XYgmwbid7c9+?5}M*l4Tbry=tw;L`^GNE;=C)X|BU8w17vgEI(-0 z_r|Mb4v%)@ZH z(GCJa=@P66LnAk7w`+vsz#tXfc*xGtRkZ|dpCX%-T;Z1q=+e;?RH4ot^|F!v01qE{ z9s!FlNTUY@VS4CxCBz>UTi9HZ3w(Cy;GtX$S0~9%UoReh?~YSM)Jqt&cT4-vixz*H z|0U`l9ov|#dAopa1o@~{^w>G}W~|FU5jEnF%`(!^j;Y*XWWOr{`9SWDJ@&Cb5kV8{ ziChzpP9igP?MhccWFAYklnNhtEcWWx?>_YQ3fP)rDV=%z6m`&1fBe(<${)Pp9S`+| z#ABgv1z|2C5~rrVa&EL^?^}&Ahu2S$&{pjfI-u+M7`qN85WogrhX;plOk|}Zk@Xw8 zG#iCbzhXno<06LVw!~}Qen_bBAHq(2Pxy{%4+Yz5v`Vt;ZDjY1?kLvZ^w($_0r<}f z{!Y&iE?_|ANYcO1Bn2gB*;v!wbK4*fq?ULdIalD8sni83&zWO!HxCzq8k=lWNp7qr zemhQH9Q;T_w+U1a8e zvJ!RKu|1buk;1w;?qV*G_8(f$!K5i9S;yy>U=r9C`Q3$$H`022Zkbz-+(u}0As@k>Xm5zmyOMHP!%pwM#h1SrI22!L+%v4i zvX=sIsec`dVXKAKNItn1tdzpc(MHooak=c3yf(Ic48zw6s!!>#EKqCUrpP#nlqYXy z^Td_dXY&s=n#Uc5Qa9OXeS<>?Ynmk)+=kRmLq??jLqxl@I@$S5KU{uY(C=}9+6 zF=3;yZxn*$_8^f|mli-#q1@Vumh#12(dwbNU(4W~TJWg7CROfmztNc~H+YgbPP$ua z+_$b=C}rxZ4)NA`&BL?{(>nlJ@p?`{f$%#qZW#v0?`bphK+!ZL~zn@~7GiI2- zWn$}=tae1#iohE*037{?8K_*bFJQ&7@<~vRuEmm_0BS)(FnMeoPr|1pa*Ox9yYH*- z2R$#yP;6D1&7>ICw$`raFPkH9r(YVHSVHc%8Kj{H{oY(`E1?OMrZ5|pT4;Fv5$=>A zq)c$M<@+hoZI>x$f3gDwN#paNdZZktY;1t4%|t46XnP2|0^CxOokVX|F*Hgw3-Dr2BR73%L2}@iy z7?()`z)y7?(e|0Xdk~KJd3pD012Wet8yg2dHva=er$SOY3#&K>4Wo4J;u>!5DoJRX z{{-F9YG(J!77v2m17CBf*3_)(Cx}1pRxr6H&y0mOM4UF39moq;SksFfMAteSM{>LJ zuCciEs%>ytPeF3%fO*|=SnirX*mppUyqIw2Mj?+DND@$Nx*>slJV2%xc$sJp**lUAb~=GtYEfRm z9;xS=_OFcfN@{@{aJWP+aOSig9NCuasQv*$V#VkFmp0~{_nT({^Pah@<3oQYhyC>< zDe+08;vWdNjKrG98vv>m)qun6D;I|fim7;N#8l4xS(%0dp<=#$nx=+2qlIFIL$H0l zZc>>djre2K%FHN3?qtXhSS0QJ)|M!{a|E&mN}?2{=T7l8pbtb{s=GCjZp2I>lGi6A z+Pl_m2yr>5KwF0qc#owXc1banaSEb*Yvr9!Jqbsk;bOPN9&>hz_d)L3lXq7acJ_U; zS9Zjfl3nGUvn@nY@)@u-?;3;R7##hY=qw4n?(WcELm*u8WHPXX>c8*OgU-+mIyvr! z)9X7FQNS|5E}1u}mh!>x^ANH0(OtSHKxb(u&0B2bSIqZI)*nB7{GXd#wvzeD{rLxXLVAxo&LU0qxN$W>a_omt`uaN<- zVhX7INqzQrtI*lk`Mr<4#BAG&{^XWmk#%|;(74BtX&?J1J;5CSvB(3YX`s%bxY^ki zJ=OjaTXrFVgbkK9Nh)?otgPKQB^{?%ENrV=Epa2epo4NY&t<^duzoQgXdHJ*>Io@< zlwEHwO3^(vA3uRT!8V7a!oD#v*)OD3XB*IUncxU10$J9$`OW=Nh7TQj??91nHD8ACd2s}5@h zjE&oEnBw?pf@0+!)=URx(~Ftn4F_@itUk*$r=1nhIGf)EYb#rQqvws@wksCs4&s(J z8xfRYnpk0DaSYC(W$2Guc$-Ux9T{a>!9tgVJh}Fr>CE=yc`o17?y|cI|GiQZg%Y8P zRE?loC?s!ykX=rw>_K}f3fO;>ZG{v|VH;5Tw;z^@-gpDJIskou1oTmRjE|2v=)FY& zvl&)LDz5;*^@ZW~th6{<5~{?9s zRTEJSIqVw)ZmTjLE+2J})QgtJQNglO#X&;O7W~O$!#2+AX1gSskAKP`+G2CGM-e*j>INDtX6dCs#qu$W7 z4a+B;|IJAv=P&YirC5Ui-R8{nS_d9(lB7e8CF0JII&98q5SB)4*(>sy6)->sYBJd8 z?ds3v{%@@?O&9;fTLlIVJNFJGOBt3`n=aoOteeclAFezmvFN*O|2J7_C0kO;Qo~NxT-Om4+Xqrq3~GS|W`t6-s}oKwiv?P?<&dC~h_KnW8SCj2HnwDQ}iJ zXm)H4STt^b;pr(daXuOeL0z)o20AbFUq>_{xQN?7Rh0do4F^VUwOQy>vk1B}EUc(~ zC`J`D$$k?L*b1^Wq@npWTw5_{L!KqqcGa{CQ9v0`rE3w<&n$@;d%6pj5Ukb>W3B35 z62Py7nrItq3hJ|nfe`^c=qe5$57M`c4NmI0^;N`0ncKD=t^@vSB_dB{d}GBKS&$e8a7q<9vdb|iP7D5Jg=$eE|6#u*-|xNB^O7%iYj#Cb*C{K z^E?9Ph;lN(W%1>Qoi)ddA4vC^KKrdEb_=GAap{1b(9q>AP_HBOF`b6=8>S_`LCb}V z_uWID=!6CD=+Z7_CfgSR=i5r@ZQLmOq?popEn$Z^Wq9QiCM~i=V)q^;o8xACt12U* z#5b{vcL_4qVwJbNHOKQY(YXAGy#ERJg*ta4poL?R77^2SLc*5}TV5T2hufT5x-_fE zmI`pbD$M`6Ow3A|z$Kq2?YIUJqv$lVoRuK7*RhmuHdKH;dV9(n4{XrN>ZewGF*v|U z7mOO7W2dmr0gj2huTQHg`|)6D%^bcl_y*tPn`3V*RooJ|_Y+Bow8%GjD)&6qu)%Lc z7j!tkKqV1~4fw&+SA9@jOob&<-HvuED&@{q_b_+A8$kSLH4D~$8nbm$xw;4_Qt+0{ z)kee9y3KD0BEc@TcyNgLo$G;#-2o-*un%1(=WHC*dt`z)0AVS)mTGc{2w_ovV=6L+WYygEvigNp$^e0Fhi7R3Xz*%@+Z(!uEUdi~1k# zyAfXTzqScHB0J=*nlel`E*wzFW==+OYy^PP`e%?sZ{d%#;_jhW*ASN8?0j1oj#6i4 zGKW1RG)3KvcJ-dLRsR5?j*caJ$1tmnC#E!shnarnJV?Ic6L`trX#xazk7uX~g#McGM$>hWXCF6)Em$$tLs{Xjj*=9{?kFnOMC;s};3*v!j!D{Y z5B!W@zDehr($+$tojz9;ECdFYxOm=0euV0?pjWWe!CjXbk$tA1V}&G};Wn<7Urs|B zy=m~i&SU>?595uH)LUYHn*%y@%kN_%9!RRJu${;t+yl}i7)@PM#6mr_{0l7U1PVrA z&pmBgxZgKJ<=a^M;_&}>9d8@LE`B<;>RV<65}QdE6T6I>`mLclrabmyV6{}9>T@s5 zn;Gbp(66RF$O-yZtBGi9Zc@mpdcH$v7B0zWl&gM!Jfg_}X3VF8{u^7>pIDR*5&H9y zNq~F1i`OTS7c&b!3#kCL$bY++!zb2?z5^37aJ1jecrlEjxd@US%7*1{l*@ z$Oo43J5*!j%<94)A5md4PZBap|b;hR013* zSgtR&!tARYWJAvTOYIJe4bWm!_wf)*nOUGiG_O<2epi^#dp7oloGyz!S21t_8-e1# zXfn}Hj;9wcxUGV7$Z}`aOwr5jhPhXANd6Vpzn%^mkhzEQ{Ek7E&=f(PakKA{R|()p z<87+3Z`0Qj-_>ix)`=FaCb1zkiD@%|0`E}fKq~Y7mEg8X!TNvjH;&+(q$y6btWIBr z@@%lgN$|8=J)w7 zrRPE{si z^6D~tVrDhZvj0c_aB%W!)@h*?y{;0wOsjjKElsmcWBuU78In1Jq~Wa76z3*e$RFgF z_tCRqDzFBlyYwC&3ED8JAYsXgB)m_osV@*yFBSQQ`pU~{2IRR4);ED=e1JZ87VLUpHFw6>tCY7VN5{j$~NXQHuT+qgg z!^uR1t#WqcDExi^F6aGvL6y@KPR))LU(5!ZDoGkm_gEeR|M4kjnB`$ETCq;&oOwqv z4DJFF+0;of#6Cj%|A_HKpA)n+xijn(H^mf^-?q%KZMUk#^f;1sQj#^mD4Bb)YvKqH+6dLdq=E-*|2Ja~MHl1N>;}WCpE$RGObO!X5;=cU?15BHC?s*1zg_qd37kG@evpC> z)HlbwD4!7d8cI{ne#ODtI?E_J2M!XRwkm2|ov-|xZx-4sS+*+DJ&%&O;FNyw6G;3~ zwYu^Hr%dq=y%pX0SleKf7)EO50B8_#z~r4E*;!**W^~cFpuMQczwHd0M*sz+=P7N2 zjbUQ05a;cd;cL8}x1zCu%2*UgA&RJIZ8`h2x|`XR6lT*FfM7CG$tagAAoU$QH@)Ju ziIPn2o%BS(jJ3p;hHcR9(_aBBdxLHjd01n6<>I=gLTf?0R z!+cp_O_)_2)R{~&`gyRD*<<0kX!A^aNk1tVM{)QTuyZzh2ejQk|CWo}5rGZlxkW7H z-Bf@W`(<1)fi{%dKP`jsGYIpM*|abde!I*j2C=W2D;oTfkd_kRpfCPe_b8NS`lObe z-$pyr&frPk40oPeO+GEOIOA~Wt3>0oN|Q5bZh0;?rQ4G_gylyws%&)W6!O&h;zXjS z!VQLdi;9`YbIFqiNYH)HjGKomk~sWdg_M2{UaLT`#5tfJ@0G z2r?tHV`ek6^*^ZaXp{759=G9juU?y(C|9zhw^Dj+nP+f<#-~9T*D4Y2Je)NrmN|2!WP40ii4cB(p5r!< zRENzjeXRcw8lAca8@>yi>ACn9%;fEdOplSwwY03AKr!hGeV+G94O*9dT*T-3dFsVm zcNl38cXTf`e}Dk>s?k@{n?%rOrWu3iet*4_%XeH+y;3Hn<114H?9W4b3(Y@L@@a-n zjXVjbk061W6aS@mZD z*O5RT0*MliK9`K2^Y%I8pM`^{)S|NFHg6>lcA%dZGQG~|;4rbfxifG}fWsI>HKmZ{ z{e4BY_`OMSbkMIlH`Uq-C=ISvC@T&UsIiphqQr7V>;x);7HpafD-Wjk_%=(jZ1irO zh8@FDE(KRfgrOLKiZvPz@HVVTk{$Q(!s7ZH4>)8N(z>llEPNhmajd-5-35@jVusl^ zW|kVOQv(L7)bo(=xjQYpgyLJc@rQrD)<%AS6NP*YJJ?Us?k`k#W~HNu^6d|SXaWCb z=fg)54a0K|g$1 zD5bm>)*f_hbWaTE?f0d{W}emupWZnSN(0R(A`)n`?c5)TxGq^OVIixyw@C~`aTkUR zkH+9S%6S_m8#n+|s~;ss9gQ$6N?xOyCASHpP>fjJ4C{n0QWuEE>N>ulC`mp;;ia|Hvpe`tLv#( zb;Pr7xcUI=>JUT=G&fRIrrvhk8MI%5U3sMMcHgK=2;tQHYbTSthp!bTHK4tGg(TRp z>!+Pq15Qe769m6$CmH29bS&x8uRM z;mZ1-JVZk+W|6hUyjpRvZtonDW`3C-k*QU6SciU`ufpwbw2M`J+DGa6LNbY%iXVT| zIdfv#{ccyCT?eyP5l|M=>{GfF z-sW#1eoe~b9>pVE)nD^D7^zuiARHurM#X>#LpwIiux9ue-mddCZ2Nd1e~8VhWZ-5z zc~~If2;b_TrK{sz^KU*I(_Tx}S-FTcfDI+ML-oap_bH~^G_@eKA(rWY-03Fr%3L~u z^31o%yeXi?zuC&)uLaE8>HUcH0afKmW8$#n0Ho8Yq|f-wl9=3ZWM6+Vf*;{Z!4!H| zwAg*)L=Ml`@@U!=zk^5A8rn849{MYp(<7^JC-`QLo?ktH{c3~`CGuVIsh&WO{;XNG ztFm;cx`ETlRpX_$jZ6q~fV)Bzk{;oLIFqBG%b=DenWC7hXB0Ndo ztXmeh4FO`BH6Uj&!}!%KvRE$y-MU+)wSVJP_&9Ea7YLN$)s;)Yv3w*z`8}iNn*)ny zz<6~jGLGZ?^!sDj^~nU>D!M~0;U#=Y4h9A(3*1rO1@PDtMLO7HgG#>qF(MI~xfjrnoN0C__A2w=Oc^bnO+^1V$>Z~?9^Mg?; zh~Ruxdi9Y@hBM*kvls&;8q(MPQ&;t8*3O%yDi7~k5^Qll2BrJ<$4qSCR%2o*ssoN7 z+BUt~0nC>#K3){|OXT3%Uy0xXvAyV&pe?riJ9D0KyxRvU zzY>u?UB|2GGhOu3-WZ@5%d$2rV>%c)yQ8HYxH=|utZE%Tzt35&(MiQgznl3za8g8m z>oiDq8*bsvVO8_0kG7GVx|u&XFzTW&`NAJm5fsqylIfFi8iZ3C%d3C~H*yGwOmwAF zOGEJe;GNSmH`y_US^P=Kr}co$M%tp=_j^@@*VC3E9Z3;|*P#k8WfmNTOc(JIVkqk6iC+Y+SMF%a|R!!1sSamsaj%-_$lbrPOBK2iOQfN1dX zqxn!2^vAIv90U{=VGLLfekw13NCtO;bLIe zQT*{AygD${sBam#*sK;Im{d{A0S>PS_q@#xU}@v_D0Ea$>tKq-vcxZK9Pf#|uPaZe z+M=?t_k*J0BoL2SCJwna82lrf3?2dY-;bAajO43=o@jmsWU<;lvI%ajGF`FV%@QHA#q`<4Yawtt3LS#IaIoP0+kAo*SZD7bNw7R6a->R|YNX^P)%mjgyhZ7L#wV~6% zuKc-GlI8jc13Tix(3}))R~NuWD!T2ty`vLih2m%d54n+ceq!ZYpW%8Wkbr@oW>qW| z;4%lXKhcF1qLQdHGv|OJ)CINHv56Gzxf@!sv9*K)TJuJH~Y_`_D`;JfY zX@Le1pWwb0QMNEDujPg5$1iNj9^6Y2S$cs7s<{kVrXqY!pIr#O{X64b0sU%QqNA2| zcK$HR8~Hx>&S4YS+l|YzOat4(6j)9#;jA*OG6M$z!I83Drv|F1^}6rJ$13=F2>-${ z|4E&1lT^@R|5Bbi8@AAP=lWuM>}WBb5}}hMJMFoT{e6V0Yfc0i`49ut3{bscDT=kT zRzp%=ZW+dOgdmY6hk3ZW{ex|Z1Sc;g)`YmDD%J;hBB{3ojYjf*vM}=h{F!sLdBEN3 z+q?TveFo4*5o4&|JHhiWM*3fl0Xp(r$CpR$Ao?!aiaC=J6qMia8=HF z%^9aeq}nVTs_iKTw!Q9J8{YgJ z_8zo_V3xRuQ%#F9(SGD3x`x>JpFw&|(h;PQdlFb;DXS004hJIBEO3T&ygpj zrir)~tneQPzvD$AJR70H5MpmR`b?(Fq6)AD+W&V2^>;#2L(FPpH%3v2t$#b=-gt$P z1pK?0qfa9C8hnDlCK01_V+XV2cZVg=6AFpIplUE&73)_8 zHx^V~;nG+vbJYG-E_GoVukjwz*)i|m)ID%+1L{F$Y|Y8LQIc8rcUuv9w0%}O zkm(u6rdpY=9Gd4Q;y%tuo&Q;1oLxuYaK2x0)DNC`aqRw*1nY=Cg_CxSd~WaF=$SJ| z(qZ#GcvL;c`r(g|`jS7d1VpMRB1t*pdS@iERp|yNu1oDH8B5!6EGF-iR~B!qXZzM* z2@%)$`A&wLFqkHg30f9fGQMCPQ~6&X@dRT$3VCb|qjjF^=u7Nj`5mQ-=}FKcpYejA z*LHIxL@4~LgA&dB^kBUgQ}Dnt*+!OY+mSm+?}f3cj+^JSmka^rlhL^Vz`%Oa(ys)pkENk z{N;dJji8tCoa!*>D4UvoB?}nTI7AtY1mf5}fkF#=+`;B}PKoug4^VljyS!{7@Z)3X zZ1{CwMXJRZ);Qmn`{cV>G>+^l$VWLGVhs!95i?~{6t&-ERXXSkIJRqtlUE zBmR0rtct@^sk}TSKUf$4;%Z!eW$5VU%i4bLvL?E>t*(Yj?ZD}Gp7{S9@=g|-qDd7o zO2J%m*EfKQZJzf{0FZV8fEG`9-xHO7TI3TUx~-oigFk+E44>DE5JkI)kD4A%=~BG& zBb});d#EFM7koy(Kh=RAjHh)$Q`r=D?$xEvbbD>YN5*@7`HGLgT;sn~b)>RdeTHZI zoX9B}G%BF`Intc+ff+`^i3I$1vB__Sgn}9bi7J|ta#7^*x6vYXAHW6n?3DD^k2l6vAx@_N7=48paPz=)~mZ`7fg%_EEi-#uC5*E85oAUpXAQnwN$P8v4y= zw_aLipn~g}n(e?IkxGs8$Va(GQ;cX!S-9T43Y8X zoHqtxi*L-C40qYr6cM!N0~iI3A5_mbsRY^57N5buwCfhgLdFfyoaaDR3);Qd&B18X z#pD<^xvnphdqhdEnao1c0>%s6oal|@m&@zp9LBRIWJ!)5JZwVqCPX;NX>?SRcFsMI z;VeI55|SbRXJA++l;>OdI2e;g33jUgS;{P^*u55{^S{e^u)J2f$HziZIk)u|k|`@W z{XC0gSudYujJ5ENzF)7+qV2DoR%C38qA|~7%6&|JH5RtA9+j~`fJgz#Z}=qnb>Kv> zx7R2&MT|GP-WWGf%*cw(b=xXZ&C!TKP-FwF-CebN`Av}nl+>d`cE|CkmX%6lgDz#drJdDKu3ZGV3QBy&eEy!1}8DeZOV zoX}Zj!1c#}psiAy+w$z=DJu}ob4IcuWYY+|^UG3aoA@P%*J3JgSea*)FgqC#>)A<> z&99mJ^eOYEjtMSheF86H;c|*x5$Tj;^oV=0`lM&tOs22*&GUdtKXB`tErg3EQpO?M zAZzGoc|O8J#44An>8 zSiWF$sRK3DJRO{7q@E0P44Heb_`ziHmcB~(07);9tRhwUy^y&2|IgRN3{e*kz@+E7 z#vuYAG{v#x-bMCml)Xf-Gv~pnMve zw3`gB7^-T0l7#J4l>>eTQ($dnS;&7Dqvo|6C~dWS6P2l%l|v}LNcNFIpz<1{-@B9fm*pWfINVFr^gt&l*l%t%mxdAXSLd!m3u>?E+aq&#=#U zom!et9iL&M^zo$C@Ggwu@*q9wijA;ivOE{;A#F=2xQiFvQR|~8z%x`j-;Cl7rxI7} z{5*g6&J;D;teR@%fZM z=@={NsNVi!j>^;FI&WyG$jT>hu2~G@mnvj)x-I?$5qw_!ah9Iz<^Vi+Ib>$Tfnlz} z3Er*Ak3>{`LEkW0p6{TBlLjk7o*SQFIRY-<-{%t5wV8U*b1(Wy;Wt|gPt3w2TI zTo3KkE|n`)@4{f!67kd98{jInB8zfWEm6fW)acIf&VX#tn(Qzp!e*8;LxVz~ePcJ7 z*3EvyG#Z2bO=aWohNljV%BrO8g~sYJV&uJkpW(6d@Ku+04u%NN0?@p&Ecj+RW|L1t z{`_KCG4iXA%p->Mz<3`Ai_!`lCG&6q`%V$6PIaOP1*f3)>S{Ivck4reCQXjjgrQ zxpu$~(c*20rlofrOxx$l{BebMd1*H(@aqIa8((>$oKyMA==re5&l84SA=OFfGK5v{ z=|M=T^)FdCFY+UcxB|5|0_~`( zaiX{}ufBk72SUpsQpsg76@t7-bavU|s7ionRfMg2cwXYo#Bi7LIbwSVMd(27$7QBd zT&5ZZq#8L&(2>E}zQFQ)`Y*D+$f$C)m(ol0_

    qCaZ_BO#EJE}oFo(?Z|w&f0H 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 diff --git a/loongarch_vars.bin b/loongarch_vars.bin deleted file mode 100644 index 65bdb77af90b92dc268c0c5c70c054dee71599f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 389120 zcmeIuze+*@6bInbA98VUkd`K=h`TvRs~}|{)D)pZ4GBR@OHRsd5rT-OqN!Saf#@mf z2?AfC2k2hCx%LF|{e}bQoay(ily|GOxLK=3bfQv?`{XBo8r*dz B3V{Fs diff --git a/qemu-kvm.spec b/qemu-kvm.spec index 651d344..91afbe2 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 @@ -55,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 \ @@ -88,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: 11%{?rcrel}%{anolis_release}%{?dist}.2 +Release: 11%{?rcrel}%{?dist}.5 # 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 @@ -127,8 +122,6 @@ 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 @@ -275,18 +268,93 @@ Patch83: kvm-iotests-108-Fix-when-missing-user_allow_other.patch Patch84: kvm-Revert-redhat-Add-some-devices-for-exporting-upstrea.patch # For bz#2082622 - CVE-2021-4206 virt:rhel/qemu-kvm: QEMU: QXL: integer overflow in cursor_alloc() can lead to heap buffer overflow [rhel-8.6.0.z] Patch85: kvm-ui-cursor-fix-integer-overflow-in-cursor_alloc-CVE-2.patch -Patch86: 0001-Add-Acpi-support.patch -Patch87: 0002-Support-rtc.patch -Patch88: 0003-Add-loongarch-machine.patch -Patch89: 0004-Add-target-loongarch64.patch -Patch90: 0005-Add-linux-headers-and-linux-user.patch -Patch91: 0006-Add-disas-gdb.patch -Patch92: 0007-Modify-kvm-cpu-vga-qapi.patch -Patch93: 0008-Modify-compile-script.patch -Patch94: 0009-Add-loongarch64-rh-devices.mak.patch - +# For bz#2095794 - PXE boot crash qemu when using multiqueue vDPA [rhel-8.6.0.z] +Patch86: kvm-virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch +# For bz#2095794 - PXE boot crash qemu when using multiqueue vDPA [rhel-8.6.0.z] +Patch87: kvm-virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch +# For bz#2095794 - PXE boot crash qemu when using multiqueue vDPA [rhel-8.6.0.z] +Patch88: kvm-vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch +# For bz#2095794 - PXE boot crash qemu when using multiqueue vDPA [rhel-8.6.0.z] +Patch89: kvm-vhost-net-fix-improper-cleanup-in-vhost_net_start.patch +# For bz#2095794 - PXE boot crash qemu when using multiqueue vDPA [rhel-8.6.0.z] +Patch90: kvm-vhost-vdpa-backend-feature-should-set-only-once.patch +# For bz#2095794 - PXE boot crash qemu when using multiqueue vDPA [rhel-8.6.0.z] +Patch91: kvm-vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch +# For bz#2095794 - PXE boot crash qemu when using multiqueue vDPA [rhel-8.6.0.z] +Patch92: kvm-virtio-net-don-t-handle-mq-request-in-userspace-hand.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch93: kvm-migration-Never-call-twice-qemu_target_page_size.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch94: kvm-multifd-Rename-used-field-to-num.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch95: kvm-multifd-Add-missing-documention.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch96: kvm-multifd-The-variable-is-only-used-inside-the-loop.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch97: kvm-multifd-remove-used-parameter-from-send_prepare-meth.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch98: kvm-multifd-remove-used-parameter-from-send_recv_pages-m.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch99: kvm-multifd-Fill-offset-and-block-for-reception.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch100: kvm-multifd-Make-zstd-compression-method-not-use-iovs.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch101: kvm-multifd-Make-zlib-compression-method-not-use-iovs.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch102: kvm-migration-All-this-fields-are-unsigned.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch103: kvm-multifd-Move-iov-from-pages-to-params.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch104: kvm-multifd-Make-zlib-use-iov-s.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch105: kvm-multifd-Make-zstd-use-iov-s.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch106: kvm-multifd-Remove-send_write-method.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch107: kvm-multifd-Use-a-single-writev-on-the-send-side.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch108: kvm-multifd-Use-normal-pages-array-on-the-send-side.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch109: kvm-QIOChannel-Add-flags-on-io_writev-and-introduce-io_f.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch110: kvm-QIOChannelSocket-Implement-io_writev-zero-copy-flag-.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch111: kvm-migration-Add-zero-copy-send-parameter-for-QMP-HMP-f.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch112: kvm-migration-Add-migrate_use_tls-helper.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch113: kvm-multifd-multifd_send_sync_main-now-returns-negative-.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch114: kvm-multifd-Send-header-packet-without-flags-if-zero-cop.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch115: kvm-multifd-Implement-zero-copy-write-in-multifd-migrati.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch116: kvm-QIOChannelSocket-Introduce-assert-and-reduce-ifdefs-.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch117: kvm-QIOChannelSocket-Fix-zero-copy-send-so-socket-flush-.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch118: kvm-migration-Change-zero_copy_send-from-migration-param.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch119: kvm-migration-Introduce-ram_transferred_add.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch120: kvm-migration-Tally-pre-copy-downtime-and-post-copy-byte.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch121: kvm-QIOChannelSocket-Fix-zero-copy-flush-returning-code-.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch122: kvm-Add-dirty-sync-missed-zero-copy-migration-stat.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch123: kvm-migration-multifd-Report-to-user-when-zerocopy-not-w.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch124: kvm-migration-Avoid-false-positive-on-non-supported-scen.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch125: kvm-migration-add-remaining-params-has_-true-in-migratio.patch +# For bz#2117252 - Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z] +Patch126: kvm-QIOChannelSocket-Add-support-for-MSG_ZEROCOPY-IPV6.patch +# For bz#2109570 - Stalled IO Operations in VM [rhel-8.6.0.z] +Patch127: kvm-linux-aio-fix-unbalanced-plugged-counter-in-laio_io_.patch +# For bz#2109570 - Stalled IO Operations in VM [rhel-8.6.0.z] +Patch128: kvm-linux-aio-explain-why-max-batch-is-checked-in-laio_i.patch -Patch1000: kvm-virtiofsd-Adjust-limit-for-minor-version.patch BuildRequires: wget BuildRequires: rpm-build @@ -476,7 +544,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 @@ -615,9 +683,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} cp -f %{SOURCE37} tests/data/acpi/pc/SSDT.dimmpxm @@ -1086,8 +1151,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 @@ -1103,11 +1166,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 @@ -1209,12 +1267,10 @@ rm -rf $RPM_BUILD_ROOT%{qemudocdir}/specs popd %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 @@ -1335,10 +1391,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 @@ -1360,7 +1412,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 @@ -1453,7 +1505,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 @@ -1471,11 +1523,60 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %changelog -* Thu Aug 25 2022 xianglai li - 6.2.0-11.0.2.2 -- Add loongarch support - -* Fri Aug 05 2022 Jacob Wang - 6.2.0-11.0.1.2 -- Adjust limit for virtiofsd minor version +* Mon Aug 29 2022 Jon Maloy - 6.2.0-11.el8_6.5 +- kvm-linux-aio-fix-unbalanced-plugged-counter-in-laio_io_.patch [bz#2109570] +- kvm-linux-aio-explain-why-max-batch-is-checked-in-laio_i.patch [bz#2109570] +- Resolves: bz#2109570 + (Stalled IO Operations in VM [rhel-8.6.0.z]) + +* Tue Aug 16 2022 Jon Maloy - 6.2.0-11.el8_6.4 +- kvm-migration-Never-call-twice-qemu_target_page_size.patch [bz#2117252] +- kvm-multifd-Rename-used-field-to-num.patch [bz#2117252] +- kvm-multifd-Add-missing-documention.patch [bz#2117252] +- kvm-multifd-The-variable-is-only-used-inside-the-loop.patch [bz#2117252] +- kvm-multifd-remove-used-parameter-from-send_prepare-meth.patch [bz#2117252] +- kvm-multifd-remove-used-parameter-from-send_recv_pages-m.patch [bz#2117252] +- kvm-multifd-Fill-offset-and-block-for-reception.patch [bz#2117252] +- kvm-multifd-Make-zstd-compression-method-not-use-iovs.patch [bz#2117252] +- kvm-multifd-Make-zlib-compression-method-not-use-iovs.patch [bz#2117252] +- kvm-migration-All-this-fields-are-unsigned.patch [bz#2117252] +- kvm-multifd-Move-iov-from-pages-to-params.patch [bz#2117252] +- kvm-multifd-Make-zlib-use-iov-s.patch [bz#2117252] +- kvm-multifd-Make-zstd-use-iov-s.patch [bz#2117252] +- kvm-multifd-Remove-send_write-method.patch [bz#2117252] +- kvm-multifd-Use-a-single-writev-on-the-send-side.patch [bz#2117252] +- kvm-multifd-Use-normal-pages-array-on-the-send-side.patch [bz#2117252] +- kvm-QIOChannel-Add-flags-on-io_writev-and-introduce-io_f.patch [bz#2117252] +- kvm-QIOChannelSocket-Implement-io_writev-zero-copy-flag-.patch [bz#2117252] +- kvm-migration-Add-zero-copy-send-parameter-for-QMP-HMP-f.patch [bz#2117252] +- kvm-migration-Add-migrate_use_tls-helper.patch [bz#2117252] +- kvm-multifd-multifd_send_sync_main-now-returns-negative-.patch [bz#2117252] +- kvm-multifd-Send-header-packet-without-flags-if-zero-cop.patch [bz#2117252] +- kvm-multifd-Implement-zero-copy-write-in-multifd-migrati.patch [bz#2117252] +- kvm-QIOChannelSocket-Introduce-assert-and-reduce-ifdefs-.patch [bz#2117252] +- kvm-QIOChannelSocket-Fix-zero-copy-send-so-socket-flush-.patch [bz#2117252] +- kvm-migration-Change-zero_copy_send-from-migration-param.patch [bz#2117252] +- kvm-migration-Introduce-ram_transferred_add.patch [bz#2117252] +- kvm-migration-Tally-pre-copy-downtime-and-post-copy-byte.patch [bz#2117252] +- kvm-QIOChannelSocket-Fix-zero-copy-flush-returning-code-.patch [bz#2117252] +- kvm-Add-dirty-sync-missed-zero-copy-migration-stat.patch [bz#2117252] +- kvm-migration-multifd-Report-to-user-when-zerocopy-not-w.patch [bz#2117252] +- kvm-migration-Avoid-false-positive-on-non-supported-scen.patch [bz#2117252] +- kvm-migration-add-remaining-params-has_-true-in-migratio.patch [bz#2117252] +- kvm-QIOChannelSocket-Add-support-for-MSG_ZEROCOPY-IPV6.patch [bz#2117252] +- Resolves: bz#2117252 + (Pull MSG_ZEROCOPY on QEMU Live Migration Patches into RHEL 8 [rhel-8.6.0.z]) + +* Mon Aug 08 2022 Miroslav Rezanina - 6.2.0-11.el8_6.3 +- kvm-virtio-net-setup-vhost_dev-and-notifiers-for-cvq-onl.patch [bz#2095794] +- kvm-virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch [bz#2095794] +- kvm-vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch [bz#2095794] +- kvm-vhost-net-fix-improper-cleanup-in-vhost_net_start.patch [bz#2095794] +- kvm-vhost-vdpa-backend-feature-should-set-only-once.patch [bz#2095794] +- kvm-vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch [bz#2095794] +- kvm-virtio-net-don-t-handle-mq-request-in-userspace-hand.patch [bz#2095794] +- Resolves: bz#2095794 + (PXE boot crash qemu when using multiqueue vDPA [rhel-8.6.0.z]) * Wed Jun 15 2022 Jon Maloy - 6.2.0-11.el8_6.2 - kvm-Revert-redhat-Add-some-devices-for-exporting-upstrea.patch [bz#2077928] -- Gitee From c8384ea0edbc2379ec92701a5a8b45bfecadb4e5 Mon Sep 17 00:00:00 2001 From: Jacob Wang Date: Sun, 1 Aug 2021 13:37:55 +0800 Subject: [PATCH 2/3] Adjust to support virtiofsd minor > 27 Signed-off-by: Jacob Wang --- ...iofsd-Adjust-limit-for-minor-version.patch | 41 +++++++++++++++++++ qemu-kvm.spec | 8 +++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 kvm-virtiofsd-Adjust-limit-for-minor-version.patch diff --git a/kvm-virtiofsd-Adjust-limit-for-minor-version.patch b/kvm-virtiofsd-Adjust-limit-for-minor-version.patch new file mode 100644 index 0000000..30ec553 --- /dev/null +++ b/kvm-virtiofsd-Adjust-limit-for-minor-version.patch @@ -0,0 +1,41 @@ +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/qemu-kvm.spec b/qemu-kvm.spec index 91afbe2..a7ce6fa 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -1,3 +1,4 @@ +%define anolis_release .0.1 %global SLOF_gittagdate 20191022 %global SLOF_gittagcommit 899d9883 @@ -83,7 +84,7 @@ Obsoletes: %1-rhev <= %{epoch}:%{version}-%{release} Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm Version: 6.2.0 -Release: 11%{?rcrel}%{?dist}.5 +Release: 11%{?rcrel}%{anolis_release}%{?dist}.5 # 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 @@ -356,6 +357,8 @@ Patch127: kvm-linux-aio-fix-unbalanced-plugged-counter-in-laio_io_.patch Patch128: kvm-linux-aio-explain-why-max-batch-is-checked-in-laio_i.patch +Patch1000: kvm-virtiofsd-Adjust-limit-for-minor-version.patch + BuildRequires: wget BuildRequires: rpm-build BuildRequires: ninja-build @@ -1523,6 +1526,9 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %changelog +* Thu Sep 15 2022 Jacob Wang - 6.2.0-11.0.1.5 +- Adjust limit for virtiofsd minor version + * Mon Aug 29 2022 Jon Maloy - 6.2.0-11.el8_6.5 - kvm-linux-aio-fix-unbalanced-plugged-counter-in-laio_io_.patch [bz#2109570] - kvm-linux-aio-explain-why-max-batch-is-checked-in-laio_i.patch [bz#2109570] -- Gitee From 51eb4fe223ab3cff0f1a2ad4f099e89638042d8b Mon Sep 17 00:00:00 2001 From: lixianglai Date: Thu, 25 Aug 2022 05:55:22 -0400 Subject: [PATCH 3/3] Support loongarch. Signed-off-by: lixianglai --- 0001-Add-Acpi-support.patch | 1348 ++ 0002-Support-rtc.patch | 370 + 0003-Add-loongarch-machine.patch | 5752 +++++++ 0004-Add-target-loongarch64.patch | 15918 ++++++++++++++++++ 0005-Add-linux-headers-and-linux-user.patch | 1663 ++ 0006-Add-disas-gdb.patch | 3183 ++++ 0007-Modify-kvm-cpu-vga-qapi.patch | 480 + 0008-Modify-compile-script.patch | 36 + 0009-Add-loongarch64-rh-devices.mak.patch | 3227 ++++ loongarch_bios.bin | Bin 0 -> 4190208 bytes loongarch_vars.bin | Bin 0 -> 389120 bytes qemu-kvm.spec | 47 +- 12 files changed, 32017 insertions(+), 7 deletions(-) create mode 100644 0001-Add-Acpi-support.patch create mode 100644 0002-Support-rtc.patch create mode 100644 0003-Add-loongarch-machine.patch create mode 100644 0004-Add-target-loongarch64.patch create mode 100644 0005-Add-linux-headers-and-linux-user.patch create mode 100644 0006-Add-disas-gdb.patch create mode 100644 0007-Modify-kvm-cpu-vga-qapi.patch create mode 100644 0008-Modify-compile-script.patch create mode 100644 0009-Add-loongarch64-rh-devices.mak.patch create mode 100644 loongarch_bios.bin create mode 100644 loongarch_vars.bin diff --git a/0001-Add-Acpi-support.patch b/0001-Add-Acpi-support.patch new file mode 100644 index 0000000..5b1561c --- /dev/null +++ b/0001-Add-Acpi-support.patch @@ -0,0 +1,1348 @@ +From 612826687e639d007e4270b01a61f34f7fc1f813 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Fri, 19 Aug 2022 23:11:23 -0400 +Subject: [PATCH 1/8] 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 622b0b50b7..2f2fb33a7b 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 0000000000..35d4a75266 +--- /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 0000000000..2de50ccb9c +--- /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 adf6347bc4..5fe4cfa4f1 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 0000000000..4401515c7b +--- /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.27.0 + diff --git a/0002-Support-rtc.patch b/0002-Support-rtc.patch new file mode 100644 index 0000000..082fcdf --- /dev/null +++ b/0002-Support-rtc.patch @@ -0,0 +1,370 @@ +From befa5ef7576fdbe2e729203538b066e5f87c3b8f Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Fri, 19 Aug 2022 23:15:49 -0400 +Subject: [PATCH 2/8] 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 010be7ed1f..b395c72d7d 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 0000000000..756f2fc9ce +--- /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 03092e2ceb..e841a2f6ee 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.27.0 + diff --git a/0003-Add-loongarch-machine.patch b/0003-Add-loongarch-machine.patch new file mode 100644 index 0000000..c1617ba --- /dev/null +++ b/0003-Add-loongarch-machine.patch @@ -0,0 +1,5752 @@ +From 2562504ad867de4a0539c261983c08cd5108bfe4 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Fri, 19 Aug 2022 23:39:00 -0400 +Subject: [PATCH 3/8] 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 0000000000..3fe2677fda +--- /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 0000000000..6ba637be53 +--- /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 0000000000..a914268bbe +--- /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 0000000000..d6ba2a2cec +--- /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 0000000000..3de0ed88da +--- /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 0000000000..14521c2d5c +--- /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 0000000000..ade182abcc +--- /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 0000000000..3db269274f +--- /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 0000000000..7bce957124 +--- /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 0000000000..ca073a19cf +--- /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 0000000000..5a500fbd5a +--- /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 0000000000..81ee99a028 +--- /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 0000000000..3677303bfa +--- /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 0000000000..c05ae7a7fc +--- /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 0000000000..0886ed52af +--- /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 0000000000..686af763a0 +--- /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.27.0 + diff --git a/0004-Add-target-loongarch64.patch b/0004-Add-target-loongarch64.patch new file mode 100644 index 0000000..38e74c2 --- /dev/null +++ b/0004-Add-target-loongarch64.patch @@ -0,0 +1,15918 @@ +From 441bbe9ec5021bf56a929134a71cd85815ec3956 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Fri, 19 Aug 2022 23:44:33 -0400 +Subject: [PATCH 4/8] Add target/loongarch64. + +Change-Id: Idd3ed114968c4a1f1be5fe19dc279028775eb89d +Signed-off-by: lixianglai +--- + target/Kconfig | 1 + + target/loongarch64/Kconfig | 2 + + target/loongarch64/arch_dump.c | 175 ++ + 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, 15657 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 ae7f24fc66..50b46d0487 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 0000000000..46b26b1a85 +--- /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 0000000000..9fb43b33d2 +--- /dev/null ++++ b/target/loongarch64/arch_dump.c +@@ -0,0 +1,175 @@ ++/* 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, void *opaque) ++{ ++ struct loongarch_note note; ++ CPULOONGARCHState *env = &LOONGARCH_CPU(cs)->env; ++ DumpState *s = opaque; ++ 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 0000000000..e549bb46b6 +--- /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 0000000000..24ca458af0 +--- /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 0000000000..ee9c1de571 +--- /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 0000000000..a4535d34a6 +--- /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 0000000000..10facb3b73 +--- /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 0000000000..182e59e925 +--- /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 0000000000..795458205b +--- /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 0000000000..42d7f05ca2 +--- /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 0000000000..b6898c2e91 +--- /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 0000000000..4013178f45 +--- /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 0000000000..841240e57b +--- /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 0000000000..ff2026ed82 +--- /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 0000000000..f194f70116 +--- /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 0000000000..6e85847f8a +--- /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 0000000000..79a70e9d26 +--- /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, void *opaque); ++ ++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 0000000000..404a605eb6 +--- /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 0000000000..a56026d10c +--- /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 0000000000..d3a61cf255 +--- /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 0000000000..b69bca6a9b +--- /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 0000000000..6badf4484e +--- /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 0000000000..9a34c0d25e +--- /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 0000000000..b86fecf899 +--- /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 0000000000..f5e68349a9 +--- /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 0000000000..e0bca4f82e +--- /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 0000000000..e50670be47 +--- /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 0000000000..fe122e4c31 +--- /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 2f6940255e..ac0ce618b7 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.27.0 + diff --git a/0005-Add-linux-headers-and-linux-user.patch b/0005-Add-linux-headers-and-linux-user.patch new file mode 100644 index 0000000..93ba8ed --- /dev/null +++ b/0005-Add-linux-headers-and-linux-user.patch @@ -0,0 +1,1663 @@ +From 0d21e423fc15e8e2e2fdc910a7e94e051427f230 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Fri, 19 Aug 2022 23:47:06 -0400 +Subject: [PATCH 5/8] 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 0000000000..5c2c8779a6 +--- /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 0000000000..a24375ee59 +--- /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 0000000000..b809608349 +--- /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 0000000000..2a6014562a +--- /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 0000000000..6d4093e1d7 +--- /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 0000000000..c4c0b4d701 +--- /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 0000000000..6fe6852758 +--- /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 0000000000..0e4c8f012d +--- /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 0000000000..a30aca8d8e +--- /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 0000000000..0f6845737f +--- /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 0000000000..6c153d12c4 +--- /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 0000000000..a3d7b46062 +--- /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 0000000000..e418c8e8f5 +--- /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 0000000000..280acd0971 +--- /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 0000000000..cb77f07080 +--- /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 0000000000..6c613a1973 +--- /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.27.0 + diff --git a/0006-Add-disas-gdb.patch b/0006-Add-disas-gdb.patch new file mode 100644 index 0000000..00d9b5e --- /dev/null +++ b/0006-Add-disas-gdb.patch @@ -0,0 +1,3183 @@ +From 0789663b3a2ad105a209c7aa36d102a5b05f1397 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Fri, 19 Aug 2022 23:51:12 -0400 +Subject: [PATCH 6/8] 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 0000000000..fcb7e45dd2 +--- /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 0000000000..dc5ab39661 +--- /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 0000000000..14dd131e2e +--- /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 449f99e1de..06a69d9d72 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 0000000000..04891e023f +--- /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 0000000000..6308fb6ecb +--- /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 0000000000..a5b4d80e6c +--- /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 0000000000..74ab55a015 +--- /dev/null ++++ b/gdb-xml/loongarch-fpu64.xml +@@ -0,0 +1,57 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +-- +2.27.0 + diff --git a/0007-Modify-kvm-cpu-vga-qapi.patch b/0007-Modify-kvm-cpu-vga-qapi.patch new file mode 100644 index 0000000..72fe897 --- /dev/null +++ b/0007-Modify-kvm-cpu-vga-qapi.patch @@ -0,0 +1,480 @@ +From 6e52e755bd54efb15afa052dac6dd0c7f696e366 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Sat, 20 Aug 2022 02:18:41 -0400 +Subject: [PATCH 7/8] 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/loongarch_bios.bin | Bin 0 -> 4190208 bytes + pc-bios/meson.build | 1 + + qapi/machine-target.json | 6 ++-- + qapi/machine.json | 2 +- + qapi/misc-target.json | 1 + + 21 files changed, 138 insertions(+), 18 deletions(-) + create mode 100644 pc-bios/loongarch_bios.bin + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index b20903ea30..cd73fab65b 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 14521c2d5c..60daafd6e1 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 3db269274f..3194a822cc 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 b3366c888e..f224f8ad28 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 08e1beec85..95b93f1002 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 811bf4a1cb..66030f4906 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 0886ed52af..62e2830e27 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 60718fc342..903475bb21 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 70c579560a..62d1a4b92d 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 bcaf66cc4d..20b90426f5 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2002,6 +2002,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) + + #endif /* __LINUX_KVM_H */ +diff --git a/linux-user/elfload.c b/linux-user/elfload.c +index 767f54c76d..9fb632780a 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 bf62c13e37..195f9e83ac 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 5c713fa8ab..66ddb25d1c 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 f1cfcc8104..729131ecd0 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 0b13975937..7e2915d53e 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 5f6ba86dbb..fc2dc58f33 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 b40ff3f2bd..a09ca4d03c 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 f5ec4bc172..682dc86b42 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 a9f33d0f27..cd47b8d6bc 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 4bc45d2474..63cebef573 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.27.0 + diff --git a/0008-Modify-compile-script.patch b/0008-Modify-compile-script.patch new file mode 100644 index 0000000..87054ee --- /dev/null +++ b/0008-Modify-compile-script.patch @@ -0,0 +1,36 @@ +From b051f9fdabc2cd49c1c80ef50bbee276b6946609 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Mon, 22 Aug 2022 08:22:03 -0400 +Subject: [PATCH 08/10] 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 fc2dc58f33..c0fb5788f7 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.27.0 + diff --git a/0009-Add-loongarch64-rh-devices.mak.patch b/0009-Add-loongarch64-rh-devices.mak.patch new file mode 100644 index 0000000..ef7533d --- /dev/null +++ b/0009-Add-loongarch64-rh-devices.mak.patch @@ -0,0 +1,3227 @@ +From d2163a939cd14d3d9a8a4afb9d9eacbb71b61517 Mon Sep 17 00:00:00 2001 +From: lixianglai +Date: Wed, 24 Aug 2022 22:56:29 -0400 +Subject: [PATCH 09/10] 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 0000000000..e7b5bdc8e9 +--- /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 48c21775f3..1f932f7eeb 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 c0fb5788f7..c5fdb78569 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 a09ca4d03c..60009bd89e 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 0000000000..d162571856 +--- /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 0000000000..349c672687 +--- /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 0000000000..c3986a4fd4 +--- /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 0000000000..9b53549edb +--- /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 0000000000..d58a6162f2 +--- /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.27.0 + diff --git a/loongarch_bios.bin b/loongarch_bios.bin new file mode 100644 index 0000000000000000000000000000000000000000..3aa4f36a853b0d605d6a6dd61d933fa43084c580 GIT binary patch literal 4190208 zcmeEvdwdk-x&O1X31GW{jRXk_x@drzZK6=61*`3Zgo8Z?D|UODRO4Y|5(s4x+uCy1 z0XCp@6TnNkYBor)_GAOzs(5K;0|Y!x0@Txr)s{s;+S72;)_{=A@B6&7v&pWB`s=5E zPClQ>?9RNG=l#CV?S0%xU?IMqJ(1c;+O4FPn zhsT*q1JYcD{5i*&n}*Ne5%GCErMcXiQ*%&S2J%oEeJ^*sE;S%8o=tb@E07myG)fC~ z-R2Cg9Y(=1RFa#2*JnEJK$e$I; zM9JDM1AwHn;gVYh)c(UL;57VMq@AES8%D%GBVR+tEd!Q2hLLzzXMSI4eUF;oSKvFB zt)XlWc)g6er3HFaSs0EgZ-JI`X;W!{a~P!^aZ_n5sw~o?%82!Da6jZD_Jk8saM@_k z&2qx&#^5?84eRrLIm#3H#y2MA)5cR_z!R0zFE&Y>rt>*Bb$*aZ3p`Opq^E|Y^q@lq zjWTGIL64lqm{GID^q(>uSyhj@X~>x-sr_t|vkHP4bm>y)wJfUoHU+93l(TL50*dU) zqVQx=gX`S1Z9G+0XOMUM?~R!;Hx;@ZH0~J6ar=(Kx)5 zkxwqu%yLA&Tg-gr;5*|$cahd=%r@RJd}V5vR2ptp7HG{%kZ3H|Q-ON?Xs5B#C`wmX zNadhM@WZ{yd{>To@y_Ixwa+E-N;&v7kx$*3{0{k!Tf7=hey0th@))-v+$@78xlA|t zi?QG~Gae!2UmvHF`8Gf_&iIB=g!@>QfiX~l_4mFnbzF_K%XPV9imot5%b^oQJHnA9 zdQ$N!(;$m#R7pqKTn}Sg>W|BWCm92mXSo#csEW`@M_+ZiAeW*~!SDPz1M(Viyyncn z=Lq^b;-ImCFz8C3O7k>bnWuxcn65;gbrWP!=~$u515h8=otCCa^C&9X9Pr0+o{@|f z`am*HbQgg>^m!D09u>SJ=sCM1L63&EhqFl)&zC=$^qgfSg!=T6q*i59vDud7G(qqU zr(@d0`^=}4$_Ql*qv}zrGkk~&2anXGmNzI+RYCz5(htG+#__I6HRDH43XRsK_MMq@ z>Z~!hHD*YmjHwh#hn~pDr?orX)G|_a4*9j4+6GYx*VhPK8eeu(yMw$Dq&wvx#dzQF zZ7XpE+K{$pgPR&~g~yP(_QgzE13If7%cL{V^DQrAQUx@D=^^Tqd>V#_2;}Fy>5KBQUSV_tp+$Cga9w zjgJgp+q0PzLEFI7BHc;u8|dsZ6?zN2y-3xS#U5QL4eQE6KX@MfwGnw)$NUkORtKFA z-l*D0fmU6m!!ebzuOCKx!nj{CjIxK~avq^{O_S1K--PVWNS56+q{+p*>tH9D?}F$z z=CPBYt?eJi+>ZBp@mNJ3bzZ4D*Z;{)>#L~*bjdl$3tDB+Cxc!Y^g`#DdNXf`>g2MU z4jI#2=9|2OW7x!~D?zteGzc{~CP3 zw0sC!z!!qwkLOb7VAW|XFnpVU8$UDV1G~7+XI&T9ai)G%liLj)EwkQYeP`)>sjbX2&}00phE#8a{j`bCI74{emO&+)&8lm$t$0s2-tugOJs2up6w~MS0NI)m&cwVorDva@GE-P zy%zaDv;K*we>CNAJ>k9Zdrxk(F{da0&|7K!tlHWccyd+N&Ih+=t-ITwRgHI9gEZ;%#C4MU->anwH$Ega zg2p!|P-OxuQP+beZD);{)m5nPDC*l~)@M9w_!=`P=YR951hnPo@b?;rQO;o0*A9LD zJGAe%E2((KrBrhD$VRk^FetKMC8Zk2m=$?6AJ zhga`eeQb5f&%gKZ(uW^=_@+>>=7pO7t@(RR<&JxIEZmV?R_Zs5_lNnY0^^ojsg&l> zJxBn)#N!EcEgbt#M-KjFLw>s;8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u z8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u z8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u z8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u z8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u z8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u z8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u z8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u z8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u8vz>u z8vz>u8vz>u8vz>u8vz>u8vz>u8vz@Ee<1>t^0)AKD0K7BN8Yw^;zOlXyYt>8N)st& z{@eF&F}erREhK;7Cz4dcpPT=gf2kz>{a0rwm*`yZhgI{J{rUXAKl;=SU-`~&|Lt#C zNX}`$)H?Nw9}fHZlpS|}d)2Ms4?cMLSCUAN_akomFWn$yA&s8IcR+K~6C@s7dtb%E`|v_vA5Ry*_b${!-nTwwtdN}D>nQBO-VO3M zFN3y`p*md(t#eZv(go>3Ct$uTh_(dRWm1{0OCGeTO#hp-fc{rm7<*G$9DY+N_5820 zNPkmVqP?js^}nesQ{PnX_q?fW04}fKdJC6+IIS=}yiO|jN2Q}ogQqTuhSuM$$_nNG zUK$WvDUET^$oidcOXZ$DQotWoM0(nqlsp#kMEq5$PSZiS!$h9)fXM zx!SDc%+95t`!n*L?Wt!o@;wQ<%e7`@sq+Zk{Lv`d23q^7b5EJB+^;pu+lKUA_MVlx z@&w*xq-oNw-w&uvi)m8MqoevPt32GS^jA-LtXT;Tjn_fR?JoBpQpyK{AL$4MDbFlB zHH~^mIS$MjZ_$pmE0eH`-9Mnv0lY`+$+Dy6k~$EyvwR7j(B3fnl+$X-Y5UEOygm8% z_v8=%6ZymYdh-7>_3JJD<`?*AQK^pkRoj(>kA>X;@PT+wKkxH>KIh$;g6%8mg-6Bn zWSQ6QOIOp=24tlHUlY4vQkm*Cq)ufS0ZmcPuWw0uUxB_%v*=k{o%HSt^~KKS9xPJ& zVs^aG(s9p0UkAh65_(9q#UDzlPphQzzS=0Bd76^bhSSwC+-{;_^=Y~k9HjTze$nRf z4M};+iN?+f@0KfoNeG|GCCzB{?3cAJsjyXVmflncdRt)!TK#*aR><#HLHl>5TIZ$E z1K*WA&O>Um-0ImUA5^3A0WB)G$8@<3I{mv6N##OL!@>k>XIIhO87(T`*Byg&VT zeoC`^5@nyBGSGYNZe4DDF_U7KklOm9n{s#S%BlBSo#dJ7!5rhgVXBPOa!omlNxTOVpCT?pU}OmtAiT~DTuOy{pjmsTMqz3*t?_0q>iiiD|tiW<&AQb zi1OAY)$7$VN#(X03(gfCLwe+q*^aP`a9fsJ_BVxRswd=9V`e^`ygDj}(shZk+F7d0 zLw@6?9i_ku&$%D@dE;_jZbv`jt{CIGeXgCE)E7Ub@&fZm2Kb=^<#3+oMp5NS@I(Z> zgS&DPJi&ZqobK|SMtzMFbEzFPokpE!KuZL4xxjNBpr<2FPYCa71U;F2SB$3(pTMQM z2N&aS-M%W+JHWGCDu-Vpzu=@wk3%lP>S_Ns9g{aGL zp7YIz?Q1|=LTJm{d_y{gHlB{+inrVV& znWFcN9p_DqQt?>uiBI!Oie5~G>~Ak18pr;&RxT+GXiq(S*Y&tpK}W8N>N4xKe70G! zWINH(+zeUQ;jij4${5RjIs3DGg$gBaFlI>FC@QQ1kFg%A-{7WIu@>FpFaFaHY3VYXw{9~;;L!e_L^v{M76gVXf@}7KepR7+nJ7GKUPN^ECdaE8o z8?Ex!zL3O2tY<>7H%x088PdYAuAFmF)*?+;HUh`A3r)@ix~?onSxZ!1S?U4aFN`1mi(z7ln&w1ew3)*C(-+SwtgO1i2^$6%9>GNvhGpYwO?$|oyy<-%5t z+al=V`k5A{iD^9coGvlVJoZb_HM%Z|E*>W?&~%0CUg+1AZQ$RR@wsD#E+4;JmlvtP z%>%r`x>CQ>O>g7fC%CHI6!^ePIrVFS`vI zLHRQ3;xc8FDJRB;=ritH?xTgM2W=4j#C?P|iT>)ZkFr6_{_#*SQf0l zO2ve6V1DiZ?VIkRl8c}l^vP^*HiA$4<1uYK_)$ilQYvA7twuX)z@P8tQwd|04fzuM z3VJV~@3_CYEbi}q``TytHfAC}Xkb1!UNw9cuNzBxc$qP$w%4r6-d-G^2 zS&ue%T~3wU{!ZBb&W|%`{gEsJmH~_IMA<34%`!R=G;PPlSQ`&_6|rtCazZc1dSolL zztG09R-ZMz+a$3bYsjF0D_fJQZgo^vdz$5%m?4F4b*Pr?H*_>f*?(!0LPxWpo+v9@ z!u9-6Vt(qFFqC;i@KtY2v#%dUtk1O{P+>^L{dQ6}#ag5-;TEYa+9C(xbGQrxagHpi zej$?@rcxj+$HeHf=(lKpWw|cBhB(PK==MmRF0+me!tW|X`!g;!InM(N)p4?CWX2TseWe`=NlWsRo?*}iE=^{@O~5p#sOa*^9jFm zcUO^CZp=3BG<@~r^C|e4Sziw7WIxn+>l4ujMuFkue&haT*)TuL;&X5P0J#;qUI<2>ixV}O;PmG{qSD7y74u#!c zY2v*lp91M$Hg!_^`o47%*KIs(_=bZv>)t8JPGhCv6JtO0<3P~Hw$J$O`J!~(3;FYr zt|DWm;p>3S4Mm%rRX?E0dQBzvZR$PH>%gp@4hTHcI6wSU_9c!AyS6q-KM8*nW5f;# zJcfQ`|HSeWEO}!dWq;uKBr0a#j{Uk8@WnCEFUm|APq6RCy2kR|_%oLw#wLe)#(;Sk zdq<+rJ2Nn@jv(F&zc?p?t42E@w;)y(nSik@(u9uo_x3u#06fZTbRnTK}bEWBr)<*|-731gpJ$_Xu3omw3gmc#!QZFKKU z;zyPVt&j?>{sVpRVWKir8!1Ihe1z)FehFjfx$$vu zN?gL_0u3t<$Q#hFAAE^&n6`43r@7GE8;r7ZkOAXS!#5dtWk01$lbr|1_zLjSFM#Lw zC<|k|F}B^UEDrBhmT0?`W$JF_e$Q^@Wzf8U_9#pJyOjrMx59RXeYO$6hU3JdohdPY z_6yS06;iq0x4$Xk9{C@N_h`EkK>vub+r7y#bS=%{e;sD?(7_(N)_muguO*eCm5@L2Zf9fiJ5{`s z)2^c83iPYUKR$Up8vt#rlLN400i>DEckn_k?&uqg75B&sW4jTj*ex$c{BMc2TVCql zEiY4d%lCVB%MZ|Q%<=3IzG%a2$y@uMMnPC1mE%(#&&T6az2YX&Gv4)gfj6!-3IZ=k z-UXL(#E?~c-bA?LB zyB~0-KXxhTDWqAbqrL=wwo8kTYaUO={y}5*$m^+u`*1k=*eK}salJyP!uR2NGvI%P zUd%Gn%JDwd%+i-8io%PJyxX$6a9P+arcaMX{$oR}LXO6W5$3u_eyI<9n&TqzTkmu3l zb^+50*r-asF3nb$QrRXmUlV^;g>Pl%SCjJ#dB4dhK>1@u`Db2ED&M#Uz6JW7eHvr9>36ZMsz5)? z(sX6EUsozsU76$2&H1?$9fjvI-pfcQBfX4#GTTu0v5hZx`)UY!7j1}4e8w39CT$t; z1b z^AGbD`;33Ybph8%@Ip53H^WzWz3eIHDA=yoogOFKAQ7KKpKZe>FiM%15PhaY|9Euy zA*89q6#|}UvouT9r7`#}?AI3ZbDUtlias4mCC5;w;WUc0g;dC&KeK;tpc3w@&*L|= zFTr!=sHd+o1)scN+?nXt9fmJ^pf1HO1K+Vvj(Wm5u%8?oy!V6@tZPw3d}Q>`lj0D; zaEqMIbGWe&%=pRZl=*Dxd zemv$ePJkCtKF74UACKeeUDsRq&hl?O0DPAMcZ?@PcV$ureA$L7D$l@Jy#AR5qTF6jRTkEU!JuPF`C1=|sbYCwA%V!9MQqbb`}j6cxs?HZox zX5H+Ehi^grRX3zylY@{kYdm2+=Vx3l z+Z#(SSb9U3sc;1NZ8G!#%N=75y^+xKmTrF;bu}F}3Yh20aSfp5ea?~0!&o=eur@2S zY@^ihj4?AkhFGE1Cn>Q)_H!##T{^cFeIn7AfQEjA%{z7}##znraac+}Rvc8lBbb)& z83mk{$Bf6m8}|)U(i+!8&IhUBpJ7zv+DjVzm=2yNn{Zg-IU%;ekxbRe_=FL!4myHD zuZlF$we<3NHCdz&8e^X%>xINXG6v)9`8vDn=b$P^m)_cz3dc50# zxvSG{d2|NjsNr9uzz~dacwX={e51}WRQZTP#Wl#^jx_B^(;mH)Lc4}ij?hjb41hhsRGo0ZJj3FHlI$e0r{mwCJODCbt2|nn!jK_-$C{!1x z<8EMyIIV@Bu@876Ze@LEJgv{4Rqm04pN~1~1J(`3Q(Xe{+Fu$4)|w>NCB`?P&$k$5 z)32kPjz=_w`?!qY_lDu~!bf3VWLpq~9vB0^q&`;fOov}m5Bs-JgHNnt{OySw-<`G?4jb|8mb(O@nFqkRLo<;nw?b4V|IeQWg8ErGNYqe z^>(9v12MnqTfuYC72$7_T3tcjn$kEALPl!lkhdK?*ap6^>ifX4D(+(m1_yMYu{)^Q1+2lP?Mqc*2+ed?rn}^YXx#T?! z`c8w^_W5!8_&Mksd{ZX1gTD5g5g!AFZ{gDNsPIoeHR=8HtDyJQZr@wODd*IR1vDJ( z>AX^P?nS!J8{ITP%6F#ya)spaVqOt3FZwy|nj!50%|cJQf8}(5Z$<;t(ctg)Y2@9r zv3sUxKB?>%a69_q53PaJE72D$ci=A>{3U}oW$>O1{*=LgGWZX%ny3t(lfiQ`cn-dO zv&3>#9|jGK)dQFxySP$n{}1v`pGzeN{@Ns+emjd!FP}|Dol!6(SCbBGH170&i_{^| zYX>G$iQsqt_5{E8OC$Wo`$1#Z&oH+k9icxT0ak0eeBb#p70*0vOgr*djA*}Q_!9k@ zPwD~mPdobOH2OyL2l|G2=K%Vnci%AY3<1`s(Kn~SJH}7CeeLK2!83nD{{xpnxOjZY z<2hs6MW22V{s|e&O-EeitXA0+r@G<9ObfHg`82jJRXEV|U3d}Jj#~wQe zppP+zu=Hkc9ctWW`n7D2Sf3q(j}cTmh5d)VM$FLkcLo1>lH)ZZ?f8%TT$?cI8jLAX zo*0|qo>ma|b5h1;<-m3T;^||Mp6%Uik1p|8tOK^3*W`#gJm(}UzO@1I1nZskY##Cf z8~9;np2Twx<`nZk{akw%_6}*;*Tp>^Gp|XK!BpE~`7PGm4P%2e0yDNDqF>i0kKHv7 z6|$e(yDZ`3>bj6WVcY!{F3GyTcE3@;SXlTa{LmEqgdZI?%I2Z1O&g5@jGM-}ptFrN z+^=2I&#?Y&fxlTS{9Bf_iIt*0YArxo0ap1BWnxjeH|Ca zH$TQz>Cu%Np~q(8x*yki@G4?8lI-$sRPmqC^3Ok`jp0}~mT$iPGfCNeOQfr$)E;G>v&vJqvqq3v&DuB{#Pw}F0PH<)J7AAxRa z1kJtaXPZ0t2G|YI&vSw7XGfq<*`Bs7$GWg7`=uekZZNJhQx3=nF&2zrj*r{r*ED4? z^lalWsU(5lQPd4Tt_}X%9<)jLcBr!=tV{D$j6D(G#$DF-lUg1|Oh?nD+2BgVV8+gh z>C#^Kbafn~_c+Sifs@dY*BQQ@@MkYu44wa{TzcBkEdSE6M?SsIne$udlpn6ur8%Cc zn47A{_aLr$eyrm{eY4U3mFWNZpw+(?zR~)wB0QJzUe~oY)7yD*#X;;=pTIM{)tS6-vOR#f5lDn(3X49 zrunD`ZIjV9`6R|y;e0AQiT)XU6Z$QKD%sb^cje^W2js@P^5_rw`;~q9|D){BZ&ezB zA-_M6U!z2BR-H(r^oOIstPFAC`?|}Fx4M08-$xt18tysN_<{Mt;t5`lNZ*E!9hX~SAL5^RT-|$2 z-8*)=OoLB>{(eA(PobG{R34}E_o@DbL-N2rAlH37?&b#xe6Q4O=-npVldL1#eWgh4)#7+9L!(T?(KXmJo0zUr>e3cWp&+_O}1@6X6 zpA>0-?=EY_SYTe7$;;sDF~rp0J<7wxj~@XRCCWF7{`*ZmyS~vEO3(I6MzwoHl$~fYfkh&w9LtsFyKdKZ9+i z@fFaJ8>bCzSOzeb^7%7LvYH{6(1 zF7F#jL)v58jrqsE6d#wQ)cr&;V&c%#eddQOwO^$5@bQLeD3rT#L|Ez`>NV& zl7F_Fa>n92`{Imo9ml`i$?NT1mGSXHNGdJ|-voE|jhE(f_&@7?P`{7TfnmLSI5l`w z>7|`RDcys3?f9X@`8vM}od^9DdiNTNeThm2l9x2Zhk}q5fkVoCd{Qos=#**TMTDqQO*GHY{F+viEWnS zeHz}+x{16MSl4(A{d|=1TAREVZGj*0j+LzUq7vh3;mzxCW}z)(dOhR1=b#VR@7WF; zzD_P({cN%G+h>$g_GyH`Q2>PH49}V(j0s}sUA)< z3pC9^I!;rGv;)y^qOO>hl$K?h?xPvUx9Vb@p-7Vw52}6Fn05?nAQ>;?D_uU|G45`r(#lFR1 z)H=e9yOw&OpWtJZp&!^D?HC=EgB*i>Esxfy;L)STogw&2#+#!gbCeJq~K+D&Bc2aG1qMQc+{+rjN+9lss1+}7a}c5YY z^Kn{!pRg^kW&EtSU19qS`VpsYkJ)UwrGO<3fnmsb*0))t$#a&GQN=Q z6l)t&@MR3FSb&AaV$ibzZRYqV$HH9DnasnvC#bS_8xcPMPno`o@GG<8x;SNx9=GlC zm?jNIImWMzg5y^set~D$lssbyVj8@EC-Qn8{B^9)#9kxjotnQIGY6N&`3~dD4=$w~ z?)QPXSpNHxX|aYFG<@b7V#LGN{B;y%6ku%)_5no@Z>fJH&ad$8T%bqnCEc0F@p_*= z-JJ6ZLJq+5~^ zGh=T0``ewYLq(ZklRr(J5lYf4<-mR~P^>?5I*!M~N$*8}J9_rZV$D#_aFjbAGS`lL z?T5}tJg3s0uS+js+}fKKK?h>q79F2i|Jsv%*56al$)0*9C-aacCvM;__8CRs9ce zKPuLN@fx5W-TG7#o~{DS)viEXX$oxD6__`;8-B#~l+(Etai|~TGxj@%mg^GNfjJj* z?_2ah&zzwrIS$3V!LrMGiG5zyS3-{9({SI5d3L=Ed zZOA9$wc)1{@mlsT`?4|GeGYX1+ARE-a9oB`>^HB=7v*_+;=koq+7z2L8+>cUuzJ!Y z^QabvzXKX)sixmh5rZ!V{+q3uu|O@y;pceWy{e8qdgdHo^?53p$LXLKLeL9X1DS{m z`q9TpF~GiJgDA_24W2@o^NKO1;F*{!1vl`jcHU!Ggzhv=%0K+qkn8ZDX4& zWTvUxSE1=*-n@?eukp!ajoMp`X}sR70)5N08@n$SaqNx9GQH#Gi-GqN$P|xfcnx=H z%(M+Wj^Q}sC%AZgKOFZ_;4K$)Hs-bh$3GrLF6h`GY-H8raUU>+e-P7FIsJO}E1*Z2 z=gChqL`?ft=wg(|^2xfIpYdKx*4Oh8bK+;>`v}Up72^~B&igMzqp%JS-$z)q+=%@b znCnG7<{FCF7aLn0|G=c5<%R3s<}sw;I(JW7QshQphxo_>HF?b(uWR6#$tK{#u@4^0 zu-sN$1D_Ew1eT#$kOk2Pt6@_nIsBl1?5sg?c~MQC%mI#qANLz&LSDdQ33+(~@`7}I z%8S+`FB|)k6_jJi%1Q8YLbhC3wEIrM$KwQ#%7tiupM2bayiJC$zgQOQSSx)9n5;^yctOV2{ygx+21M@(IfDj^NyN65m<9{8-#OCiW(wFl228y0qAT|Ca4 z$bcP)U=Hawusc`cb9Ei!TB!e>A^8-3oC-I^4#->Rpv*D(5lk0w-Ch9f@HriGc4=0h zzku~wTcZlwALbXNF?DpWIl4sJUs8ETvpHA7;{=PQ4Cr;#uUPMnujuLP;Bu_Canp<{ z+=FNz=M(lLg~x%(r}WSgqz5)Ku#xZg^ysB;`iwg}P{%yz`rPYH9X=T`y0@>wtku^I zAN*$dNU>2M#yQ~s^zvR~Zq+E`abN|~fX@;*%$sD+g9mh7=6QgVz+?@u<+*@{vxamU zvHVk)VBPdltb5IzN*#DV3Rv#)QOP$k&&Hp#apAe#u#zgz;r+GfixKZoW%k@WBIuQ4 zpqbmxHnJ}ajHkPO+^!7J$Fwz|ZB_7F8UH$r0k(aVM*~z%s=&Lx@^hS$*J<$`axXXV z{9n|Nc(1}5E7=GdiY9|@oR zBA)fykFpti&fqKLxUt@F^7AT9E^yNp&_5Y-SGlL%v|fJaV_F94*opae*Lo^`ejSx$z&{N? zM1|{M4>PX9{K{U;iyXp!=$}#{uTvbdQkPF+3b3XQYecXn;{cYA?Dzqd41Nl-h3{>* zVtoicKZ5t`TC#|r)xY7U-#vaQwZAcxp1WlzwSRjUefZ*~6v6k?-yTX4%x$1-h4=AP z*Xhc-A8AUOQ&lpsk4o(8m}&T)d=Iz7rhjVJjG7tS{T<(xn{EKeOM;{@(sC@=B} zpB-f&pW<>oiW^^+BeX z$H&^!tnJ{lF<0%xc&cyO2O!^{(8i~+A#co({?iSNm(T4w0Y9q(WuJIAlQ`y4@9ICF z3%ngdU%0@JOxvrFhoY4Sl)HAfD0e#dDaMj6-(!;@*Wep%0>=EPr~0^?o*P4f477)3 zH?+}BkAP>=(UwA7#yeP-pdqb=)fHX7N3ri!^yvufX$1b*Qy1WPzexYz7m5;CI?eh- zTGS`fex+C12gI5O6@4NHE~UUll)>`#D0EJu4D4SR4p}eyvztaTJ&$(#8vNKtd21Th zftYK#7HY8NF>`&^B7e`it)t8-Afk=&N3P;eyar9Gf?JIXOOh4ClXa99X++5j1C{f4@8dPc=9-Cc@>xa9(^nw>Y}hqx%xA_3wkBc(mzU}C$d$T$CF&Zr8~p~o zE$~cP*Kp)iCTVBL&-w-R$?gARu0=aFWuU^({_sjBeSGykMT?R;>3!_I!@43KQ++93%N>)>hT9ErUKZE_C@OzXSYG zzOlR87qjSp8~gb&2aK5Ozw;5;DD9nS<4P#e9e}_t0A7=LH&#lp zhm@-InRI;0A?5tl2c-*J4@rLneItRv*lToIM+|ig#!s)@M1h;iNSThbxdpny`lqk< z@mS^#$iw87y7Z0R@P82V^B`ZtUqJtF&9gk<2Ni0vr0fOF)4^k*vo9p=#R%}T+h0w3 z#=gzM7{&?6!@doCS&4mr=EFt0>GSYdP|%dJUyuFM+__Xa3-4LirUf+9mkh5<@(H=$ z;ivf-W0r+F=Kqv&eh6ix`WRxJQrw^5GI$MUnSN1P5JPN9Z&sEe##D-Zkw3#;$VFky z#c7zE^W&^MwOP5Jnw1BjPb1}$w;Z~{k2dpLfS|{N*vs6M#0>na5F=*c+L04iKl|em*MobEZ&#<)obL zvkhfLxeY022JwDaUZazH4F$LzdBBg`a$q@p^qcdr?v=(iwRTV2f^I4qQdYsQy5b@;>1|52y1Ar!E@y0HR6$RlDFw? zV;Xo#1~19rFB$wLgQsNhlnkDd!BaB$O$J}d;48$nc8eHj_$!ja`|v8zCT>@$XxEEL z{9oR5ai(plqii+2RCJ<`K#+g3*9Z$by< z4b9_z9;?GY2?L8TaNvI2J0#zf+mt!YB|Mh8(CtGVN&6M9`y*E?oGBO+F>f>bQT>%(eBF(<+`*f&bW-tRCfZcP8ryEz6E^W;{H+xQ#i0%t(ic4A)<(r6h}xQ)omu@s(XqUXqe^5qy;Krd<+&l|PaZQekD7DaJ#)(NOO;9w)-CokPSgsq*4U4=Kk#pnPMo_q4gDg< zbhz`ldO5GV@O(OkX2r{_w(_3Ikk%}-EMt#V;i_=6kWt2w{rezzJGk>a`V+qV=$a&7 zp3_u^o8>TUb_e!tYIl)(V!Y~%eGlgnL08iZn!)QiO8vUR{z3=Zx*ylmxK=@y=U@#L zpA#7LV2u{&4Pb2)WM1UuIWOb`|C#b>=?JdV>c_t3V~Zr5QGNnvf6utQG!`Gz zr|1W)x$*P(+rpH`)og1LxW+y`S7xmP75XN{4vJ?fx|@CAG}5y8JmCJ$0cN=tc~j4% zTxrhh^PIkAces6G9ECgMZJg*XVqIwIK{F=tIqRjx8g_FYirXxB2z|iw@K!&3;r8L2 zyU%N1f(L8+X(x1880%Wi_)t$=hhsX}4~~6ESnr3nhBREdF7!nRGO_AboFn&bs;qt@ zlL-3;tDk@!f-E(R#<}$v4pm{l2IV0hg;)WeDR?)wA-~tV5#VFIdpbW}Cdx71F?_4} zjy1li^gIfB)&ciMT)e;Gh43Niqc^aP1iadcayv4}-wK%*ZDla|nCu z_Q`vW>hgZaAn(4T`(!@~u zemUNk_Ihu07abgZP#SPG#{H-#U81pE&mim>7&rwn533%m-EyzcrL})FW}e2F?KJGt zN4FbuOTqhPswsDZ{tjS^=-Y0$mUpNqi{%lw!pQ87;f8hO6?XDW0u zVIDe$xs)*GQZ!x6KmQr!7`TQ*7u}5OrEid*=S`6wHWG6Xg!Khz1ImPr#2kc%IS4=I zAXLmjcvv>fIf&`+>+)gfiH@(DXI?GBIOVD#wa&)^$J*?&vfOULzApxzM5<= zZ>8nn`Fg|0I*QMI3u~n6OVPieDFm9dADML5pl;@?nyKK!IX!2!F<-4ly<9%?)^^Zo z)yww9=wC-4*?~DOIq)Ear;>dS~p??@_u9xe?_;(zSSvf!M0!uC<0xWrqF0jNq13J;d zQpbE1w~PBg=yS&NioV;%b@2YC49L8we=@0SKr_!{KMS5a4O*UM8bHrF4f9DzfA+6N z8S;#)#&?_NTC>ULp0Mp%=rR4B$%u_i ze*a152*gGvBR29E=(BSxz(-rL_8k2D0q*Cf=<;9j?68XYk!GA#^Cx2_%1EsJ>U}=R zCE#(>o-H@mg$%z~bgmit2Ye?(mU!K1IxUw5!8QznZ4mPdA6+Qo^D4wT6cuZD(6)u3 z5o3VF*)Q-_#}0ts%=0lJ^dk^+0Y&?%OK^Uu4f*&mV zYpxC3>P$yl>mfhFPd<(PGrUd;{aXQB%(jVbs^&p#(gRsQJ^3upYm>*qpzTxZWpi{& z6TVOU&Y#1OLzXA;9CyaeveVorvrs4Zhp^e6$CF}2+CihN95fgQa8@kxrn$jW&ztr( zsmxgaz7G3eyuX9}C~IxhV$_$5xi|K|Rz)cAN6fphKX&NDl)mdG zv{9Lg`34?)^p#HV2zZ%k>XV*}-DL|HC)oe(Xh#C8cTB$LeobH;Tc1ROHi*josGs|V zu}<`j-m_+weKwreEA~CHequbUyPK z*WG*FwFwk3+E>=M^%)rBL*}`jnitHNaRmCKbpoHovQL~*VCg9Ek*RCl zn2W*gFQ#A62Ohz`0|l4BX--&IeyHop+!&sD;^%XnX-LA2X}0|7RvvdmlYhHNJX@Fi zjOk#k*>A7y;&U*}`s+0n=hbG5Hi*wzBgAJuE3zCuK}Q(-XwlZ=VMF;qH=q}ACZQ+( zyFRh!lIaQ~4y&8C9Jh|I_EGg9)K!OPE>gCk46E!l@v^}e zvWz6#+qYM zCd*A!=&s~B*eaw?8;ZK&!*V}zI_53pPw@Y8KjKG(v!U>8Bi?QD>+)s|G3&4{KcVaL zlQHxme6E$AsQe2RaXf;5qeFdd8)V&KWkf!X}n&a*XpxAW**~yW!@3G0%x=JNz+eEnv!*X@|n2(>Lb-W<7+YM z*oAiRI-qo2lhP2w>TNF%<9R18j7y8OTX3$mUsE>Tt0@~a&=wXpHDR|FspcMtbQS!E z{wmY^(P!ZvTW96rwA|MroHwQ2O#bTVePS*?G;ui2gHWZx9>f}79Ex*Qa265vJM%cO zdgnES_=VW_wGHtn&YuRGZt+ZNU%}ri(l9n+9#6yGh;%>f-)<3KQ#UZys;ReAd6(mm z*16RdHlQ2(@^rB;4`)m8+7I;=E*Ji7dQ6kp7M^3=%DSyH8r986zX|y`ei!t|Z4V`{ zt1ksM7AAaNwTMA%)p=ivz&U}b^9r+#r~c(%}+4BD}l!r zQh7~t+IX}Dz7?-+=C<$|mXp~ZT+?N?={{1QK%2IpO`E|N8}22A%FN$!3TpkdF9y8; zT2ZgOL^aP00bOGmlVi;~`xauqC))zkZl$y{X1?b#IBjY(&c7CA;w4e>*HxpFM(*{ z@nYOWeH!WmR-!&VSx5Ivw72^uYJ^Pj)F5dZ{P4fHGuE87<+nv7hTpfRxk_YuAco_92#wTol*M?@d=RS)~j?9=!4j{S{e77Z!%aohW&{Rdyc*%Me;986Q0o__6b8p;sk7sxT= zm#sHRFUPWob(*EmxE{6#8?YDe+*qm{j?by>XB)t>%zZ0-Fvt`5tEl!cew$$m#&o~M zTwxaCpE!Fie25AMT}5v9|KmSz~T%4DtDl zsW?*=<6_Kxti{|)3)X86!8t!|e2yIIYs9{b#+Q3y45zSGfZMdK#1Uvi+8REK7gu-; zscW&0o@1I-_#K)v*kjRxvmf~^cV5@VYYuo#XEoMjhq2b0%jPpp&te_I*mm!Mrp*WyCEu#S8c#v-Zh;`S%n6{J8L(*8@^g}pv#S57kM%@-KHdc zDV{ylGtY@OdV_@}NfVs_{^XS2o!OZx(UgfPtABAwW zA#dmm)^LLdcrCxEkI%VBtiF1*d9GP_FXlt=dnALyycX*StyvCvz?x>3yCBwnYXMW{ zYI^FHSU51zk_rF(56K;G+Y6OjMPB4F)MqnfAdeEfptTD5?3iTaDeY?#1_}p7wpZC9*g9B|j zI_6Otu~cI)>f_(W{Ttw^(;0W<8I zD#lu!B0gtTqyv9f*HMYEYbo=N><_ZPEyhZv&0;KJ`Pe+q;X-*KhwKbhQpsreaHC^S zB-w0j2Ig5IoBZ1Z({QoRz8H3REIy~>LYu^ROT^GLbG#++aP;8F;}eckiS;5VD^)N?m`uRz!EYm-hTr&{&qBpR9XFt~O?8o|@ z{mK$;zp~W7AM3y0KzvwLekiL7`?75J-^JC5D;+k8V&r? zAAAGj!#CuGvHkKQeZRaoykB0T?U$GO_hVlF4Kp@|*pxNT`+p$z4P1(odet8e}LO;cMn6w{H;md`f5@+T+YpOo zS+9mpa^*gl*fUv1IM+ePdV8!xTBKpUeGKdD{a9zOVx7GQYw)R=*L#TH2@RsZM<6D} ze9rvOYu9I~m=DHx=09GejhLr@<7g^oem}W&Iex2nxl~;t6ja{u{EgkCnKYYh;e{|10iT(+dLf1^hZ~FLv$I!?alf;EV*a}ETlk$Dq~ku}d+yU+Gr_kQ^I^P=^>N^189Xe5hh^}v3?9b(mbsqa zh4y72M%aMgflRNZobXNPhs}6~-!G^i(LJ|*JkDJK-!VN*M=A}1$H#YH0~& zSMU!oaDiVtz*DYofRDjfF0@%Z10Uf`eILtQXg_3dbsXPFS2Di&aeN=|`ZT`FyZXns zqRYhhuCDo!;;z2&&F}i+`2MoH?8c|jHqa?>8fDB+-+{foS>V(ErW^zFuW>GWLWPTIDWVNI9%GE(a~U zpfj>@zY^b@pc8(9?}2+AURSN7a^_~EfZttlFLVt23zDT7G0@c%#csmcDED2^h2KNt z-^yFEGvB)bx`ugz`)Em-E`Hl@3HG&Jj*DPuOA1 z8|SzlpvrkT!-0PnGV&7&EG`5OgWeHnH{*5(eoy!g?0MvN&)nQyz-=GJz7^Jsal2fr zyA%3<3Dd2bbf^E#ZQ8*&?VCsSq8(-M{!6i^#=zdDk@&q&`1#Dw{5#v{rqGz$yzXfM z@OteS==rO0zKjPli2B&qXWhbkz_Wj%i{GxWWbFQ4xUo+n>?7CT+FkbK8{ISKqrKdh zJN_fy=9_U2!nY_e4{heMPqBXIy+BxV^a}QiR%7grefohKtm!#?6d1gpOIOU#qr>1S zKErn~_5{_80NubZgt9_E;yu4d1bs`M0&Q5g!8Ecx7g*id_4!!6+g-N#?e3Y3$(Fsw zObZX=s;;E7%0g&YE5=FN1| zi?-moir7p%ehUf?9RLx7%tQmULwjx%!JqOA^q5P z^bhXiM7~Y&eE*NVZvl_0y4v2EBp4;Y1Oh~jc8~xwX^^0(!Am`XP@sZFLJcY{6G@7P7o=!+_bh}wRLQRU=0v2ZGuA1|GxXoBss%` zi|zOQ-~T;-cn)XIIs3Bq+H0@9_S$Q$4LxI*d_$3Mn9Mf_`5w|T=zl#6^Kv%$og5ox zvH5uP)_qS!%GJTxMejGf~fp&W?hdvbZBIUt2@CEK!h_5bxbOCNVl0^J#yqi7=jI8qhuUP?Qmx_h>VuOak4jV*>bH zzy|)=SRv(i=*5W705AUJfyR!t5a!*Xr!Ws*4jLo8l+zjS;AY57NthSu>zxES2hJIG z*Yio@nK{G7YoOUj*NEu}q`UE7WU_9KO?6pV+7O%%O?u_}S@Mb2ujTiq2fT<+5T?r+ zi^HZ5hkTo~6#M~g-uG~r!v&p^uUO@WE0sqPp42{yL5&36yPPCw*jV`!N(CV zBk}c_kiTZa4wX1L+MY29Hqz060d!}Z+)tlBRM^{kF2#I;cjNqPD6Wqsj2T~NG7sM~ z&N|;wzV6^X*MFUfvaBlDkGCiI4}7hnEvRcT>O%Qy4)%`*LZ0x$TemPq{1#t^g(eLXM^@DZ=sfTPGF z9CbB_b?{`sR?@hqe;?8O@) z=ijx2c8qhxlydwPckdfQVVQ5CY+2@KZJABiG}_iQ;EY+|3pPAy4&aY{m4h{A3F>2? zb*yWE$Fp!4-#+tkoTJrz4g7PV+pC8zk2=MDi^8VWL(f+~vC_0}Bx3$R-&a4n3_i7p z^@cilW&!u$_6_M=C&zJp@Wkm1`F%RRLr1so2xPr6u>S*1`%F7+Ywm3yFJ;>ih+hJl z9X)ubsTanlC$&8<2|Rqw==QOQpJ1f<@V3k~miDo(WF@gOMM)fibX!8nlX)o^3pFY1!Os|Lj_4(Ju^nDmh?$Q2y{k1#~@=4t-$}Jj=wQ?$We}Cvq zZ-^9=|J6RX68cN`y~18a{4nn#Vc+%_tb>t{=Oh+^Hyg(E;MUA0;6}UsjE=iW7{m4L zc`oQSwcp~5T+rF*nV>VQ!6fXSNn3w7SQzhmt{2uDUyv28fv6rg#uRl`_do;v?0t|$2e^^6!vlaEf z5-U77iw^0!FBfG5m)ilWLx;51|UA_-F#pwTbo5<;g}l*C|rN$&aNk&7W~@Bhp6VTt_GTwdLHO zZcHz~W89zfdlJ5zL+9t-DE3dKy#(MMN}SA8b)9}d#t+=tZpiy`&jn-1wgGARPV^WN zCc6H~CzDX{&Vmc^;^kk)xUuq{K5n9ZUyw67XPyx0c@Hh*kF+@t>CfXPPG*8V_lL#f zrhXW7cTCsc*96@y{^$8s`u7R`yXwEY{C8}s%5pFCzQ>=>vhDTn&7O5wdFjMIS3TXh z{X03CyBtk>&y0EPp0F!6?|ysJt+`wF-_tz&2ha6TGQPfZ^?>JY{@VxR)~~#y=vOZc z{XFZTvcbPO_+jx=Un##D+ha=7@jL(8zQy;-qI+W}u6$zNiTs`U8}C@Rz|CTdU(!#kv}_g=(g+?Z4-CB zGp1@&(d&nI-~ZPi?LT(egr=L)HXZuxpP#R29XYLX^vN^NhNr%HH%u*KOtTcdfdiEUW0v;eWVn@3<>}(!YGnwg)B_Pj-Lu zN$maJDYZQv6JNU};$>6JpH%iC|Ipu-jB!)$xmAS0rn2*IPqy9<2mN=~1NyT%OTRbx z`|~~jebgZR{R;nm$@lc<*KX18J4WgEJ-zgMN-h`8j^%cA?31L^bqqRd{qJl2@6*4Zc@L`!49e2M zdivNT{ciQ&T|@O}pZ|M}AAcVX)88xC>-Y5U-;ct_-(&svIR8D~f1lvLEB zC;9JI|2@HfxA^Z1{dbrDuKMq63;z^V%D746QZvTQ7(aGw%Jm~A-F4TU<5Q=Mop9r*5tFlXCg){8?8r%< zJA1^~yahQU(sSnUnw&M~!4YZW#{6(RpZMk4Y=@&OIELRIJWVRhEnHGqQ@FRVr7&*k z!lfIQ?po?wDx7i7QO*fYhf{TKa_(_{VcZ z!ckFMAzVo=#pQ6Rt_`l2T!&o|m6pns%1M>^l{J-zD{HIbtCv(Ctd;;{P}%XrqNb_y z)g9`>0$)LL;ike}g_fo1MLPh?gyLPr6G~R2-oquQOTH?#lpQV`RqieKl}DkjhKjuv zEfv`=kIP&+p>lPlrD{dhuBwRYgz9X)dc)B^9qI@uEF#Z`J9l1idWu{xp(WWc9b4ik zsVVUQE>Q{>&C-LVZKZK#xn;G0Pn1t9SIbue%I0!&#k7h|6;@YiWpm}!s)bca)oFk& zzxt)>UDZu`xr$zHzWS0H0r(ac)D|=p>?$}`5WQ4g8UZLLpf6gAr4-L)t2g8tJA9+st;G6*2_&7A|LSPs-xw57QydlYD($r%j_m|Em0+EtWRyrkG&{9du6WJifoy0Fw$x}$V2>WnX&kA7|_ z`>^b*vZ(T;a;1D>`G#_(BD*50Dxu0#HNVZ7R74HT8e%zu#AI)kK zFykp`E|^wWTX+~0qAoqWG|rg|Do!cdR3wVii&qz$ORSPwmw;MdD~T%|g*I$L8=BFE zl(O_PN7;_D_sUwzqRZndPgk0&nst~}&IIW-m%%cdC%s9 zn-6dHZ9cZSWwY24x5cu>x@E$a^ey%+xm(mNrCVyY)NXNa*|eo$%Z@FFxA?Xk+tRY7 zZ3~2UkJ)4OBzqLk1W&qWn#b`prW_!}_k^o@HhF7iCAwGbXe|BDhP%%Xpme}TE#|A{w+|3!*$*d_=OfqNA0F9>1s z;_)Tie}xP6MA>m|f~WH?JWp)dw)V3#iD@rd`fZuC{ks5_e_{TA5tO~J?16&f&<6dR z@&AOIgn9CP#&;Lz)*3%qX9e4E$TF3ibah>UDA+ZnibEz5%DUz?q^ zFpDpN7t3{B?tJI}Q-ttdyCBDrHxn;VRsd#s4Be+<{8m2$>t5RAa-AEn$x4;B zP)1*2t~Y7(MEx1kclcjSLR#0z+VE)T&RmFnrb5T);k%EGv3MMOHwb6XcS%RToGjMO z`piaqX}q^OQRhtPr!1HT0&zJPd6C|t#~pvvt@|~G%D)PEQ-+CYmcfV{fjzxmsF&@d z%_wzOTVY?j7cr|)7HpA>al8XDh-eF0jrap6k+$uR+6=qmwf!2f-Z%59aPEKJM_Yf3 z*F^nu0o$OwWZ3({H|s3GpN8+utEbsvNCTZgw%p@<6)_VPf86|R)g;rZFB{Sx9{?St z?+w#W(YE@lR8z|}h?x#J>YvwjE`9N>VWgIq1iR(xNRbGAWXE~kh}qF`UUyY5{La$P zSVt_B#FGW7;so?d)&22%t$w~Y_AC?kH|pnmS6zkQAM5E4XCY4f5R^TrOWC$AWe@LC z_Q)<}-_WJ((Ot^Et+Q;zkx;6}iNxwukyw8f>^2Aa>z^nRT{y>nf2t0HD+{_Sz*`C3 zSN+?u@G*l8Fm#j$*e>Y4>cb9+lQ)`Es!>)Y$~uX1PC_45iE`>u2G5E zCfiNkbs>57qOF&pJsWXnj6+HH1+SddZV$fCLfg4N$@3?fhdwqPby$LEp(_rshe+6D z8Nh=q19-Ru__)wAI`RW2GCy!~32<}K`GFsqANaWhc)HO1g#9>igo}PoQN$VA&-{{B zmQ@;YCNxtv^t)Z-lfX|{rx$O7fp5%%9zHq^`#qnFX;~rW%ay<-_x616iZr_dKY64X zjd=>fql|6CzUJJm&q1N*Db8cetEV}8o@(uZJ&_BTrv?tz&#T)27@Uaf5&;-!7eU`m zS+?C6lOYGNGX{wK)?z#x0=O~wrb#_F>}V+yY(@F|W1b9${61hmWRLxr@7M=k?2mYp z;rE5#0UDI}zk9g>|6TV5B0y)1r*uJOqTG%?y?`=3fYSvy1G0|`aH=E2lwkY#EVu5b zvIFJQKP3zKg5@GtTxufa7`1A3TVk16g*MSS`|PAScDZZUzzU1}uvf(_@hL9oQ@~Jt#R_1Fj82m7dKp z)Wmw&)#BYy&kwb{KwL)P_AJ}`fZct_{z*0V5Br98%e1@WI6G(G*bw&!@wrIz=c;#A zl5X!%nXLCm55T;t$t<3ReCmx8X~SV#Q2*(00efVLZ*4pLr7Wq5lqcE8q55}CsW$d= z^lK&h^|~v8-pJ*9^L2f9-!BzD)3M8OSnb==4GR%C7xokn_DppVlDH#te&<_RV3-im*!kNU$V$8#smxAY{M*-Jj zz!&hD{xfW{1_H;S;H*U(j|?~)=R7x zopEG<8XnxY+U$R2u7qs}{ZO7oKa-cX_QhGL@QFL}eUaEaMkKDrdQKKB#6eaY=nyxQw4_#RAalfAX;j|yQ7IYSa zZ*RPU`2R1rV_b`bFY4Rx-v_%1mU)o86=m|wgI&H2Tnhy?ZCFl9Sp&Xa~^{7~R@ck*zt9WmqT z;AaedVghu71KR!upTC|l;*KU2@!`x*>*;0p-Z`Xa*q)e2xszWZ3x*N)w zD3|5&ys1!Say)g&l6GT#qhSk1Ia20Jt~J2Y1MlfWM!Q=1-M!lIy}LG~q0HzVp#Rgi z+bAcpjI=-Ao={ zO~Kix%3!R^`YDNQUxcKQGnr{P1BY!QzPoEvZ_G86fe+n{^H`C8AnM8@d=17kebZ2W zB)%u0d@cM;rZy1equ!1>kxzqtF6(4Gbjk^FgE8Lk(8uvC%q5hmBeGSwZnOhuvLA!= zRN0`jI@Dk1TM-@!xaeCb)1|*|=x>fqrVWfq@(R4`I18G7o~{J=LV=f4<_%s?NZUx- zHL|Ti{JD9kNH_w08Ru|AI@P$o_ylPnCk!ATXaCBwg7~zQ4?pi*I}GdxzZ393juQ!! zy>pGzigRyUd#B1cHKE|@SOW#YL0qu@fNao#lMu1m*{1Ed-p3V*i@FHXqz+4`j5FJg zwIy_=5)N2^hXLMz9x5C4vHvbbJ{R~ReKnH}>nDLf(@q$?d)T@3t^wIuj#DrAGy1pdI$^^* zK|UTLFm}WRj75&qtPo>Q(ih5*W3S{?ruNLK%m|bl;Ag~-_9fn-4vt^?W^&vw0>0?W z$#mq~4v7`+5Ydi> zo39p*D0~}+yzDoQQQ5zUF-yGv|%*2V|A3*M4{GWq3YgAbJ zyLMo;_FFCE`+y}9S4TU|#yNY9TN|5plRh89Mqlzgu2b13Jj;%Av!szAp2_xx8sq2( z_<8GRqz3j`?6(Nzyl}*6V*~ZFot&T0{-Lyit{g3{j5!m&wKKq95&^4?XED(y zvvLUh$}G6QCBF^Dw_zM7N#XFvgbxW;NB9l9c@tuiV6HQ)T`?!kvgqd+;4bGUtpYym zXv0j^&u74+Nmuzk@EI@0nH%SlArEPZ=WJ-Vf0M~EOCF#Ce zkV!55tKQLOPzJg7dRpG|cDZg+XJd z7xHi(aJ?KOSO$FT9kjP+S=0pr&$4ZGps!H0rCp+BusxCwg>~xHpo5UGy8LsqJo^>4 z-%K0$#&*y)ygS*O@hQj?xQ^4nr)wb#QqHE{g?xhXiJpeuhWmfyP1M6g;J%ja4AQkx z7Hp=D4KiTsKd=r%e)#U^a%^zza00lc-1h!RG5rMeWxH&Mr_>iZ0=LfR$?wVk$?Lnu ziKxd}2$BavA0%-QtXo_q;G3(N$nVMP$@?j{k^abg0x>nQ-j?fmuJy_P+wh%p1<&SS z`_<_}As>@59PmsUPQazDKb6V#JIb}94lDU|4_ug2tod#|hF~_H8B+{($XLl-t9Kn& z%uim{UEDG1&I0oR<-*w(uZ{5^aM#CRPd$Eb=NQCXkG`X9AloolkLOQ*i}yn*6KMC- z#|n5s8sep^Yyh0w*uR_;PT|rjS~Hc!x;^)|nG-8PgB;_G1GD`vx=d*4gP2snOB~*< z#5zu{35J6nz{4!Fv4%@fO+1gHV~&_{M#iyata0+PlMm=~AAAF?y>aeD8~n{Ap9Rjl zTN}7AA2C*cVBTQNCBj5n?1Q!L2CV&e`PZrqSQB$U+4B_iN~uvP&Dd9_-ikhT^(+T@ z*%ut!l+)$d6h>K4{WoKZyEvx@?JZHR3-qCs>i|PnT^ZmxXH0Qf=I6%!D)Mj2+5!40 zj>B2itI;QzLrUl`3;YyAkL_Fm|B9NvQr|D@_JXIezCY-3j-3%ohrFp`&%up&bj-UI zeFnX5iW_GpaL;T5-Z6jGDJ@U-$x(gZm-+zpC7~R|cdrM&VQl}$oofy9GRDt-9+!$3 z7}Wn172)ibLX2_1G6eM9gz_a!(63#GIP^~PlAR5IQ%Gp!%mqU>xciR;+D%XU^d2CB)$GSam!_y z-a5nDrbt!J8@F82`Lc}$eU5yWWqenMvO>n3$GE~euXAjBgKTmzX7IgZ%ru8Vw{@Yh z%Tabd#tr!f$8IfXRK_DmjCt~1^#bCNOS}Z>5Y8Kqe8h#tBiC_mjHllnFC+fQ2kY#J zcZ@dGi34)4fb9wJCC2ZT?Sf87%GbcFtfS@EhJK}wH+hkihd)a7-j(jay0fil^*=POsj zyY}0~1wI!ZB)k_9$9ERs?yfw18;ZGIkLUaG&Wz<`|aWlnsV4%J`|> z=DEiIEhta7JV7~o&wwydrX{SQ>ft(+Ym`vmxF%={z!20Xme(EZ|3CKY|BwB8Q88`* zm&AURV<<@8``;G(Rr15Ts}1}x!Yd-kR|9;J^G%1ZbiV@~vR$yR^jh-Dn&k$5crIUQ znZCi89(wYjk$zw4Zom6|r9*uuFXg<+Ih1?AT+0MxEGO0*Y*$eizi4GlAL+v(@P|DU zk-qWA_UXGn9`kE;SzY3<;&$IVH+ti}O+Om5dQQ*1t6zAm;QsyUb~HANId*`(wv@79*nk&kaH8+XChL-}^TC>)WW`z5eIm_mlkJzj{tjXWgvd zv;B9s|Nf!>p5VXNyr`#Z-lE@=J^FpV|K8xgxA^Z#{=0pvp6(_8J!+f&ys1IIcfjL^ zSMkHO#DCurfYX0Z@ZXdC@O;~LeC2OflD|E6|9yr3zQ=#J`tSegcKbs3ubR-`t8h8s zE5qx*-DmZO56<~n&Vq-s93#@lrs>YBGqVGZt249VyE^Zjj;kbC{9%10rWHEj=jSQh zQy2yBRoBu6cx^h0)FOA$-lArBhFXi$inEJV>95!VzrUoCN$|*1OE#7GN@7bVl;)Ru zN?YJ9Ils&UpUk$h`0`Qkn{<}D%U>!#SS~7(DyCMb@Xhp9SX>h-m%!_=p=xi{F?f$A zRp(ZJNN+!$Zz&wOrKnET4Zpysf?RkY?kO}o6=ya)XjeO5bH3*kMN5j}i=FU3^uSLu zsw5fSvbiNrcp&a5F_&85M|rIDbZKqb)bi}|eAJv<5$j5KmBKT2Lse6isCMafS#&?p z2sO7LA6}|z;d_PFrSC0u79B1!7bg@?N7<9$f!k6tq10XKgD33#vOVyg%rD;q|4D1b zgo^x%6&0R}Jt!UiimqJOLcQE%AsWzzY3c^`J@qR!w!peBd7ZLu!n$ee?Ca*Q%U@Tz zu4Y~BI`_Iw>l)VWSm#~0XWhYdhu8Vm9b4D3u5F!IAGO}RK5o5by>)%^`jqv``U&gP z*H2q-U!S{v{`&m&>iW|4HS25FyVq}8->`nidhhx@>kqC!yxzC|*!q_BZR^E`s14=~ zaT_cftQ(Ryq-;<&0GM<9#Y+FfnIap;r1V0ZhqTbQR=7neO>l z4ew;SiK{!_L01jGCajxPqs;~P)Uw?Ad5wo5dvSk-XY1U8ONC9H75DLgZ78k)jE!=Q zU1(^7tZ%ZhK6Qvt&dN96X!9=f-5rz<^#sey}CX;Brd%A zUIA?xWP1)8?Xg0(2We&h)%@n{wg>g1 zZ585R)ecf^D`Qk!CDOPMCzUY^8P{FKcNf#!73!k9T^A5mi+{Zn(248#G}?i%jQ^WD zaUCzlxRU=Vow(lK3Iopn(>ifkhu28I7o!uG`Q66+F3=ijE~HKz^xjpce%|~SsUz;T zJkZI-=!gyL>xT|@yS|q7wLD|!qjRmVWqNb4-EHUky4&ym^>wK4=NdbA%f$%4fRI%=r!rjldDtjopDmsK?2qPuw+#EEAFT+cTe-* zeSguPeci0vUqzm5$fvyiJJ#(JA6%H@`2K>dc{z{dEtuOGcB*p;pRq7&;lmG&&CAxq zP<1{sD3u*pv$A8J74 zAvYpTrD4_lUP&5O%qvP?LWHR#LobkU$H**Wn%4!5pKo(zhr%iHnW{R|J~nwd9!p`pL+4e0vG~! zJa+skcpZo@Ls$ba^WOCj>Be+@{x-h@dj*u`F}KS7N$yojJ{#h!%fQ;N>-tn*n;7G6 z1nh^xBCxm6u;#2efHq1=_~wdv%`o>hb6xvRP>c=Xw|ViwF2##=hZ}q8YNxHdtV1>0 z_o#|U+rTwe`tMC2bDcWhXwyO4#!z;R0eeQy@lG>*&Z1L=EdQV}Hf$XH{VoUZ`8Dde zZ|v_(w5e}fuHBzB)@uSwAK=3JjAygc2K^a3Y_(p1PqoEs3k3`9Fd3hn_MmJV@y~X$ zjfe1?Yw=kYuW5FiSH_UwKJlY=^p{Wf72rBu!e}x2<^l(HN0fk{8hoD4JP{rN8#%^D zW?WsF-fe7?v?oo5of&K#rC;=UaC9Z$a>UVBSqWF+&QATnEL@c738So|rNPkmsz;mY zKn!5wh_Yo8?BnT2!FOvKwXqihXA^A0*Q~(FBljZ~K(t7VhCSfkL8j@!J{4VQq#kwE z3Ax5hJgJ4nZdD%`+)(mKS`sZ&yg2fmLH+|j71K8$ zu8wDrNZfvd*W`pxsS{~EHl*DP|IbuB$KZK5d@e_#?5tGb!n3PDk$w1Ql;Iu{rVw7w zRXA^i^grnJ4*I8VM!gF7hs~{Ui1h74yr#GQ@`kA%^^rbiBUT3Kfb#Dkj;kPB0CkU! z+Y7;=>}$9N1p1owkyb7wZ!OxfW{)F7g0M85XJ2@tU{L`b;Fa{7)fo+pzCL8rA zYPL{l=Sq4n2%M&R;dsezLF!(v$YJ?|zdhd6fNBXdY$PbsvF!P@SK( z>S>dWetL}gp-zQeEBuW;@MWd#a1m_Pt6-mh;FKm~+MhrS2YH4r&co>q8iPNs^vBo$ z{$YV0Wm}Alqs16axzd&xwxTR2a4s-)KE&BTyvxDWft!W`V>?qswxmz{X5;&GoQvI~ zM{ES>Uw)r&NpK7;wZ4&P-M*X6SvRiw=&UvYpA*#$k;F0^YG?6Y>+9`(K1q0{P)E?i#I^x3}7zIU?k?drMverjl( zgldC2!KC8}^GjV6_zW(YE(l-Q7)LJPtN`nE34^=P2!q)eb3ttoX|vTJxP9k=dx@}T ztMDN~oOFlRYh!(Lyp5(@ukMRjjJEGay&QkLVP6a$8($}y<(Y<@e`a}sccg!dbTkvT z@<~F;!E;D>(~bIYoFgIaGdaGVMm_hfS36?5&35bUNCW?QB?4!w$T{9P-m=}gerXP3 zOAzi{JLXWuD|sk!HUxRq9oozsOQYneVW?wJa;br4XDMFmY&-laEx-ZJVse2u6|XXj zY~+!32FXaWpMvRLgeyZLdc@WN&hBVG8+A~&l4S<*QTeVR$dA&#%Szr2`i0HJF4#=$ zvVwN4(kDaRCGEc@EWu;pz?qC_6}r`fXJ&+i)g5-uG0O8X13XOjq2)aElY0?#pYE@l zbPrjlJGu{rkC1JN)5|*--gDraMLy>7k0bE)ki1KlAH-|aCisH@R`Rre8`cJ$H*&mp zMi@@S=hk`BrU)?6w9Oz9a9m~alV(|yvA>o>lurI`y=EXVI1>nr6IpM0pEE( z4}4r1w@s%vqYn+^5S}W;eCWm;t-@{z;}fD6>Rh z{Ba)Td`cZM+a=)$lE(>aHsEvGe`Dn9L2DV(Z)Ajsm2fIXo7d)W5qrsp;9HGvgwxmV z=&edP=fb1#Z6g2UdHqPnz2H$Eu##n*9(YjI~wi?P^rFgAR+p*?Sz1G!kuk~54*ZK<|>cco+YH76o zTxqms3!R_qGC-$4g~VU-8wOe+{Qo!ijzZDrzq@zDGo(p>dV7s~n6kZCiv?s((k*2& zrkAh;`A>GY*Tg+$j0YR{m8naA6&J^3B+f3%M_G?rLe(rk$b7X)`s3 z9LwB84vgnI2sFe;o&6j>C4Xo?%cmq1+~?dsLmlJ|+kpqlO~gI=z{c22l%Mch+S_xz z6Od=4fiG91(LSDi8ThV`GrdoUd&x^tcBEG|v0vCH0bY9;@3o%onV1V@UqmWc3kC2W zgwwD6e6VeuD)EPMI`|;_fxMA@LmWyN?+${|-97&d_N~bxuTD1l|4^>WvgmT&xAm>* zwp_p_&!u0h^L6eG_Q17B(fPf^zY6|_wn_fzHSSw>TW$c}^Z3@BH~)EjYtEbhBKJ+Z zEzf>&`=6@2xymKJzpZc0xyqIMyagBTTf=!e0Q3770Jkjv;|ni8Q1%7k zqdVW7i=aQs46f8SjlO7pzC&0DM-Ka`n=yxPy3bG8n;rYHGgW;YNdH>NkID`519?za zpC8E&vWzxN0iT~b=w6GW#B}D_*!G02t_}Xxh@nCGMCMy&jAtIu=@9M>xY!2L8EH(m z!Sb?UUZ;#m9LR6;jq6VCOLv>+8vnPTJgBb&52&}p|B~}yfUlCrf_F%m9tCV2eH{c_ zU|%{E44g}w0x$&SV|m@dezE(~u2{sv!r7^AoD_gfr#7*Hh<2C*j?TccK7Hd|IFC>Lqe$xoxnUz>s216AHZa?S=dFn83AhrfM#ZJnBWB)y)OP~$^7gf8 zrus|A3Bp@{DcXf}yQ9%A$kWBJp(2fTZ5P|$(JrTO>_giBXuJNG_~}UcPB+fy|J(d@ z-0+#Eu9q~zJNX3pB%jZct>-%pJW4&N&CCWbVeE0ariC2Em`cnC{@W>&w-g!kbravg zL7qI)7-Jz6eJQdjr)&Ncezu}_(NKg0R0tUso6 zzhfoF+Ca$nQjg^8)LkBdezz_*Rj?6oMDtGtt<2c9;64N*x8O0)8-*@PK;6RjUV#{N0Rog$HqTo7drvbFZ6s z>Suo=X3a46tF~CnID+*){mYO19B1uP9~p!n;zs+XJ;Mb&xl;c~o#ZeVXo35J+#hVc z4ts={9}p+p27jty)LVC**FX!h&$YWCo5zc6ANIilG}Tqk=lZ&Gkk@(~-<^mx3LVt| z8K+G^{#W(*i7YGM-MNR#y+rOg{u(fTKsY};lNpD*x=>`FcfSU84dnU3#P{;yp>--& zp%5;{-9!9R>oY%!PvJ9V_NVb%;t>0QahIqjzL#)s(dLHgkIGWvz`O%pC(fLOaWd<5 zF7xkc2CWb0p{yQ?YGN7>a1qUZMg0kQb|KF7Gnf~chTpaVmTK6YZi7v#jNuwKT>N=t ze2VPLVBK^E_LQK1)njTPRuSS$F}4)P4ROo(Qj68jcxH?-wFvlqOzFh&Y2tb5=}fg$ z*n5Q|wiWgzWvqsRN5obAK#!PPu7WHw5b0!}0>%Jh+_LwgdQ z><0JPcVYe#q~U%YaXt=r>U>6DKb(88au0#=s)Em1K^xAB1=iXFe26-&Z`CjYYjet$fi(fgwG;Ns9A}g_FSn?={1`O1HC-)+9C-jb!D~dqjueqwXO9t# zOM!Q`q7?%Lz9(>gp!`?_`Rm96m30j5I<_MR#vrcj0cnFz`VTdSBDP(E6S@lSJvXBa z#_3gY7BA0wr>>+K@if63hE~zW8nJ3lOi{tx5OWwZS#zOkI|X>Sx9-Dl#)%2oay$Zl zwG!=&j*UUw*?~f9)#Eo&j>b0`ze&z(-qR+GDN~l^P1_^lO9eAp>|Vtd9RYn2>S)3Bd7&cu;yHR~n4=fcJ?Mp;hxqhWqmzUg&oTUVbC|;c-ZW3_ zG`Vg_62C#dqO2!?FGW0y-*w4xSa%$dJ`<<#{2?xMf!ynN%^N5x(H6uSa=37>Q}aYo z{}{owOkD(Q1}sT>KPtxa9HP-)*Sr{UCF);%{Xnre`~c2J?=NDI?+>`g;(IG$KUQr@ zfX~!W{N9VQ58&UE&mop0&WPt2M;}=8aZdaqoD=^j&WT^F?zAqk{gDVZNqO7xs`L0#0lU5XCTS6HAr{K15emS_CUFu zW68$@^|7uG5Ig@zaiTsaM(ju4dcbi2bmJQ$(#BmQa-s`{0YQg6CG8xci`K|HCMQ@D|~0ain3p-gsUczZ-eT8&Bk*&X2SV#Q%zA z>_F`iJ)RxcfPwWO*MgL_sxYR8qyOr&HiYlZLi}&U19!zFiIq5mJvv`CaZXujpa2#oW!$jW0Z-{M)`17YTZ<+xf)YmKkU$=W2vcBIbiQ1Fk3!>e$82WkY zcB!Y#S24%g8|57MsM2U#A`r*Z=e0fV_1d0rqustn+t0i>7tGyg`wP-*xJCm`ZT&Zy zkK#W1p*^PizAO#@1>lN5Y8F?Z9p2et3g^G8(Cz_PcOL%)G5QdD@gU%iiNpC?mkG!A zJmHY-{plXqSs^~yi)Qg4z7tm`_`O${1NB-_zZG>`0izXgSpk<7a7i6sG13EOD`2+f z;5YGtwpr08>m}glGeM8A*U0Ge9g%S2pJ`$**2aIrnzT3KJw^jA_>QKN=Jul>NDE&e z4*ZNSwDF89w(L^jhy<*4Uv=Vq{(RLoPmy~eHf`IfO#HTTj^^A-9_7Khcs}TYYfiRP zyF#16bEXKF_R!avPT;5+zn$QR{9TDUtELID9rbzt(mu2PgZ8r9s z=qhnuI%t;f{@$KZ=Wnle<=2_TC@WHw%Dpi;w*>Jd;>L-Kyi0!f8hI9ROk5Ms#2s-> zyb_nhZCAWg<|AG$axK(uicEkW8Z@&AH1jBE<}o|y#^SZ5fHu~!K0D|~0sUASZHwKI ztyIvK;i9`j!PV@YB=#@eA_)CGja9(Wn!D<@1JUytkKs~-J&=re8Zag3kipuc&z>M*vN zfD7$pYbIlyZqEtJjlekbT_coUxF5eZY&vz{GR+%pnNBIU9T59K!z?4vckDNBYMA}! z{lXlPZ6&6%KD$M zAVzUA_Fqu`Ocm!c%xKFXz9npf+vJ`F`;_0)kUmu32I^&x8xWqhLPn!}Mjaq!wUsqWB6+B93g+V{mBe14f!_8F z;gpB)Z1da=p8E=TZkC_tf=*UGC32g|OTkMzcfif;Z z-}ZprQsgB67(M!RX2hF{O&x{xD)6BVK9lJHF36jTKQ|{H#k_Fz^c&%kOZ@4#>*?3n zwXxml5~Ix`wl`qgM*e@*+5GR>JxU@~|-mabS(e zb>ZU{@H_68#sW8HkvMw2g7q2bG7is;{@?NV{jvT#33R27*7Zy0Tf3obE6Rq9uJ4&Y z9U&6epbwsn5{Yc@YS__YuQQfBfU+&uG&$kR!r9070gh1o;Jzo!;`KKb!80?iJZTp9 zJz^HC|E>tfmu4Gd-`@9-SwyNjeN#_zHDaq@v0k-Z{vy^DuYQ5p>gZ$Ggpu~v+@_5U z^c`YeW=MV!)~PFULPm5(D6)@3e`^%%|B&CJcFJ#|`WJW`o5&Z z$1aZYVn~AgFz1%u;40Km!d431mp9FYZcfVnnuZmzt zctLQF0^C0a-1h~+eGlNC0=P|BpZnpigB`k-r}H_|KX5AhkbOxwiJL%wgrZ-x$97(v zKYtN8KZx@cz_%Iczo`4KQ{@#j<_9M*0c`4c?Vw(|5pLtn^l*Ltj+|N|o>BAE5DmZO&sEGN_-!W%Q z4$vC&Jpvg#A9L9v%w^kAF5AF5D4);vVol?NOg>P{q;3NFP1$i`NbCMLOqer=%}w{3 zE(0&U6ta>PJZtuRuW9H_@N2Pqr7ZFY)omdy|#JYH= zEnkJM%nn_d0$rH}x-tP>nXeIR=tiue8*M9q=N#a1H)KcPbLh{%2emKGxx?DgR&||7 z@LnU*T)joYJbZIajuG{vL6g0pcN%S`4%t?7nMmMSWkrZjo<3$E^jonw6B4?z9wNa7 zzO?2>k-+yanBO-!>|Waf#cS*9elGllJ!UZ%_*)e;^V{?i2~-Q$)fqU`JVrJ(e=)Aze7v@~3XEZ3^T_*85Yh*JehW zVuU+PKVG6j0NkHj7OW5ojCt@U@1^?Rg>*I={wOt_M`2z2u{Vu8N^yt>vZ z!iHt^VY zF2&mXA;`uf_KDn2V-(Xs%>SPa=_fwj*iXzE(qEh$5+mXvXI~1MAB{Yt!;{3lSfAd6 zc6^5Rzl(P4@V8^iI>=Jj>+P7f73~-iFK&T;i84d&-NNx*;Ck*;Y2uL|0UuZsv5hFl zR<=dU`#s8jdxSY3Y#QmtZ~fqL%S?OpN#pW$ywl_e9^wcC&oo<2Jy0X@Y99z1~;!L|X@<{d4Qk z-l1LEE1a^uuaqd_Hk32^%UJPU+~@irXJMb{yC|!5s~PX~d+Se2{k)H?QGb3DV!qkPRmR z#{oKot|pOvcQfe1HBs-siQCeIEhk=FhqPt)cG4kv7HKgP?^)(QfZvlNRnsMSF2(OF zP=1;p4-H-L5bdY$bl}0v z4}ia)r-?M^38{Co;XTT+U4^|m^H0DF9x#i(Nvi1zz<1X*QI5WS6%*ynon^}w=m?TmF6W0ZVDL@B=DL@Ce0H($L;>Gl0MJz|U zXO4$U9I*YhcAW+|UQmuL;A$&b&Q0sDP3;>BaY=c`Ef^yF~IO+Uui13ue;H`3!oKkS5MHPSuttTsLk z{KfnI9%&ih?~z-z6Mk{1TZkU%q*K!8eZyiTEtP@SybIpOeog{C&G@r6_R5)F)2q#9 zu>^Qsh4+63UP-US>5tZfUcsZNTY0W4z5WI3@BrV$8m_hQw`i+k?IKY!z_E_FVp^*TjCi8Mt{JI3)hI`*D|!`(L`?YI_%4eTp{P zQvGB5a^XlG1G+~antx&z$taiphI~#Ri?$DLH1XXI@Q%w-PwP;CdlLxWQ z9M@*>hPjtw|E8y(2eHm4zL7YoQ2-a-yC%knp8fWiY4zFP_fGKK_P@ zG`q!5uac*LUP-qp)Y*gYuR1e9T#EjdEl%s$Vm%8f6>svtl6cF-w}6j;vLHs z$RzsyKzDpIz@s=nJToZlEdCUabzZjOwW2)Rv;C69bD)a^l=*%a_^A7F1mFX{Z4B~VT|AXw%S;D0rE63Vo#ZZU&z>-_WslpPqWi%~YmD%-vYWsgSL zk6~Wjf^x~vSJiix9pI@fTk`C%B$jEb@L(;6{j&t5Cmwcm!E3ai-$_{vW!FB|S)MZ+ z^A7gNh-dDnkPg|Wf&K)(!$+fk>1As8Eg1h=Kdm!AXoY>g zh2Q(C;d3y?sS9QK2`Ha+rd^|k_e7s^o@aTS4=Of%JtG3RPrt)y;#fNQ&Ksuj950}4 zwrd%9Twn|kU#@YO&)2Co*9*8Hdqb|Z)l4a{kuN{_H`V6sTVN}_rodKmU4gB93}j+c zflY-vpE9}QGOR_uP;EJo&7B;x_kWq`g3L}?9p~3NC?h|p!Y1Y(*rGsY@0Er%%vE3I zRpL2%f>W*$c@CEg^rA2V z@7}ZfR9@c+;HSS3jy_fuGQ8Jnz6|)nTIUYH^F-aLv3Kn3E2doAPxRc{4|njUAb$NB z`1L8sP>%pd8FzvYK^{0f(JZdZ5V?mydxx-2B|o2wb;lQw+j*8!8)Ut>aI9T>cuj5X zx7#wmz`1ra|CvF&6XyYZbKjJ{uEHZlWI2J5-}kT!$osB4$}Gow!e%F({csDy7ghHOG9)^>d`Z=SpXd)1g*mw}#7 zu8kEL`1la&IF52_tRmqd*s31Inrt`b{)fJwB&efzC5eQMut{Brxv#|{a%rEi(H!Qe zByB*4Y6fqtivVpvKh+C!!%KI^i%P(;;;k@8Z>%{+;_US*pV#WmflVvU?p*;LS#Q9y zKXss}#@cj0;MosYY6=x`5bvI}d##9XnO2Q;DPiSV&3V5uixa>B`S;1Yv4?$IoY|P64-o?1>b+yRd7#-oL z^0%QLciD!~I2Q?W%KnM*;tTMEyU>m*oPWi2qzl(wzHeuve;V40ljpZ-I_u zAMUj0eG=_jj-kgjH)YTVK_?5a7h8iiNw@*e3GBJNhc-0Fb9C=hDQP38pwAK zqF)Z6yjZ|69>3@Bj1?!IHH*ved;fE2JK9S*nEUvZ@o3Mj;oZ0Aws>(D%KQT5!DhfQ zf9C+v4|xf1->0xfxL(T$wDAkj+4XG4XIchnd5Q^g^c1Y4f%hq<-KMVq?{%Q<6~Ha^ z0JL9818vm6jzH4JSM7No;IkgI(c4cO9`M_Jz-xU>yl6oB%Fn|b*DrtH)Ejd_Ebwz2 zWx}2yJR9XSK%ca6z9}Sq^#y%Rf&5Qh!}9*&jxR9pN*FKmnx@>T%li?a5z;XGpY&UX z^1lSWA3{4a_M1g6>Nrk(MVlN?2KWEu{^CWz`Or1-;u!kB4`6+ANO*4jWb{9-KETbV zFKcuAfJR@5$7DB7J8+aWWNr6f!>P_DjHV5^}y7usj5OQ6}$8 zoPwUGV0=vlEb~Zwy$VgaO&B|UdMM#1FIB^rL-%`fBE~*oGNb;M#uyQU`bR$cM-yQr z{Sm&Y__hLg8uc#hQUb6w2}gA>Y`66n+W^~1$Y<$*tuJ7!&H-$<0XAHH0UPCqH4TVU z^14CC5=O}BkzpQ(;xx^`P%lV#dY_T zH38S^voG_Ht2j-<$Mt#y;RB5kz8VkY_p9SYFQl!(T-<_jMLIEGw$s#?zE+dncbh}rtIyU}#qFOPthrZ+>Mr{erL2@mwjZFr9J^%Vl~ zWU&8{;65UhYK)3C^LnxKl<2}AEEYV#g6zU`dhU!-EloQJfY=7$EHSKS|JyGgS zF%NHD8)iEmE)xCxJ=se4T1L4jJxMj6veXooY%u4ji~Ao6^{3NIDtZ*W>xM z)TJH&F~0#P(6yd`&b0-4*sajb_7W~r{pf+B{{7V^j>QA0>-Z{NmpmN(d>sC%ls}JO z(`f4jyd57?VDl{~uo1V!rOli;be4UC@;8 z_YB(C2Wiegmb4=t(MHHl<8X1`aGnLa`vd>VtVKEaZN_2U3$n zG`M3kWNO+8vTeOk-fvjmJfZAHS#O~%mZvS%%R*qjwB68`$oK0SO>)04C{9m1;9`G! z7MWq&ggpv>A8Ui#Gwi)!Qv*C!9)lkc%7tPpo#pLr&`i6ZHj95j4ySFBtn-)0GS_T4 zGyXW_=@Tfg{{0xS4fx!Do34|`yCHu9ef{-z@Qj0 z>U=SsKE>Zh*@5yUj>e)6<;?h#sN>|P7{4fg+wCIvd6c>ACXq|reU7^KVo&@yc+vIuNZZx7n+5Ct1;#gNjqB66B+$q$XEGdE3#@tP%vjP4>0A5gwEph(Gh=(A-?cZ- zNPFBzxNnWV;&}C-t_`>!0WB3^9~tkhzA>_A30)?7BTnVE<_cc!LM>DA%{J z-ZaI*#?+;Ft#Kc$HmR_4blF8hEyg(ahPvBpqTL_&%n1k2umsFQBe729x{$Cm0gkr9 z0^6F`wDH`(p-l(JMKNLwk*ASY)x!n>a3o#}`-6In!+OkF9@rx=o>nEsB$k?bEG_(Y z0ne4MAdcC~{lvZ-`pNmll??l3%sIW(r6y0kHn&%TYN~p9P)B_0J}==JJh1AvL5v$e z{SuKVsw}Fl>W0oVy<%0<-Y$7uX6V__Cdo^IJ84IR=WJZWqjo#?{H-GG6FleOl61EQ zei^YMjeUr{wPCd9YraO>AsPL!VINJqXxc~T`?|M{egb^dDBXt4f<}-7I`T6btEprx(N5_xa@%0t^jVFC(6E3?IMleAH(~{52~QS zQ<+@*e+M*Iiu)zFX5o4Z7t`^(12R4HPC^>C^Cr-DG~j6M?G0b~mwqA#aLBZ<>7eZ~ zadJM}W3;iu{y4%PV_4cOtTo0Htb_a(>O4#r`knUajuc^YfrcEn3R`xHyeE?OU2Bmq z#@~-fR|WVvZeYKZS&84fXd8_4EjebKUZfobn?&Sezk9@Q1&q*IPv*%ykwR~*0h-dh#DRmL!bRXNSv;B8Fe0ziZZzT@=;{9LpHaqd*N-@#j*u-yptJ(#aWpw9yM;cvDpaCd^% z_*?{<2=qH_2QU?N9K#_dgB#2fd18TBB&On;kLQW7n4cxz%@d4MI|siXL>~SrFqPxI z?RFExk*XV-_4ueLQ@)>|=k$^S&9LHSVsG5!1CPpWb%hwc*p|6@3spu6pl%A3ZSa`SHOa zYJ<%SxZ^5pEC&Y;U<^A_ZcNXyTe zIN!lDlKemYL6-IRozazrcnz>JzOuXUwZemi5la)6X5)OMC}#>zB=R|5D{3oBD7F`u z79Yd8NNFY6C8Z^`C3{M~Dp5;oOLvrhh|`G7Wz)-?Wh-ztlDF(wSyXvk`K{%X%GL56 zI8EqSc~r%uiY17&{8Giiil&Nq*R8JUt|cy)YlCZt%jf#a6;+v3Ikhsk(pBlMe5vwq zWlLp5ReaT`stHy0s{ATf)rP7aRV_H#D85>$&aU25?W=C7mOTMtU5Fpi>NM4*HmQ>e zd8N`}m8WV~)rVCH)#=r>dYu+QdtI?Y^{LSX*#&0c zs}@nH_Y_SpUsCR?nC9B#nqFP1r%e_j1!;5D!|GS6xuCY-aDk=JUbq9NP)%Dpf2q1O z$$6{O>pbi{=A2rTUG!ejd&NjD2W>QNJ0MiR2ajV|yjR$;Gy6VPyh(G;+<=p2VMOgl4$Cq|rDFoJ}@=r0LA8=XH zbbe{UTV7}VS@d*#-}9`GpStG*H_FYFiFV*BpuMNhcpe1j;z-Dw zlvM(DX`G8)w7(nqOgP5e02h3+RjeyKd>6CL@J^EAZ{YC?jT;cCgU1oEy^2YH`<)bcj-ny8?MhIZdFYenjVfeij@1O>1UnS zMj`eEaf1ET2&^k*IjS*^EBk}}AmbcCcBCB#`$M*+puo@;rUm>meL#MqOw2r#iMxf< zXKWYNR0`!`!WMzG1!Zwr-yma5aHa{!=@O5u2Y96HNjwst1;nK=#y6v_Vgz)=7Yxsb zI^I$)QB8y?4*Of|Gnqf=46C?4snYjF)@wJ$8z=6&tC#qt&5K^9F%}KhkFZO{z7noi zM#3(<3!c%|pb;|pLn60t3&^?pQ%HWzKV$1LOoh=SzY@r0b{^v|4V1z zwJZ$>s~9i{_Q-=E0~02$=OxVP#u&ZYch6*Mm$YYUbK5f|E|Rwz^2&EXu{7no7Gu0x z?UB=&+WOOSZN_mM=x;f`Vv0KG4`VJN60phlgF4@1+`%SRGckrEX(K=v5@x&c3=x@k zZD-z<$SdC!biS)aJ>*T1&^yU8=GPk9)dPJf`x3B5;kpEuOjlz(`=~44WxFt@EWl|f z_?y22KNIM(ort9)zjtZ33-FL9@>{e|>+eL|XPG9e6K3FMD0!QQd@9SxFKJI6fwd8B z$YG}~ePJF^b$=KgM-9iQ`WUh94F*M5_=xJ^K1_B2IfEoI2y$kD-UU zK2>i+YG)hB2cAYd3OJq{jN`eNP-8vNLAo0HA{Ki;F;MvWd!FwnGBHjWo4s{8X73qc z%1!r&IfkHr(s0RgEXMPd*l$v2#X5q%^}zT!@=1*RuH(f>JA^M3Y>|L%gF>G|(I3}< zu5c1Y!gu87F^F$umUCVxxPtrqT(sV!qaTd$$uhz^@o6aI!Cl-TE3huv-WFp_AJ&y^(d&`r1h;dGmPs8f+o0>ubRDjg7lPBmKgp$blNN0z z3;~|E9WZjNYIh(HbZ(MQaV!vD_R#tv;w@wumk`DaFXJrS|F&Ji5WsyvH$~hBzwtVe`P$vRQgL`Jfq*)o~|->SG-ep3Y2}ma#@zEk-iw6 za$;~lUUYfg#Wxgs{GvzE?!^lHzX9iC#DfoX?!_GD_R3fUj4i;}Iy@JJdzWfdm=fXj z^XL$A*$zCB7rgS@TvT`oIa8I_9n5 zIU+k1G3m3;6@OaKRzZWt$ z(OylxP1q|N7ebG(!Y&Q*X9g*z-WL4sx^ITP$jXMnLiO*7ZHQE4``NF7IW8aY1m*xa zfBX`CU=a#o<~k_S4jKr@zE`wRNRyHt?fP7ay#I&2yN;@(*%t;4A-KD{26qUO;1&o@ z0>OeqAh;9UEw}}D_u%dl+zB4sEocG*Ip@7|-gD3W=9@LM=8svm*V^=EceOp$U0vP% z+f{#S>+Y|z>v7u0c|GRQW8LX-{`aj9eM9g*&I96EJQc*_GXLv(^0Dmm~n-eeUtO z%AaZ2(*9PLdCZ4@Z8P;xnv;ybrSW|@J|ELP)L_-==xY%fHU?|C&djjnRjA7tqG&!?FL5 zb}Al^$G^@8kLCX3aT@y2ChX%i<71gI|M2$Ac!)K6h!OTngfRcsCIm6NBJ^<0_)z~& ze;5)z+@HaGct2d9|JClmpM90}@AqQ<|JKInw}-k$=)c{M`$t(4_}|Kb$9g0FLmyFz z>sSzfmB)|e!DD&+X#DtlnCsMswm&e1pdMpDo<0@8@_o4SZGWuK2>t#3;QGVwhc7W6 z>LZB%A?@+s>(T2Ezx}yHXnTSOEA-G3#J|lq{om96z5IWyvp$ynk7eB7)<^fhtq<+x zLm6~0`qy^uOQR{Hy#l ze3;jx)nhsOXTOU0d;RQTJl*3t4Cx^*?6Hm({}4C*r|k0Y2tG_S%@tpiPkH4<#9+&r5S^MbmIPS5Y@>mW(e*ZZBzt-j7 z>PC;-YslO7r(b}F>7G5bZTcsMz<^hX{;z!aljgzgG1mA`nm7MU^Dytf()?AAc)Z8; zn0J5nNw0>#ZMW~kGq}fm`mgb;e;@ytkGc=;kFhlW+GogP9qs=Q@gV=He0tnB|DVKz z{5e+tt)C9R2e1FDc#uE&gWmYJ{CWD%m>l2#5c}W@A@t992%-Oqhj>Uw^_Z6rLz>6o zU&qd4xf4$UfrbBYU-`Lc@BbJR@@L)utvvW&#f1Dx-}d+N<6mP!{>SkT_dOqDLjKeE z$7AKMW{u1M=Y`m zhs}d}7;HcMdHOJ1VTOP}ef<96wemm2S7bem6MJ|D`uP6;BECY_((%ahS7!Yji2 z%A426+$Z88T4crN*TY(}`nLIJ2h;_?1#XM(qyqv#00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AKI|F!_czrCC`LPG_EiR2Txg5LXeGEG20aQ#W4BcUdBfAh-h5dv{$lq!*k zq0jzRW5nyc*uFIGqqF5srKef2gdT>(UlN53ZKf$VCd8GBAx5mbF!6X?@b4KQLWEFy z9ZDky7fIOi1G~6+B4k^zW*d{szvl6@Ks60{!p{u`<(X{B`kXN%R)n>r96wPw@I66= zIO>n#jY%1szL;C>yXDKZ+kc+d`wkiT9b07bI3gKSE@p6MWm6ZruaS$lwX>j>Pp@iHyCRvx{7z|;v9ue)$Rft@?|lxa zw?`6_NObhJ+kX65RLU_k8v8(gJoCDit(iD~S-87-2>(@Mxbde7VJHkLx0;W3WXt z+!S@g{5`b^gomXoVMa|kcv4`=PnB)04s!G|+Ldt1m-*rtSIfjKg95NrPzX&$FJEru z2_t`#8#L-Qm-a}Yn3(-iAFZP|UGA~^jj|y( zRJ;%ZUD?dt+k9-9i0F9oC$iEzlA)|M{V^WH1FEmWY-Cv>oEO@v7LnG-3~%Y%py!C` z+lSt5-j}uYt!2rzvz(A|GZdb9K!5E1=FR+8jTnws=R(N%iGX1D3i^V@ylq_+!a?R$ zjG&)k04_cHD)WbBX@QXaL09wzoUQiPIH^iMXDeCwz0vXnWq2i%gWkl}GrmtX>A%(B zqT&B)t+wZTPW2Ane2v{PRKgRE`M3?SAI2P;Vv9@zs;-Zus9Q}xS9W_6Hjw($6{OUf ziQS$Ww3)5OC%h(soo_stPlm9x^!Qxdw#xb=aW6+uV@u_y(0>}ilNL1`?Rhwd6PeGb z#=_O-Hv0WGX$y`2CE(1)c&`DSUT5=jRV;0c&Ddj`eein>1^pRo4Q(j2-Rb@vp5iDr z4a4I4cgL~ntkc9wwQ$pIvkcD@jerF|czYq7;3f>7$r@{0o?+Rr-{ZG_SPeD(o>&8x z7t6J@y!C1cnfy}w(e3EXBOiBDc^oV{`?}1g@@Cwts_KZY=$BtjOBG7j)|B*nB6DO-@A1p~Tg@drluP_F?g@U5Ct4&p|6wt5kMv3^4>v z;MKV84t7MoVt|+piJ*eO3&l_G0>*u|e_@5~Wi5;|R|jX(we?=#_;IGyuEeme4GFfz zh~iM+^iVCf;l~Cw{*vR%{cwq;T_nD?oT*fwClZ5xbonMj9hd49Jc@761T%0LV;det8uH(Zq6Hj*dQUhT-z@TSXq80b?k*Cz2hLxnsb|ENBhdshF7b|8hTQA z%j-YHsLWr|yICC0t2#+veNm@&MIK%8HbMW+h22o4*%MOZ8MO@w-cQ3TC4ZacMq}S+ zsHFNK6Xjnf`Z4MzBws_oaj_07`pZ%LZ}3=?i6PG2AcPobNftGp|{+yB-d z-Bnx`zi-(gM4rq%s^&ytt*d{$mBC`>tlB>B8U34rVk3MPQD^Dg2hvSU;4z?!|?{bV5VC%mX6ld&WL_S#74QcAHV&Umw>qk8v(W5hv@q5 zT6_OqC<4M3DbdY*luMVvxT0W|j_A9BGX@d&mRSC$1MVu)9-NJ7^5`A$5fuTF*wdNP zTy?(;LZ>l#T>I_2f-z#>8RT5Q-Y4F% z8%C>D_ttCOgohT#LQp#;%MRG{#F^G}<)RwluT-9Y-lPbJkJ_*gSuhSNsT|2@_WY(v zuUNn1;G9lf{nhl-vVy~2DhX^^q{k3UA9>+B=^Fj@AD8yIt1Y9`I+xy+(7fo&676qf zjGauUFjBUuiZDdN>aa^oXp^Btv{9qHa-KzJrnbDGHL?*7+$g4MxP5sM*<-)|?v8~l zsf8k67nPbqoUuZ{e5W!`smZ48JhZgU2FJS4Y9yST4j+4F6IN!jl#I%N#Cznh;AbqK-NEH>h!Lkh z*J+(L*>_g2ZcW*Sw=N{9Dj35Ovjg?x4JI^t{rW5|O_bV1N! zA*Pvop>;)Fno_etDqb?jFtaYd13}n>6ZVmjPaF?Plo=lvYO*U$|3yo zrHcGNV6(97?(t|#oLpIurYzDDG?nu6Y)F`hKv)ZoA|!rS%BIG64v8T?=L)-_2bsAp z5O}ZSXlx?bp=;8R+%7$ru#>md*GBl8IPPKut8$b;$(3c6tiejOdndrucb*Cfs-^z? z9nV74OsuCI?39@b)oc| z#JOE+@No-w^vz)T<3)R{! zDDI{diH^fe&D#p*$1f!iV#vnHz8raLV_a)X<!zhZ%cRSmd&~jAc z`YH=RZa#EL~MV+u>?5bYy{3jaO&7UlV`QIykvya0~B7n7B}Uys=5+ zNr+LeL@I9$ch}OJWol0O77??P3LWX)xl@79jq;F;fD3orJziUT^MF!gD<1v`>hxZZ zUqRh_7GlGAkHfUr?Frwjn1a;SPR=`>`RVg+cYli#vvHZ$sW#5MF$i*Z9z94(>QBo~ zV=&^nDjC~FeB0s9Ax9!`sFekAN>-%;@r@N_?0!E(6dK_?m6omzQwk0-%;{6pd>Qxq z>$vB?Csnk#e!~pO#+I&^>LlX^X$Z)<@T^%zo27Gz*rb|F||( z(>^I^u={SweNDvU-B=f8?;Scfo9o={PJD4nZfnP=RPdnMWYwTEcC21HAf4|Xf10YaD8qjW zb%%z9K;cEyWTyK2yT`Yo42-Q@R{0a$k>RP}51TJoj9+YjhsS)M6&f^lJ_*^4!jYr- zQ8&^;ksEWMO7Q>{!c;fn>o)2hYr9itZT>FWbD>I_J6wlrlV)O3|H_7R=myl!KO`_} zT!y9+gDyQgs>gP7?lLJY@PU2!dEMfu5tuS>h4G0g0f7* zWT~4BSK-L{wdNC=-L=8G8IDqtmMKT^9P7Aj-HQ1sCDu*E*(){P9EG7)<|cM2o_fzc zJsnbqhFN|c`qgMYe=;vgyCCm;4nuZ!;f8|>(8zHMNh-izE;A_V zK0<;N;#eA9A4Mf4pKSR(3bk65QfoGsgYDM#!ri9QYLO)vzN0Y zy0yLxl8V(a?MMI0-SXLz9^n_2#H8VcuQTs$FmrC2+1|u5TawlU zA88}bLdj>VRy9yNzR?@;^(m+=-0AuVO@;8|NLXfIcHW_To3wPjl`FoV6XJ|cmwfi) zV6Ct5YpO1%LcdeomkfW?Co^&?oR8rUOXh;bC z2DPC@0Y^;BJv|eFq_&{Cwdm8H&LyiH7i383)(ewJ3iqJ;v$U`vVL)lS+@5X3)6?YH z1nKCdomil!vfcp7#Yh=kBUO{4aB+;NWDMq$=xBrwESZBODT&!z#4k!^Yv?+r)+h9^ zHB%Zt>G-LSPHm2b)~d*yw(7*{Q;)H(Tg)`*)RwOFpsssp=^rRow-9loZ^dWYm%aZe zihGat#BSrZnn`;lTm&kRovh<-Okb!wQv{B7+j4hrF|lEW2UYI;!|T}!|CJf7E{BSr zO_r`fQ4BP%7Y`L8;>e0MYYM;B2PN&zY@MAMZF-3x!q9(y>;95u`|amkcXmQPIBfx` zm+y6v#7qu9AlGBY4Ep++9K*Mu>Jcfw<&R;fXHAQd=_}45#g5~??YTu z(gb?G-urL-p|Eva7_|n`)4mPJu1mh9uCWjni?4smKA)p!*DS|fgvYqIQ)=`ex)5Vd z(hYYm61JDUEyPBaQp(?*qA8cA<8^|shJhoq*JcTFLsJ&>(+`c{Zgg0XqK_`LP)pNl z`R(H^93arefE@e$$^$=kKL5v7dton~(Ow=>k+9lKcSptMcUZF77V9*(!NT9uPOFjiCQI3EiO#{c z6olrG~45^CQ>PKeE9X4TvC6Z@Jy`it#_Sp=r>z#HsKrWJcA?CVbD=9K_>6@#F&4qoSOe93D|DxtI_V=nX zTrFrgTe-8@NM6KpLOtSSwvl9_Ah(J}4R|dMoojmqXpA4!@;RtqMxZrX9LVF~6An*b z-I`U+MKy6CVXkzxQ)=SD%O2`# zp9l48S5}3XQx$Ppjjo+ZnaRzU0Yl~GU>b6d2WE{|rB9rR=iBHlmL6f#o?#M5)gXTh zov}ED{?qwe5i|%7rO$bsAHK@kx#>oyp~U3U$l1T{8Wflr98TKveno9eEE>cyb}8+= z#KQG9GELICvOf+(nXG5oxn_U>=A-}I?GHPbf+>ob6Ud+1;$8VrMY7VCN7p|-WN&zk zmBMZjUawFZ>pYL}*k<0?UpeyM7w}M(oBjUOu<@P#t|%;deaYmvryn^GYd_BM9wP)a zyq6TG{3Q{Jr7->N`E)%&=zZ>OApcJ!p~0{BN6u8M2pT@o*H5_)o+{QqL2^L6^2e`w z_e?q<_c;sK$jbFDRyrd;on7yRe7I6LJy zWuJOz$jj?)WYN|McCvFVvxt3;l-^$@1a9y0wxFp7gX)bEQ&2DBR04>CYY2jBr$cao9oVL7>t;pLs zRf`ME{Cux8lZ*WGNvwBABV~I(Y`}ChKb->3G4Wr=yA>T_J= z58c(Fp(${9JW>YBnAn`jgL8f-cw$o;z0AXI(MRePeBqjz$Y9BUaPRPJ$fdJ!WpWfF zqX_byT>XGo!p{1A{*bH@=cTu!=yR2)`meq5ZVXzBSo%MF$urmzSbT5TKImdw7CNXpdoIuGSh zkRiNmJm;4fhc>NuBi|EnaW6NY&d@VFi@a9N`!+9MSH#d+S7@D>%d8L;L~d+gq0~%Z zln&j*K1EaT?c`W^f{t#&v*pP|jCxeiGIiMbD-NNcK5JQzB)js6c>?K~a{@1uTd9Ks z-@I-eiu;$saPxfED#$qgCTWn+7fFSC$r-q59*K{o<8d>@pYVBQmA!LCAfxhWA2(ENg9SasZCw$Y4;lHH zqQ$0#br~_IZ{H8m7fquf_J$T+jY*`Jop9_!p6uk&FhpB3sB zov31*B&Clk@_2*>?^r==Q|nzT3)JpFSU?<3G!xYMUyYNQh_>AO~RWO#7nm#qY9w^LDN7; zaL|S6OY^NeFkX@h1t0ID&6e3f*RJ5*+a5HbZ#m`?Xq;l1$jKvN7>wHK>Co+17BGcb zf=4zxKV~yipUwy9-yOVYldUW7Mui;4t2|#j==Iz%BcxE2xh*ZAdydHbRy0O{1;x|_ zk*Dt5?n;}il~EfuUaj1kLP=KsZo6D#;oxAvShTn91V<8%k5UE=YUgmYIEUBu6Wi-# z$@LOrzqP)ZjHJ=HC=bggO5PUG9}Hcf^bogt%`PHwYMl|Hb%j%n5pletp3Khr)8nxP zW%_Wonn5w3oI$h)tD3%qXs;xkbGox~%0e@b-5Jtk9PS~>fu_Y1meniK6pg2*x%k=_ zPmBzYsNgbtsvDdIv#JG6J#to~V!IaTCE;7R-gHsNgdxuzJ^V@2puyMjC*D_)^Mj#p zI8WZCN`FK-HGh`)YvjTjy@Tti)yP%LR)$C!UJOgGRWO_cb=7yFYW0nAxXaeCg~UlkP(I}fQAGdQy91?!86Ww>ig+V%uo^pj@-ZUgKH4_N096)voxaqK>V)(9$u|qg(B9f zc}*}k+Q#QaH3&%QS>7t`+`M*sImn|2F52G&u<6=$8H;vK>Gp59q6$32Gs4$QW7>6Q z+flg0q)!D5&-!g`ape<2EUZ|jG>uiU>=|H&cCc1^NZrNBt^_z9s8cjjMT@B0@7G-sBU9>VUelQrKw~ zU59Pqr*&vEw5vE3W)XH(x>6ULH4HwwxDk3K4I-FRbYo+*XCzpHX(bw)ADh-%f3>XpCY_O4bwh)|&?lR& z0eWUO>B^3C!9lWG_YF^m-nT8c`MoJ1>(HrOZL?)&TwWjj{w@0U*<8L==!XALIqI$C zuh+-Q)l*^P)O?)?Pgrppq+L(?rOLW)abPACI_wXz}8 z+7Y@L(-jl_AVWgs?aAyCGwN#MJ4hVF?;z;KD5RN0>RxcQhb@YK+MrfNsShW##8R#p z>oMJv+P|qko0URhsXzaN%XUfX=G^-Bu3`CZgI93;Mzq-(PiLm&P}DGv++Y2}_Cc3j z2wLKs`dv6WiHV*`t@3#&?xJJGImW+YUb>`1NIc ziSuQkyt#uazM->Aq!#C`n(%F+q+w!u^4-wv&E<#`PjW zR@wK}I|tX=&Uq&9uTg^QXbKc^rM#BUzZ~>C=GhKZ_$~3Tlcs-^NM_}L|1e3@H`Wzv zrik}Vg-|3dce3ODembn3Gx(H8?|jm}>V=_{AfyD#5Bcg05;Mt(?$M);eSTIQ8!Z`p zzo0Q?Pr^+LJ(+qcp>MaF+hp@>zs5N6e;7+^t>Uz{Y^@_07iTsmPTgBS|1t>aAu8TM zN14s{ah7Wh*{ zI0mfGTsB|K-FL84O4nN^PZ`kQEdu-$A&1ByIX$=I?q zGCz)Nz{H^;6Te2H6p~Bj{^tNvTnu#%;j2u6u2&=8fy^~yzXcl@!niI-x3~OBF<+p5 z45q|cd=`Dc&BklmB;7QI5d_of;!OuFL`i|9a`Raaf_e6q2Se9rj^yIYj(g22GGQ~$ zM>^!s>jhtEc=;6UW$ESzyqxKXkjED->(-c6%5I)see&-|lDo<#nQe*R_dcJXdsp<` z)QoR1o35aW0s9J3O0$OIHDP2}+j=jjT@jX4@pM0HrZ@z~`hkD6G~4m(+_>@G^_%qd zFF&d@S$U$c?)1bc6y^%+bruH|SkPWuyc$OpxzA5%XRLUdT1Hp$#wkw#@q2ix41*3y zop$PG2-k7kYxAe)`Xh@!D~YPd0#EcZ7{6tg_1qyc7GZIY6a3^te7LoNY|WIepfJJ{ z{MJn*RJ53OX`ZoLwvoTn#Q!QKr5%GEHDb&e(n@Nw1?KEUD5N=!hB-SQO!~HWpq@c- zqv#jP@mGoU>RvR?hh=@M#Gk(wAyO?>4HmK1)?lIB4X*~(ZF3$7G|_$}>Ry25Aeq<> z3N*k9e)*K2Zz!x*CEl%h=iJ@W(7w+<`Rb~EmQbhM+lhWq?VJ7WK^k|Z^~eD?!mH-r zi?^AC?X`HUrNh$PTTYVD(Zxn{hAj&m?#Z_x8=mr%f0RdnH_$?f$Gfx` zu0g-7)ig6xCR2-EpXU$nE~XLV)65Ag7x4eMtI~h=2yfJ1l4snLJ{9=UDol9 zSn6jD()l*am-=tf8MSkXw5t8za#dXp7xCmTtY>rRIUJc1XbiX7;0d}W)oSREd=V|` zD~6rG!eCgYfff1#|(5Q|<-5SBQODc68q(LpUkt^cj-2VxBotzVgLvjUVaStd3sWRtOM>Oe)&e<-n-I z#c5FU`YcN_GRu-jVY2pAn9}c;n7N3qRC=0AzZcPuH;Wg9C`<|oCD?n$B5Fmhy!>lT z@PcsB=pPf`%}s8+Xr_?BP)C95fDaWdLic>7kjYwTJ0yChmycBew|6U9bhDD4RhAod zrLOJhU!)QrwTI}R^z{%srIa_6hThJcG4MGm(ST>QqdB({fZQ|tYtTH#7)cC{d0fSKQL6^MeUwv$ zh8%+0Ny2RfGoCi~M;=dwXsid6O>T-qqrJ)#d|>Wc)+Z4CM`E^N;P1MR4K9f6UqGKv zghCf=yc0xYI>B(C5M5ZBWz>hQt3o$Q?!h+BUm_V$ll2qB*hxXE*Qrx}2VK;2kLFrs zdRAmVABRBT^rS$CaPt7gmK=4mXsl=1(mKf#3$1F_Jga{RJ}4}@Ytujyi`~TTwK7XA z)fE#?t#pyVb(?~1!?9ly^%(kSv^kEh$HG1C5K2s~lG~H1B2g#qZ^#O@N5ehI=NzRd z&+T$Db+k0Mo&|)4%-?#uqWxOqK!sEMId4Q3jbZ42c-d9G=DN>}GHw>77{{%owpVBl zx0VH$*!y9x=oODVf!U0Ai?B1)V&KAJ*TFZWt`MH|u28wsixX?fX`1Ix5@#ITV)~J{ z^6@g;R}>Dy$M&G==L}tcQs_1`zOA+0QDQbCmxY^w9-ukRx$J`I)V_kHV^(-$hk@rc z@)Tn(ka0D2j{JUFy+?@Vbn6vTiU>`s6r}1?RN{?sN;zz&KDF_o@09@-zIPvbwgd(^ zGmWrhZo&^wHE>kw^AReE?4Hls`)(iCVwm;WYFI~0NvUVCdRVO(fpv>%cM zlXkZYu6a$Mim8%|9!-`QO2!FLnDDfT(Kn7;c)oX#7-(FQEM{GBMIW-qf_*Iqw;y95 zx8XR&UM3a+zqiOINvgm{5>exAOuMfEsE5%Y7vcGz#B;$#e7}q{kA?~ zPI^%pqiD6R=|rS?VSUHPlvbQOc$(<_YL9mgb$M|_sCu5n@-1Rpf-&0rJ+ zrp}37l4+sC=tX-P zDZ=!mG&+Cy17%r_K=lpVoqu?d!n$L4F!Ylnd>_rg*3OkI6NtGFwzu_bN+VYeeTn$R z-%>E`Z$>viM)`k8n@;{p@VedQT5L0RhLpcOJY`)<=Rg=Q!Hv7LkR;e`=>oZcNn*3t~5(_Q%1j^nUxNfC@km; zbZkSip2UW{xVAme9oLkv)kTBNBihcX<#{c3I2Zou*mf)>DE6hNjo`&JEp8nAK_axS z;-oc16-RIbG1Ke7VB-dyZ?s7by}lXoEfpxn!x{(CjRPNB3=mAZ8M5<+IAF>sf8X~$ zd!qswe+YeBiU@Pq9LGZxWg)7N6t1Y(sO%NFh~QITw>ud|D=52C#$e+^=FNQk3Us_IveReIWd$nTw5luTb#QPsFya}(knI^sICrd57Z8-PVEmDXsa(v>t0(bggT_(S+mt-z5wvGGid$-#U zK#f?&hG0{l%*ZmBS{r`NZ7P~;c!&4m{uTxHn&cNrs|y{PMKDKDQJ|3Go1B7Fn005e zpQl%(vn&gJ``Tx;JQc2#j>uU%8xbAwZ**PP5j63WZb&4tTsv1t9jQj|DHg^&r(1*a zVy%DA40zZqTOuw+wMu8WsQNqgk~*EMw^|`ea3eDB^R9N$qDsjeo%%65L6MTzHuT{X zjptE17I0yX{T@N-Tw#bZ^4(_{6n@`VT0**cne*#%#kXL3VdO@iusf*lndQCKXVQ&( z=gmED(~>L_*}NMF6ZAJ~N*UDaSW>lQQ%FY z)guH6RoS@9)P`T!7Z8K!BAEiW{QLC=O*nhsulw%k>@@bhju08{RK9gdOx~C7T-fO)~jVF2n$BW{ht0lY&N-XuO&L4-6(}Qw{%~Z>ZH<>#E867prw|pvbk@@qks`Hp|f$Fj(JEq^& z(N!m9YJWSt=Ly_!-xp|FD||b_xiEY^UDQoqN^sROs?~pkiz#H-4m0~Z{i{T*)!r-} zN{m|!dS*J#Q@RK-guNSl+#*w|&|a~QINF3@ms1!4DovQmu8*?UsUcV{uU{{Y3H~I6 z`@J@k>KqDZ{?tFqR@W?^GnZkqDoe$Fwb7DwDxZ#N-9?u8+34=H$noMkJAvzI-}98{ z7Y$;Y=Q*(?qp5lwkBy9dxQA_tm#dne)_taD?w?y?r;1LIl``^g5>>3ZZkeW-nrp-MQ>3S z%#xsZeF=R3@&-;t1X=EmO1wCYu8%x9`2y1i7dK2YN}fu*-c^JN{bHZ_=IvPNsAYLr zMLJP`oCHste5)Dk7u11s1fmjqb$VZIKM#f{$)^UdCblgOyOSx0y#iLGZh{bhwwuwJ zn7Xkkk175rSCJhn>@thyUT59y&{W^Rq_}A+mMyY#T|9HHbdu3s^L57@g|NY}XwvV6 z&c`zhV_3Y^R^M07wYpo2h%_rYRY&AK|03xdF85MHoUr(1amr1{>ym8_wz|(6-EHCa z;WEPqt(HnRJJmalntRS!1}yIdE9qBw`h_qFroSMr!ord_T^Vs;qCAtq7;Ds8#p~A4`;MbG9SiHvu?Fa;2P9V zm^7`QXzbs#T>E5Tdyl#3h${OI|E@QJr!gW*cwG~*MqNA@W&DLv#vm$IO3=ak<95Vu zWI&ixR)4!hZaj?1*~(np@VshpNQf6EHOif(=nOVgtySd6fZz1MkVj)P+4 zDm5%o)jpT4%1msBXB824u{j z?!7H%QlvgZ0%UgImziKx=m`@ly4U*g{9_+t%7{+IG8Bc6Y4uiF(jG4 z5xB5>xGbv7TT5DJZ5eUxg}eR!AXmkh(a@T&MV#KmUzUUHrRUSJ}&tEy;04`59Nw&V<<<# z#atBd-{aoC!cqOuUJ!0}a)zhVTRgn9Fn51zO0;p~sU`CXg?L$QboS>ba-2H(evQ|u z1}|aWzF=3Os!Qc(*wPEg93RrIpM9hM_L5J?`;@UT&m1y+o;~tibIr9w=j$9=KcRK5p+=7I^i!y{SV1-PxrwkgcSJaZ zeYW?R+hfN~d_!e}(Dj%I*otRxNTd8;4w;;YzP#}s|M3iCb(ZD5BnE5o^sm13&NK}c z&KNisxkg*-mw}ca-~HA<+5LXn{EX$?m;u^P+E$6NA;kyzr+UmM96iluVyJ3dT3)o` z`?<^7lou}|5bR!hhzu@vIQh(crcIVSd8H;UZhq+Z2~O93sGaJ@=cnbbK}R>XTHd~6 zoQtMGT(hSxi{!)J%2y*iF$~K6%axVYl-Ht5sq%M{Uj`9a1k$s9uH7{oc&{cz2`19C z^mjN7+XwYulqY*5QJ5q@`>3Oi-m$#aE7~$c*zS)OfV!~=iuK12d zn1z9B<-!lwiQ1!%O1@ZIYr-B-&FIE?hrnZvcQ|BePDB+b?ZQ{zUYd|;!865DAZcz| z_PUzP?R}iNi4RpV4|ROiVZSkIhK!udn)=FBz_jVwOXN9zGpC&2u?DN3b*{5-_o!eE zg%%lJ((>=cDZC{MDt;rcB$7n%Yznb*jy=AW#fCwj{Hu}Xhz`&8RXM}wQkeeFwdt(L zgf8pP@YvISwFXzLeUf1f=Zor%&=wdxS~8+Zd7E#P_vOa0l;DLqBaGcgh<;7I%S77878<`sqM$OFGs^2X=AX)OmEA)6`8sh4^!C`#MK_(WP+Y zMm}bw#bU^XMnlPw8Y#G5Hi;;^siTM5TNNMl!5dS9nDEzDPNwhzR^dmEHM^MAUzw_V z<%8f0sHzlnp&Rv)Uqbb!{PN?LBb^eAJKWlYkV(;h5d@8&Qm2-Sm|1S*Tc8y(2^oP9 zNgzvF9IRT)u$x*B)#ZIZFjN*eg5CP8qA@=G$+ADhJBrg8x-7!Qkp6-C4_KcPyOpt; zLOw;SX1^Ny=#almnIHzeYCqD~^HJH=xf-g!y&EPP=VmBmv$TG9Swhm5fsj&7j!)kXzIv!sB+*Oh%it%}!Lx$xm2%9o9 z=k2w~r+PKl)C&otUJgQ1Op#S`0wPPXE7;#vxKdY5jq8$w0?d05!)-J)MT!=skG9EC zB`=!zl2Go#v-HOq80rQMVEF|k#Ls@AxqZrlNp{_k$w%Jb6rmT!d}4d}-8vh4+8_3~ zFa`&De9JZ6sGktyXuas>$U7DDhYIGpuJTq>Gaom)eiiTSOID@890A8v4s_N57&`4& zy}}B)Qp$+g`-CAs3&&J93tEX|8RbseQ9@$%)?}+22DZKA-B>pw57U`;UL6tIl!iJO zh^f+B^+0!vb@_jDdM>{`BJ~i9N|U}g-0)jjvls0(BwxpRfqWO=(r=pM=4hJ2_z`>9 zm-T8V5gn_|#bfOHg>|6~lCrQVI>l+K}N_ zGA1VL&*c`V64g$Wt&GGuugY}zkJxYUqMczsBe^kf5V0H$R~0<{33zT1+!GOIg0@+nP^Jjuh!>DJMu{zP zi}1rldr2tl4d(Xitf-?dk&A`Mz^ffH*{k5FsknGAj9Zf*OV*m?wrHd-Bd1D(zE6rd z`u!x1n;iJ*5XY6hr_Cv}qC2*VE4NV?DB%kg@wws}f8NO(brZvPARdpe)TE}~x$1RV zSvXJKk5j76EL6PLohYl?bRVQYv=#QEB{OoT`1Q4ieeU%arqB{)&Sc2(c{IiFSfc{> zOHJmw6F;+1{wu3`qMBI$eyGTLmO5*vy(?Ajuk2bZ9kHvvI&tI!s#g*YLxP8KFeyf2 z?d&hJ&LzIPH^`K<`&z?E7Q6T#nc6jamTx6*q8*&8xhR!illh~YBGFCyyoowjm@BFi zapDxTZ5cVvNIT3?s^ADK3$!TIpYn?DWey)(UJ$&vfk;~=Iy6q)b&5H?bM$>n+D!Br zC+H_nHE+;7s+q(|4iyoFkDOMakIjMu2~rlbWGLcOaoQne=@~H{UWx^{TI82pD#oxm z3!hCm`p3}GU_!2Yl73k?tBXnxQ4e`)P%L2b@@Va|W<+j=-8?%of-vV3b#d-4Z*$Nh zn$uM(8TDI2w5bgwDv-r&ZFEGTyTh~*Y;}D0OjvuaN+ZAAaEqh47w1M7v1n616$vpe zP3qO3w7K|eb@is_hJr=%&%#LxdJWbqc(;af#~rSgfWqT1c(uTE-p zuCjDzojGB3_+!m@^i!w52OT{#4MEm+ch8C}t{EC^Qd`WIv4Yp_)h$j6@=e}Qj?=$% zD{aKgtY#LiK%GzG{vmD(IWQsb+sRE~;1Yr3J*2v{RT}j!DvUo|&wBW!=Voi)IOP8U zGeFG0NqhqtgR+esww-JBHZ`+-D&}qXUHt}zXhnZ#mLrJyB_ zCa9ZhH*nMh)`iL<8AOz_hb4Pwf@C76!<;BaBGg)OY?t*p-4riS~Rnjub^Bnr>=8}hkhb4-Zl&Lohg zNq-e-M=wpe2YFsd^b8`p*uWvZI^p2e9(gK{Tjo6zQ;J>6m{HiX^sve7s{{J+>9%wD z%U6!)yV(miIuu#>cvDz*#tw&lz1U(87mN%i=I`N5v>{8lCx}#(=WZ1O7D}(<#dcl; z)@S+<^h3rXpRA z?EXcvAa)8e#v$_)cCkgQC*Qo_5>=FVRhh4nove=Nhx__2Ecm<0g58%_FAaP+Zr{^# zH}XQ%J7&;jFPCM}wC6}PS~c3n8r63UZw5?0)p6@F5ZS=+)0O?;MV*6Rj_4LG&Y!fj zF0p#BYXrK=Z6Tt?EfKP{@th3=poBiomjM0^`v5@?M_Q)AAZML>1>RE9L~QQicN8(QAJULOQ_Vb&&M8%%WijhI%b(_|63!_Cx4?O zFm zp2Z$%^Og(MIQVu>>%Op6P(~&(VZ`X!Q^cZLx9sJdeSR(#I-t%frJY-{?(_xS4Rqp3 zJ@qHz8Pc9zHp{5wE8ZCEf-o|-ZsPdmXD0706VI$|aOg)cUwqvQ_>P7Kb3-y8V&9nF zqyv7xHtix9b(ZcZx2RP0tW$&p8+*^8cN{V>P;Uy@b9Dd0S9BQ^rs*f_)BTl*Y!cHtD1B*$j*Onh0Mql8krdhbwy>yFQV(@|Q{Yo2YC_oUwe{< zP(M5)>k=tN5i5bsR`}rMoTR=o^(^5ivxpXGG)Ve=5sX6_7I%SU0hs1_I3>JIP4}PfyoQgj z4gcKj$EgMRTlPfJ?RgHFq8%(!$5JH!9I2t`+RMTJQQ zdR6x(P4iBb@X|IPb3%IFcmNAarO88*w2oRuHRRH&Wa9UDt-HJ?6OJgro6^8bd3PTY zY-q9Q6+>$exE2VZj)W_WsKJuKOk7avp8e<7^S)mRs5%jc!N$C)Tv@C zj9cWKMj<}N^+z#7y3EuoH7VV@(Hr5syXGM;%p_c_e@p6 zMv9bdilAg z1IdnsE<0#A)MBoh$rjTkg+fX9Ccd0I)AW5(#?w~%sfZcFQ+xBwfWm__560T!o%X^! z*EV5L5P1i5k%oBRbyK>7nSX&P$>hS^G{M!UozKt!HRst8a}V?pm$Y%-o5n#r>$Hke zn?gw}52a01G{uNQ^}f4!vsH&;e~s>G#}kpxLlZbm%&qC{Nd&XJ6toa%53L#&0A7o~ zj+~YDlhf!sr71>Y4qa#Q*6zndKN(_q(eA7x+1BlQU+`oF2M}QCOHi4{r!465A$V-@{O9cC<6l z8j0;^ih;`p$B^frcB^{3pR-1@j%GSn;{ojEG9vokT2nf&=TuR=qlompG>Qu1KYvsTkCmEWmw{f>Pb zg;L4t=zMe*a(#o90Lo9ziVqW^*t4x*$FW;&XIfUf%La+*S zmPwRUinu#go4(~M2w1TG3BrLzvRq)=G{}?q-1ERMAU#FCAgt zJ?lt%QOf{EZ{Fd&|3%Dx3Ty#f%gpJB+eiB$7bbiQ2QW?V;^?}=PwM7<`k;*oW-JQ` z(T#l3$|)g=kar+dMAcAQ%3Qdm(4b^+VAZ_FAn={-(*2Gfa5D2ksr0y!YiqPf>Eig( zftghrM){W3w8u!P3y#6`JCahH?w|xu>e%4G&WW zcc_a(6$`F`w2<6EM&Oc}>vF%v2#oYkKEX~%LYa+Z`7&{<&&Hm2WWJJ9M&sZSI8R$B zhI4siwPx87TD4jD(}j>goM6I&RWIm(IoH4Z{R7xwGgN{mqsuW4ARn2#Hjh()3C_Nv z=&Jw~Aj$Pg%XegD4Px?B>W}rtljDoCkn~dSI-@IpJO$NZ3CztMLW(HBGRJF1RR@?k z%zQUc^q$pEvw3`IBb_S5dKKk`Ob8r|Zm+qBkqPcRib)-+uZC{-PXLo#xk(PS$F#`3 zW2lnYuwiP6@T;nq8bX>9(Lo^8*-8J-PoYx3Oyc>7Ew$spEt81KP`nwRZU} zH%2tKp9g`6COFG^X(9xPU#KG@HCPO!Lool{?bB?;ji3P_AuxXDH@Sbq)Q_w=ALx_2 zl&O&Vu=y0`yNJYvmmcTP$8v)3jFDi`MbI3C?wV!~>3>Rs#0ic~vQ;DAYf2o%pNwNQ zoi;YR4skmpfczJyeGMfi-I`t}$o;{Q9M~Bhn4&m`X`G0q!5&#aaBd|z{Q#uIcTo5J zxDUA4rT)E_TK#p$U>?O{ehN^(wY!xp$^?f=)#s-+a(bU zT)fGCk=CN?W`D*Z;SIq{9AzM6u>wC2AdtuNatbnK#csi|CyiYR^;AC?ot6(jCG;+7 z+9QZ9?L~9zSA8@aw$*yY&rI(EY19O0A_QNvsleXBL6c{`-hli+jFx6{5&E5l-#hG3 z1LOigBlTdplUXv%(r4LD69~_!O-y6o!YE>IG4#C?o7M*U)L61CO0FE~DtXhO0&6dE zh1=eoa*jv$KX4sqA3+GEbiki$1ow&F{L)*)GQ;UP_6q6!EiL1Hdr2db^u18X;3#lw zHuKaaK1C}!6Ft&xcL*z0HRCfhD1jr>kS18dd~~-OB!9-Xe$cmOt7Jfn(K*}aCy?CQ z7gj-J8{iTLX%r9kF%$u-k3jZ8JJ_ z*C^$uE;CSJx5%=zminGIN17R64dO7)6Qkn#sxH?4;`s!cRUv34p!ZXn#yo1s#-=$? z_Hu%oBZb~3)OG6ixKMy4{Yr0|#)l;q?peEb-B1lIvV_!m@LU#-P4eRq70;5c6er5S zy7fjvJc%4$RycgbRE>5^2u1g>*@l+zQI_SY){6>3(aQ4^sa@Jg9V9T$c0n@6OH`9P zB29RFHvCG6?Q=6`{@*lG#v9CCX}k&5T@Af*ul*w;-|u4A;_GIi90w{OeUvptg3M{l37_* zX&a;T&&m{7mDXWciFnk+7dNqbbp)1T2vti)Vw~x)HWzbjidYhfs!+hSFj`wU;~5$U zJ#+c0qggcL zBv1({puXXgLnsBP%6Ar>P`iEaw`R^5eYw}o=caG4X|-fdMIrgoSk$K4I8;pC&d?G@ z&j-s<4?hG=Ji$dx>fNHIy%IX;+2XI6tU;7jc!(_uQFfV+e_>A41L_n5U3Eo>Bhzg1 zhg_b-F9=A$JN(kgKe?!QS%tTe2-a!%*47?Dukuqv1omhK2OdmyaS8;d}M}U z5h|Bv<{-bOkyIT-6zY(uiEJ;^oe9-~?L|8bS;#^!_l8|Q4?rNTn2r~fKDo{~fr}#h zkvUFpsU&LJ{%T1Bv6hITBpoUXc|wK6rX_X`7l3BwsIzXLift}~8Z_MDaJnLZ?*YzU z0K6@rj^l<=1?|T(8XyAz2!Skt|Bz&(qWX&*fEK9}E3c+{6p^)CgOq8VnT;q!B@P3XN61Vx4e5?}5D2 zEp_3i0=O|v2@PhDZfbYybf=ltvRz`XpzG{k=nQe6&d}qQN?MOj#?S=+9^rTA9*Oxx zJ>QGHrg;Q-6Hl8-A^4hJpnc2u?lYlr<>xAYXsyycbBgpc8&B=lPdIgoo+`lOUSFW; z#I=>J(Du|$IXEpl_zbOiTk`s;Uh%a0C4ot(iRl464@-EG6utNr(z=rNZP6|b?&_@+ z0{BNbFXeNoNUTET(#AG#jYBY-XKIk#XaRVq;P%f}XV)ndt#(CGZ)0d~P%3;~kfEaL z)aQ`3sDEtN%2l->02U7t1iu0MuX*{U%93vHz+?GowxxJ*OT$bd%ypJ;R5ZGq(2-kJ zUxFZ0>^Etw{}H{Ngs%s$7ftU{GoCx#6tEp(wk_6LJTh#~Guf@U@rBZe=`~Xd2=CYs zLuUTnt)21pCD!R*9-~>5EhQFW_=W2ir_(i*_w{1vdRURIkI6ZEE=qdA#=3p>npP72 znCowAI>|j$P?;zQj*(`yj)b;@<}=sKfxOH-UJOFYHUl8S59|y>T?Ho&Cgc@Y8B!>t(YHkVb$;Ix(TB7q zbcxi?b1`bOSCGw(IgW`!M|ar(sFQ=TSw#oEV}VP0V5X%pc5{Xbc9 z$Jgxim(X_X(=(u)jwTy(LP(@Ciaa3qJ%soouFZFb{Ugc+Fu98M|6(3!wE z?}?Hs7eJzxCT_MQAJNV-g`1ZRR*JMHJ2lWhpYf5*@VAJi>$Qo5* zNKEIItj_OCVEJV`!3t(1erb8&m3I@m14>^9wl>iRP~2gr45WhNWZ}kF#YUWxV4@xR zoV@P5BD+)vDkKK0wKv<%XUCQqXI}uHjkGioltE&wNa}(AEuN}_*buD~O{q2_NZ#sQ zOWM(wB}ML*`L>T)?S)g5e})EADLWd$pA(A_)!!U<9h< z!_$nJf5smw3UB|)_77lN4N?RGEg0A;MMtuJ>9~*KkY~>rSwNR68D4vOg6jPm)>?@%r8Xqb)SCw7@LF+f5+q zVdyuok!jm&R8<0=+F>30iGHribU-M80XJB%Kn%1sl&FtP_do)zes=Db@)|9kf-)1e zX0DQ|yJ(`~VfLbJd0#VtV=1z;gtn%o#urQzG@~zpr@iQric~+bRlz)=9)li^kI}O~>xM1dbkg>~dvwOAFgMU7~0=d_YSDj>H6p>X#XL3boq9;2B8QBm5)6n-m z@gc)+Q1#Vw!x-~~s%8;$E)NZnES5upW5ZM&1y)_i4bof1KuAzz`n#f&LeHQfxV|o8 zx?gb7*a)qv1UQ>W*5ZG^P;otMjQ8vrTfEw7p3uSC(JL_x{62pGy-~Y3FtES_IAX@` zUTH2G_jeY_bX2=$O3q;zLrtx9_wD|tCw5ULjI4+2l+6!tWTx*~4QFtZNVOFXT+FdD zp{zI<#pIVMQpZur8&`agx4dIXytdDi5HzEff0qE-IfS9vK_l86a48eelkil@9o8T! zCb925LTsR2i$-?JNa)dfB^nHc(>@TYR~5hqv-_xIz|r_mc@BG#9U7D}qr@Oe;L;ME z>M^AFidO(sXimvBdWR7_KhlVOC_o|#C5{{jdi;tW(frV<~D5fbO zn*X`7IZB;~7(Ye|GCwgHQNY`KJZ&^QL@%&|(K%!O7hh#S7ib_BFp5DZi5Em0tQ{O` z%*&dn*+#%%bPMvM#|!}%GMZXj%qFXM`3&e3QFq^so{-!?ZM5ItmhUAsrWUUpFp|)0 z(PYZ2o=9{Ln3;u3@sgBbwOH?j1p~frkxJB*kgjem27tE4Fy1Y!=ZqkwN1lm)W7VS| z?Tl5)pa_oO@{trpsR7W7r5djMwMw*Hf+tNvc|p}Q#1 zwKa8CC6+F7St|gn6TxcNR^o3ry!wEu-b#QAB2+!0Um+AXoqpvJUQ zvAgRa#qpUAIqXe(Z3fGiJjim3+1g!yt>~hsku33yAC&rWzh7uqqK0QaR|AI}i2aKT zc5rJi=QRkoergkF>ZtocLjACZMPzBpDv(fFY=aXMmQPLrTrNBNuSZm>&9Vo@qKqYP zdxFhWrTt+K(16HTy*h{59tOG)z22r0i2SV0M?Uh(6*4R8IB=te9-+S&RfxqT1nUCw zXB+d)Q*zno%OocAzJ3RDP)(d_*}AZ!J9*;^Ub&vK>5~Ja7Z!+@(&A>tT@!;qAdkGY z!phfgh8=_pXZIKMG$$Ijl;dyQo=^u9e=&ayvwe|!d)R!1k#`Dy}a(xEPX;}xvg`{ z2n`fUe;VJyy3P<7alTGHSAe!$)6?D34~sCs(i(T-md1d{WMS_+^>@fVdIEvaU-Obq zs5yp;f4;D;UHtl;gGwFr`$(!6rJ+bGGTpW%%&8%;rS{Dc{j!5BHy!`TTMB*(9yVbI z;beaO?g;Smfze;@V?+6tYAEj^Q*}E<@++&%ZO0b0-LCw9f*TKknri>*)(r;Lm1iVqq6xnog){+(VmP$?(z>{_Rq?g~)Vu5`qK^5`E6;{XAC z4%%3>?RjHEdX^pq_4>Zm#493{->iA5{`sM0?l_#;nxAv#kP~;L2;9+hR(KlsLzeN? zwR7of45Y1cXtJ|WJ-)CAuYZ|dyI-%RXsCcV&{0a*-NPiV#~4ue%0qb7&?_HF`r<*M3sfSWCzWWj?=edS%{ zpo!DMCE!1T_+3KT&TR*k$eb>D4kF>U_)9=zGj6sfRSk-=r0^qB&0IU9bZ*N%CYZs! zGuMxCVwZ2OI7t$0K6UlYJL@STl9} zkzU>sOuv0pU_8GLa*mvD!dIK9vz^|#L3>Q!eoP+1SrRAy0=T}O2fm}vgfuJU6CqrH%Mv^Lc4;Te9rg_>7eABg$Tak66l|Meeq>=e4qmd4- zfxch2H84e>W$gxK{Dd}VZ(DwD>lg6pcL4KaYh*S&7UvEF!;^d&wm{E-PAuj$R%6Deom*I?2L-xi4jBH9%p|dYe{}$B z1`aL6XOWlK7k${5V@u6|P31S*{V#Gr7>M;R#E%h{iXw1J!HcTmR-7c7nN9pSHsz)* zntS;b1v$nEv&>=@&)1l;bFro1Ifv_&v`xc?DInKX_IRb&L9FrEW#no3aXmOAK@2-f z@LZ`qpPa4EKMDFZUT=p=@|rv|W<6OQ->(69@=O!g>ue0~-%Jyu1AF~46>Y=|gqs#`-$Bx=}9ppW0mVJ9D|^&i%e2rT|R zITAW$;jr|SO^)hgN2CkJ+gtRcRgaQqt1bh&U`+9Fqn;=S1j`ggiq7ri-rgP%P_*s# zSqDz1@s2-TFY80O;G-x|18Of{24~pDhkVLJ)Bi-9jB5@?Y$7fN745r&ETx+yqPTA# z*&b{wk_?;JFpSxhqQMi8FtgYlK&l!M7Qt`ZQte|9W3h1u+_?9>0Bd`9#7@c`zez2k zeDBhr^^L%5j->j+d=Sud9wrE;h?;OkXYILx zxo+0J=!@<5AWT~WXX=c3C9;|jgYv+rf4Y;~oN9oQjJ(_K7XB+39ec^`89*N{48Y~v z!*3$q=LPQ$`K!&EIy=Wf&(mA^#3_CCY3}?@2rYrxFaSU0@1pOcqr(}#x@`ipkkz+1 z$HDsjC_^S2eW2SQ0csWk8(g$GFMxZM9hWoZqH#pxh{UN?q|HUO&K?2AHnl{wzjD1R zY(L8tfJ!VdUUS-}I9h0v2SsDl0+A0tO(O> zI*^@_dc7QZ3g$qcZaH8Wb(@#9rkv1Eo^g0)w(QjPiGD}=d--JB?{4KMLrt3K`06-s7nEjXWiRzh}?<&|NacSpWlw)`=Icae9{-8WY!x%-Sr7KN|yzd8mm! zm|`(E{a=1r^f}q%~g=m9{2VSbx1B zrUtW$t_W&~*F*AtPd<1=2x>lQMU#C|YzSH+$5D@(1s1bBqhDR7+u>d0Hc(S{{nHSi zXL<`=8qVAh+d+DVTTN`=@T67}|HOC2x1`uEfhZc1$6anDvo6^-rwqf`7|_(^ZwSfv z%LRM*L}zdKm%4>p!OTTpG}VlQXByqyL(-DVw#i;LX^eD}RPWl7h~*g)rHUW(YQA}G^cR&ZQ%F}Zx+Gcg?s_#Nfx)#_l2{L^AQ|S6bV=3PERYmWe_sdwVNaLh^+;exO4i3d zdz53pg0xzs?VhOwe&pjPc3KpT@=mWLj|VmH49Y|pn?b&YBZAtx+gQXF-E~+m&SX%I z*>9Y=JSH~O;p?xn+IG(i8c~IE;SHqZ{^G^h!rq5ciE0Un{3W!H#-X=b`>*2w&VrQb#rVo zQ8DkK6;fgTtljLDHeBRRX|2#ULP8-A!|}U2Nn7Ozv5cT0R51KTn+zGiSCb9nr1xDkdb`Y zA@JrSC2o0Yj;Hr&u}Cl)Ge8o_ymM>9aR)?vZ)1g*MX$h05FvW>w@NQ8LZCF@To%Qg z)eTp<9&8z{y^_;Hu}FdPj3JgHc6$$$*r{cCpf8(K*KLI+I5r03Zku0RM({Mpgr=S(9s$%`>QZm@C`#^ zp36b?H1EtXmAJkZ1L5|iA9f(P)G2Kg%>0*o4B-GWCtvjQnfMd!U67(vsMEVMefM^S?W4gZ3CZSy}LgAO*u@S-GGzMzVJyyGUEis}RS?+&0h1xdggZs0Z<=6udDLGfI{hkhQlF$GWQY$Z zNeYpXmeaff^=zA#nxJXbhHmhIzmd(QVb>_Sp{e@`Qm zD6`QvQbCS+|KF9uv9y%ObD4CVGtlecy6A)1(ts@tJN5`RTh&ZaKH9fQK#8|thhr|N zL<3?84S2!%ISZ?p>h#(b((|O6lJWaR+aAqI$(Z^W)mgSl1rvE;{A>k*;jhl^l3*jE zJoDm4^Dc;z*09!XXP!`R*|FzakSAVm$cnz$^!Z>T47FX+faVfrjRvNkijG+r1?gi3 z!w9d%e?i()@hoWkfr$J=#z&&K0n=h-vJ8wb5`|<-O6y<%-H7F_!us&9K$5cyReq*%KP?{x6TL8%!K zT0i+pGns=W?G*9md^}V@p*|^`W8a0zpl+@S#pS`J6J{R*Pz&Nw7_Sl>QvGqDBsuyu z4*KEH-+BFq?#g_PR&t_;;k$lo>yT7HhHfW_R>&tsfPqc!P!iL44^q>EezFv=uNknK zsVH@O>)e?ouV6AJ_TsaNF;K--WL$}bX4BAq3_{I zAF#_|#nPG{diU}0$KP1hM9KeTdf$a0txgh_t#p!PM=bSRztr?k(;)XJ9=GbwvsI6q zwxFys2-hd+Ovlai)>j?gusUc&Wv8fH({b_h<@e;S-@eBUmmfN<{gYCjaTv^FQWr4J^mXs035P-Rm(WakNk1aq`lVO&ql8td zSwumUVJtc*3~EVJ@G6u5{J@M>k%(GMfUNjbqXNNJZ_o43%4`u6iC-4F>;v|z5%GXD z2M)?@bYsJrf3?hv7R0FC#cd0`=j`}S_X91^242*DAoh_M@NC-m>CjXa+rd`M1vBq#Acv~XY#K?#X{Vj90XB` z;-ypg=AN?h;+lRxwVgYCHjb5X5R-etkVvPrwL-of@fz`CjSS>4G_Q*wJ^2U@-U-@O zu>e$%kGl=j*`zL2Aj7@TUHsXdx&h;McPxo%KMfa#_@pT8?pi}myN5qxMSa*Mz2h|i zEi&T#YON5TRg4dbr07}Dd4nBJF8Q47var$FE431|_P*sAkjd7y4#i?TEb`U$L6fM? zSgvuDhf(iW6)M3T#v9e(zn>kgsq}WfwU2#lH4#ka8|EK@XA6%*1K6A)fYw=7ZM$XJ z_9}MG@uzf96=KF=C=|5lHHN zQ$kje`-{+Vg3bn3Ay-i53vF`e-x0WZd5r+;3lfobp(oC#*MKXznJwq3S z&@k2XOHcD>6U0SFgf55&qYv=yOzGL}>}Mo`u@*J3eew;`qN07eQ^pfZ zmf2Pj$kWVo%?p+oD{+Ox#w>#qiy_y|#bxhBEV%pCTQ1O{2zsK-zvsP9^w-!)c!h$M zT9U3vAHUV z7ZKgxBpWSo`6eB=cR|j)Q64S**1?88{}tW+%uB!j6m^{N1$Mpx=qM#Gi!7CQYnTUi zv(0b#q2}hhr)-B0-mT@onj9V_GwPbG7!gF@i~j5@-8x8~2mbjbt=eK;FA}tI>Y))I zT=5&(C4^}DLJcQ)JTB)&L48SG-F_#1Z;DB{Dd-nR zSasK3;ITz}rILwBaw=n-ee{MIbQ$I^27}&{I{kzFwDGR2f*#?%ct`vA4Y3%8>1)k_RKZ}BaPc1h6))i!jfe)1k) z@AmZqlsq`y5-DNf!m(gyqM_Qle$<-gqw?f%g(_x2rO!CNi3lm{tQk|5>`cM(1|+K_ zq!WDc7EwUY4#NyTOZDBm_`3j+akmzOlqswlyTE2DOqio;!uyGhRS_JTCvI=1iR75s zZf#t2lU&(4jBlF$XE<^vtMQt6;)f>r@W>&-QJasE1Rb$b#8~4(5oyt!QtR?_mjzqJ zg3-g{183Ln1n-j_tg6#7X@Da9ydi3NygGS-=YoL^mY>l}CeqyY1s`Te)-&5A0P%4osOw0kWL;0Yf>-lADRP zdNvGV&qfK}5Xq_o0Czo6)|h;!qKF|u@;H0MBlPS{%9$nHTg-5K7Q0y7XSIAO`c`S^ z0oN{+GRY{7`<)|GhZ_uYSBx^VPiS2;v9XAave-7>G_^ z!S5jjgbQEa`I3sPzy4WXJlQmFrPIbRq_rx_7xhR+py2%mez|;&kX)@pBo#=cPT_bxYZQwLPxrI| z4qXEyTL?m#ICL$uuzJ~QCQ95OZ>~K=(EX9{UB@GucE6Dg7h7_HOmIHzkvUB^g;o_n z2vU}N=!9z9*S*KwfsQ)sh$!I{N-Gl+L^>QljQ^-)_22(KhdN8abNe;&eZ#F2J9No; zM&^Rd?S&PVjxy}r4YL5{tYKVwpptz$MST|HO&Q+*R*w>Oqlvg996mk!k}?Xq9^zkT}j$u;f|7dv?5wOa>bsEWT+ zoJvb_#cG^Fp@At9(}EkD=Afn2-SAm2PGuX(ew&1-mn}BptB>k`YN_j3TW{+5HP-Q# z=ZDfselZ#c1PO7vzcjSDrxx7sv;)E{n`*V;fx&e?)8mUtITh3$(4?uS&TZWJ33K~P ze)cgwKE`pN-7>vc@-X$MZ6k<55_%BD=cGcu^3)Y4f49YWeO&w|s7GiA0=7$qJGgBn zn*+Du;Z<{lu&HK9O$AJX3lH*x7(P<0m zv+6hN%F#DzuT1RK==o%zkjdg(cM33=<1S2j)dYIiFW7`L=7J~=n9lv7b*2hpENT-J zXOH)}>b+dL5#+T;%DWO5)`*6Gw2R+gGVCJD8Uc>BzwrhPQh@i0B^Pe|ETWrX91&KO zRyDp?6ERP%Cp(!q=mgXS8$99!M`x7{(u7p3eggmbXrBh!;Tulk1$2@AKVIKGd0Ht z5aY{s_)KTh;gEc`&8oL8YgX7FB?!NBN6UhaX~sCN!a@9h?b8@u@6@_yyfJ0NXa?KS z_!e#U=)Ag@cQzKEs2dJTY0{##Ay|0~F0oj|Y4O=x3J?7nUa)_Up z2gXGUd|tNm#ZgCAoHHe#2G1}xnSe8W(}iv6f;jQ-^m~Hxp_?C$r9drpKfvo+tm>`6 zn2$#sv-?V!qU_t)IVB&8>%Gie5cK18`6adHC8SCVs!>lN+PSp)e3N!r< zGbSl05BaJ5zc%eW$OBJnOf1a2{!a>q;5P5@r(l=?(G2;HC=XA{pjiUY!6 zTBzKoM8Cp1@;^WefF8499hI%Ova>l|U6FUd%*Wd?zDGjV$2X!VS#+T}+XB+#G zryraU%W=-)9iMBDK)Zl{H#ip*P!S@g!z)hCUkC6S;>c=CyGJco?-w_HNTj^N>}utA zoX5RqPo`Fq_|bVmJA9AGTA=!NjEp%irwna%kKxkx*C0;Jr3Y3En}G#bZ7P*P0V-0u zX$LBsgV>O)c$|UW``LGAyV12%Q9X5W4jY5TBUgoIJ1Uj?sAqt>R-<{9ko%_w*P|(( z-RCyF`r763*4{%a#XiV??-q=W{V%6UYaii__)usqep`R2)jf$KQ5%sOlk@m2hN7Yz zPQh$}4i(vifv01tE?*aJ`P3=eSCFhgsTI`Aauv&c`AjD z=IQO$=`ZlvOZZor%iRd{)*h{20w(TL{cd|M_h-NQu}Sd;B&3n8paFI?hy2`1M_wgxW&{v3-C5X+C3jD`;k zN4rLCc$a|hFv-$;^`cQ$98u%m8+B8_s|9p=>GT%yS=<}0fK%7jnsE%Ca_z09wTybY zEap7lg8#VDYkuWVx%}(Mrph>|}O4x~*3J&>gE?ERCc0h|_&UB5l|t z9&6WdfKKQLSMbDdil~p%H@VftUPzb^HG3ySf$WLcO=%rg$T)V#qo|RDo3hiQE0paE zKCKUt%L07Pc6H2effM^)UD}!0=?0+w4h!^NGr_Dr*|998A!t>;nm#B<%5PjFIJUtH zaqJ}!*-gs;`E!yzNggu7_*f%!u7JyJY%~LLN?v_#NCs%$ZhR@-OaAjDLlR`FEf+uT zbiCX9J}rp&+QaIP>r7F#m43*7h*ir?WVSMGC7ZpGSKU*WgLO&xq_pV#2QLi6$7wCg z>=5ZpHh6a2@ok+mnq>Dpotr@RJ=!J2Xr)It59F}k>=?Rk_Lt0>b5U2iqXv_|Nz=(T z1&NF%$PuMlSh*U@cRO+0!YWa&GlYE#_K_pSo)P^!wEsDYX zXNy^3x)^|H@AHS+ID z3a5G~f4r)56TEOZ8m=>j>DCR8l3&kbp{-ekbpA&QvsTo7k_K^MZYinzPa6Kp)J{*B z8e4;ho2?XI1uL~aDK4VE^{h$j7+CZ4UlgmOnkZ~4j_E68fR3dHt+|4Ph^gcs&T zI@4NP1WKgzQ?n{|{qGs6MvDtVFt5y=3~EnR5CVh9 zSV}W?dP_Pn$9pCVHK73cBaukCQFh>VRjpaKO6`tt<(cIOwA~{!#L!vqf`eiB&7Aii_DKVuJBs(S)QM6!dYUvuu$2U zBtLl){`y&8Uulz}Kp8smcZaVsfqI6ZNk@zW%T@9;V2|m_os};S?&Izcr`o$-z_j{~ z&0fZwZCosDZE6--t7%tohb5AwhsM8z9&)RWJcm1@v@5`5kr?dkfAr~Ayas}6Zmbnf z(mbGI!8lR^eu6l7*zc&d@^}uaDnKvr{`}A5F}92_>3Jk;sn=T<{=tX_)h1sVt1CrM zA)Y)hVfid>>#0A z*N<8k37*OO3!&e+H#PN{_Oj5r3z~#-nFKDk-JQc<#|idA9z5_*e&Alp7-!~zD`INUdo6Kl&YhnS&*+xGB?Bo^(}7VC-(GY<9(*sXXG(iAeFX_hmLww5mv410P%YhtW9`68qz#wu`?{b0!!)CiQw7W7p2TEZ6j&zwp%(qDnUA`+YV# zD3VgwK#3V+U^ce{^)-e{|#F2@(5*NLU?pFbFPVQqWE^ISz$P0Xk-QrI5Z$>lvdimVO70e!Y? zV)H8vdu73D@0R_#cH0ZVm{{AC$KG;-YmO`QYot63duqS`VXtdfEx3ryfy^iTh4?c< zuO3KZlYp#G2D$QHS(~6dXQkz5ze$V)F$qj`Uu+WorLfZHGwu0q&2XUEPN`;Fq~?=D zvyHf)ag4+1%edZ^z$O9l!lXeqllgW?X{?6Y7-E&i*Y?5-aRIbR36zeWKTv1ix4L2Z zEq0WShhav!m+!4BN2pDE+LE@=mYw?;t;C|(^bDJOAs;c}l|gp%>924kU1z$`<+RX| z3gQH+zAp9vJwU?0rzo3Eh>*KLsCci0_VG3crFWUNnn<8 z4}QL!@HY}S<0tQsR^AKnrn@8I4iL+t8SK2qq6dtx{IwIcqWTM`dKg&9L$DXX9T14W!)iY3R5OTWw+DPbjP=nrNnj)-gt(=C zM(9Gi>I+7#cG7x*IYqXHkcy9hd^U7z%qg|4x5R`%?6GbD7w#?KL1GiLS zbjc5=IilTeWfno+xQ_7=33|UQ0Pkvn)Cx#YALIE6vbP0c$~sM*+TupZnj1;#U1Ut! z36R&b{F7VQ`^fwxB?cfiJJP7+55w(kNs`_<^cbn@wZOi%LSPeQgXa)l?7mA`9~8thmXYw%6y$WS9y~Lth1o#_1Ol~o} zwi~(46#m99dM!-ZU7%4Z`I*d<`tfK`Ff}}HccIWp{=C!TWzj^8&g`ub=}_RPO*g(Rt7#JF?S|c;YE`ATKJ!sa?hw zfHwUtD@#c6h9}p7bcg+LQV|xSIuoAlvHJrAGVVl>mpL3*$;-`Q&xJB!p?YV?)T!9D zw2A3=&=~E$Ptk=Z7%!W>ebd}skLQmC)q|RCobIryi!|q?iCzC1q9YAGNj`v#c9{v`s+XJS!&i4GWJ&s;1rw7zT*7h{@}Dzw%6%j z5xv`wyLPo64#%`e@(*E%>8?${cXF`BrBmrvV4_Yq$Vycy|Et+VBr?!;6Ez+uei+;s zQnyB2VS^y$KWOvb9hrlIJa2m6LQl0T9UR~_b~V-gBuvADcbeKc#B4Ecx##$m1F$6~n$*1e3;k;u|zNssz|r zn?zVuaYs^!QyW|;r;6>{?RL2%bDgN?%<48-oct&6Pe+ia28$mu!!EUTUmJjQ?$gqHv%kl<9=R3 z`>RI^)MS{iAPlj6>P*z@>aY&9V^M~uEBdh{Ldy`#A#SR&3P-t(VZkz+Z3r2mzuFWX zj(!p&>XLHon!REYBchr3&qqfCQWM>BFEcWU8=Q%MpD&O}snfOQinjTS5P|-O@U2+tRSOT zjIVFUqIAoKIn4^FocjU#dUC zxB`oRpBfII>~1smGDYx}4kq>y3O`FtQ8RF(7I0!>X#b+`F1oG#W!%?-0*(7984LYwSH@o4P%YX^{NA#$Px@#~bS*9QslM@z3nF#Cb z)4P)|0-E0IAcABOmz0o~Tw~=g49%80{D86W_34q|-TzS;(Tn20aNN85bI#q51eQ00;Xh*0!~{hHX~T`)QR#-xcTo((LukF>-a zSv==oCb3om!f2H<^-Oz^r>Ul;+0mN%iLFyB6h(PFN>ybA58<@?GGMY*hZ}vdMwn)V z)9zAqQOtlmMvp0m+DX|RNLNB-!}Vm7bqZG4A?5ujlI>2<@w^lSKB;DxlT8=&xiUZ-4+?KC`YV82ZEwkO`n|$gIaZaF}wk=ad#r6TF zC>KrZN0%R|sYC62G2%gF9T^aLB~yq&Z30;WRIS#&kc!_qPL#3MGpGg@bZxIT5?(FA z5#sfjUTqp2KI%kz&J}l+z09WK8cx>axOY9bkQgreKI_|2D~(l~ zZ&}v%YgrX_`N?{y#@Qtn{e>VhLViOSsjKqcQ0YECe)J!{D7rcu_I$A&6$zX_<@L|* z)0`vWBxEsZ`&Dvdz)jCZWT=1FQ0N{wd}} zSrdrkx}GOZ1Vr6}r3EleqP#aQe$HbtLlYT{Yiui}BVaQxBjE`M|C^BKAEu(uPhdD8^}t ziEssT=lJ6z$Ss1|5A!>8^v1OMM(Vqkqi~i{AggQAUD)YGLmPhgshXjP_YQff6Oadn zIT4~YRry8JC9MsnjwO0+t$5T634Bh<0f{P8KJ#UU^G26<|D-GZqpEgS3lEk>R%$M` z7`wyyq3i&YC%rIgO&QJl;}rWjf@5u`(@ruPBmlNbz=N?_-ZlNS-BzUfl@vh?VNv5v zA^IBExy{{G0d9LJ)3bg-bH52g0~ z|H?i+rSL;mKN1z58v>_6j2>MC#1^%R$*Ek;(@WNauZ#n-ypxDHFomlGqLbg6^Te^2 zTvQ`JhkDLnVU(ByI4QR>>oS>5VEHxbkfpxr1^5etu=%9qme_yByj8&uVpi3f6~XOA zOtYPcylMR#4g#mM_RRgbPLjq17MdCHY&@r58<&A_$Ll1?syg^2YEc*dX2{oLri~i; zNJ^4mv^^GK0a>ko?ffF|DrMBh?T?s4(PyKTD^*|Wp7eGOWLU-mr+YAT*q@Ms>AMU$ zNnbymVS>~%Fb6*Y%Dcf2Bm8Ce^Ky-gbQ`%x+QR1b%Rk@j0@L9ea5;>G^kzXNf#_Ll z)aW~9{{T*ZY=B$DSp}<>{2g?GI48zw0cpji23ASdm%~JX;WeEehh&Uc7p#wjEXT|mC*^-JRDeSq2V8r3EM!PHACH(*lGIudsz_f2MdpmuB=Q>SG541G2lXcT6j9W%0UT> zIt|8;-qLLkb4QcE)KtHnX5JIbbY+d)wK*3TUw!qNU$lFH@OW|+PX4E4)jC;`rp4t* z?Y$M4FZ4&!W*)P#A_Ctj?@P@1+_ExgZM;Gd%OqM7kaj7KfA>muM5ObsVLj)z2p|Qu z|9a(?7M7I!wUht~yrY7M&B%Y^cJkajxRIukb-mN*mk}ea=6)H*s!?@*&a7+?T4KZh zfT`A?8R7!Tb$90o21)FdUe>nNyUn5FS;SIr`sdyJ zX(<3M?NWF}c>eAD3^Qb{pzvBj0fd%Me?rxpCh2}~UZ}tC3 zBdjgLwIm^f;~-ItERC0tzka?ggfAs5K79T`NJt-s+1zcga*mC4^w+#WJkyc-DAI(p zaoPkYizQE=I#nk_<@t{hYAz_dbMB93Pd45&Fx&>eJn~wQ*e_T&?YHPp#*}if!~zM@ zJ{h8FNbv|3yo$E%aso;y##Ho`X!~4fZK|tRa^>*QE9vAg4z5<2_@>Jkd{@?KaC*TU z0S-8dHuE;DYnD(Zmf+@nMlq;mnC!FNC6l{swQj_#*Ds-Hc4nH`Ppsb5SQstK#4}UB zR{zI2{!Wz)r9RZa5Z;i`K^K*JJG%>9Zz{r|=C_AGr!B@6Q;Ys=@Orx`*sE zGR;MAWxysXpy$qkw9rwW8h?6W~gqP zG4m#qi4p?&az#4OKzs-DWLj8^o^6B0-)seT#ns5TxVB=Q$mHhO4o}D0<>G?`rF>s_ zjiO>Xyt&L=YO2J5BE2aDKTr#8c7i|r9-v#tWtC@J4Gy5P54 z!0I;!LBvAW>NOImOxs^X%@xKW1U|U?3d~whrz&3d!<{MDTbi#iAtkf91sw7pbxSih zgQkg)Z#!Wdr~NW$#X-pO3!~4Aye$OLoK8Jy(-6pRzJ%jD+gAMoQqhi^iC1sbx^`)a zfIYS%vIeEib@Fn7kr#=$LY6GVUNmMExIeuwbHQf=1aUI+qhF1*WN?%f@hNtAQ>yyO z_}vY!Y$b#5{P&ImlA_*l@pVDXdpP}+yO>^T@WJ_`V?2}!)R;p2g|lu;n^C?@*LL@6 zUU<3B(}Z1Z%j3gxsjBXO(kRITu{GMNm3c&H5%VchN8lD^n?RS?G2&&DX-HAokc`PG zpz8VsYKqDs%PVJFMwCRPjo?SCHCcl9a@2SXgbw{LIYR4Mg^vtrg|zd4ROa9LlUxw0 z+>4u*L1zP_ia)V_-QB^_)#(}H85U5&kXPyS zCL#dLX7$E>@#6HAgVqnj@@7MpT$OI!`e^$*x^-K!9KN4)BbGnREioCqxu;c$?q|ew zh-j!gno^|r;P=WIULft5SKrC3!M>D86?OeF}F@M(sK9&buH`2wl}8G=Uy1aBe& zaPh6s)GKZah1SjV9Sx9cGHKYAWwWZ;0~B8?^3g0Ty^Eh@a_DXKIWfw|jyzSQGuQC2-uQPQoVw7yEuTf z!m!q5$UIn3ifk3p?M)Q8(S;VWg433n#b*3_MC)O>UE>uKUOjMRjkNzA5OE$HwOE4-NFmHsLt0uH z;bB&MK$C&zIenUqyC}@<2TqH|Qjt-P;~v4rLKSgXJP2W%{MJ!x+W(^^K(iWTW+I`} zD6v;urqtx!qH`NS{YGxA?%RBH>JW&GYd(6_xn@)q#*cM2=1x5P=9wQ3aVNpXB9%3+%qFMMnmU*+2%LP=rzlFxV^q{!e(ndfriu zte_O}l%~Jl3@5ns{z13ba<=!K2l(KpD2b9dAVBHonpb-;CD);7W-Nc!S6K1GUVvqQ9-!b=aNKLFw@P5h;HOSd{gM~Z1P7J)s! z%Sm|RoY5K}#*wWNt1GzxBeICGd^{>rphOP1iu{S&J!UcwnATGBu=wiieL~(zl*>vk zx0|7h9OXmJf0|~^+T|p|FqRtDU_B@^Q_HWn#QZ15rt?ImtQ9tZh&rZk(M3s%IZ@!A zL#{t>+6b!SMWr&&g44Dk`cqNIX{t3cWf-u?YYE*VrV}cF7lmuFLZVv^s~SftIp$rs z7#L$>b&q!m(tG8OrgxWK2-Eg6DJv^09G$~{;A)ebX4SkqnmgG9<&c?VdV$*$FUb3D z$yC61F0{$2VYlr!Bc8TBBQLbs2+j}kzkl5Nyvzqz_}u|(=e3Ekf^dpd0O-G0$qTxwlyc~tRp;o=raTuZ-YA->aaMPWQ)?6y0$ce>MvV(0_^Tr9fBTqPfQ*>Z^ zKJGMUq~Zs|ewAWlfh)EuOA(TUBi`A=?0MVa;1Af^(bA#0UH!bpm;$^;%Nxn*ZI~i1`!jR<-QtI3pH(2x82T_lcwH&Z32PnWk3ZbQW#x1ZIsGq8yk? zsp@{_g(c5IZn1B(M6`L?ucl(M7l`Yjp1JMDxgt43a0B=JhQwm5PSexq>vPY)ITTQE{ql^`HR!BZae|+t`CFRN!oSpVC z0_LW&bevl5aznY=IlE2UB-uR-P%V)F2Zvkk=>-4hUx|1)m7SJ&Rb2UD5RmG_C5vc@ z^TN>;EWmZCtq9rkKQft|igx^KGtvnfHWs;e%(t*U+&q+&;b$)}5ZLZ%H=Kpxhi^TH z2pUL}LIqH)>WPPlcuvR|O!GtUEq+)f_&hMpqsg8KaS$~XLmWFK`~U}d1^Vv<2N z)0rD@;yB<^%(a()kaW|i`9|9?Hc&=7@-*ZDj?SMN_eN?@Xybj#NZ4a(F4{(@8uYB# zbk1X0102adB;HJ=x8+ZrD2EkM*mJGjD8&e46L{6)?0RME@A1aR?r2>)!asng zqfAfKM@P_I?p1yG)lVH7+L?21NoDDA;#+^0!)^fACjl=XJ#?_{d}KZ_2i4h#t#ecq zdejUs11-Z1n|`eJ!F|_NFXy;uK;n&nSEf#G^82ck(Ev7TW4^!8$h;BpiV{swoUoX` zjk5t&E$4y85hsz#G_iIBx*`QaAQKy|AonB8@Zja+Oe>c9C1Mk>LS$fO>Tr z4UCBGK%|6lEqY+sH~>EffORb3bF-Ozo**9A>eaveQ^n!*T{!~}A`zp{GqauRb4kyb zeDp1`dKV>xDore)?ig*H2oHqdlm?j>ye&)p>*L!FgKWFDYDFKfGS4bl`z7Dk?C+8pbsazAlWt1UqNXbOsR@jc3m4#8Gqc1FOWM^HkTVy_)%!ew+a6K9!91e zag&)lDz5Yrj8-3_=$Q2801MljW}8th zMvYgA>`m@nUrOjTwbl)s;}lYZ4SZM%3Wa6-En z4s467ttF?j4|gov%h>5u$`Swx_L$hRn0_KqLT%e$oCl!ven)07ko|$?+rSs`bZHy9 zTVDDNrL~3&L(NR>t7rVJZimpxmhI2$eTvoahUR|oHwT$D7D%dt*meUb#^1|Bb{Iit zn1UF+)@xhgT+ovVI!X3ShxV2Ve=drXD8j(h2!^*CwTiRk;3{q;}oq#bBw<}$;kN@8|6re-)l&HPMrv4yDCN>Q9TL319f2ed+aqFSw+IYu)H;R}=#~?RHDj#0 zG<|17u)QX$(LddKhHXK1#$3r({O7N4b8Pp%nX)iX-6#|*;Rk<=XPzx0ByaQJ6O$(R z%mdiyW%t)iVa+g^^{jza(_2gRzriD=T0af12KQQEy)(rabgMd}>TWhUUowhZL0rwmPWqyTMvv(HEnV1#x|Pk?GYmjI<%5)NVP{>92Z8@$W_Qp7LtuJwg22nT}ruPn@!5Td=%?o z2$YRFt8HA`?^k*#jcbVbgLb~q?3W5X8-V+oEoKzGeW!i-b@gSi)i$j`0fN&eCh8x? z0R8r!k_y$%AYMuf+%K7=EE-8FD@v58IghBcPs|8qP?eJfM|#a;fqeRtXr@mzCZxF6EQPoE%SYlYJZ;aTdo%aCPFUe_wY5;2ZC$;~m<# zYTZnOCbIuA1iAXTGPsO-#Z%UKnvlU2nGXotaK0~I*;i?mUyUDp?wtL2uu5p~6s766 zB4X0xV>;}BqYfinpv&sFK6s&pQ!j*q?%YSQm1)!n^`?Wwp!I|LL|sHw#_$_?7%Fqgt;( z+K3anH!i86=3;cJ7ren*?P2*rJV@^eY_@_C^d946;Hu81|H>y z>&py`dLq!rJUhofcnCN5FHYgQc9VhUBgyXig6b)OsCv+Si~IeG=OPBD(88wv@bpC! zlmPS8eSPFk5Fo9$fnTy6&S`GiAOFFtbebp}I}*O=)tN2ss@lD$GiGRE4QoNTMy7Nq zJOXABN2Cqr2ZGMp|L<)Ai%9-3d<813fn3rmJAsqSgu+!6)oeFzZd<4lqXvxdCZW)v zD#Rnq#0|cP%DZ*^QRKBY+4FdeD#P6^MyKd8A8Gj{@BF-dn~`iViW>w0{Gnu`D?3SE zq!FZ8txVxPwqLsW{NFaK!wuNFP@)aIYef_9qruM&vRLSv`t7kpr$ zWl^cN8Gryyg%0u8gsY?3WPI%EmX)~12Af|Pkv;}J&A3?(?!3;A&#l%)uxy^WpsHx0-&TswQMKEt4} zgT&QRMQ~c~cbx(>n=4L12?Y=al<#{kO#Q_Lo{>>ll(g0Qb)XW=vbv> zf_@Zvx81u6cSoChQ|{3)J<7610+nBofO?rERwF zy<7GM)BWrLd{I}3e|EN(PJ+WU1V7L}09N*q^ga#emrw)dN{7&pa!n}NfrDN8<|7+V z`-Q@3M9NKq7C%bD0+nXAKWJz2w$8@pVRA$FKp`KF4O2 zs7Yhva3ELxmlp<@xSbR_=AL$S*t^rW#4|QR+`U6~TAd#%jm(LE*O9y8J~`jD@P`nr zjU&b|jA@6-Z)OqB{hSU25~t9P0pno11nnc@$ko>(ynyW(EnTlgd(e4RW;tR1{kyf!;LnB2fUUo zj~?nAOuU}rdj8JHOg5L4Gzun+wKs^tJi49an6AlMamt{##q+OW8Txa)q&KPS1HQ{$ z#+VTlhoC}KY@Sx`Ea38QPZOb5N#!%;>6fU%q_+y}^w2#iwe4CH!A z_;rze`vJ?f?kBUI^H(_{PBT$+Z=4)4(-sR>JPqs*fAxqus!LMFiX&@t=g|u1$+yfo z--!B41GyWa4Ad*%Pdv>bR9g<&e?if`aKyWCyC81X?s!Z^EZ9On3a`w4-|e>LZzLD9 zj_I*@fzs!#Pi|5;V=(D=_(6>C0d>Jiz@TmpeP?4&kmf+(aRmDg8DIn_zha8%7qKfE z4u_-b2?0(%bu3#5xnTWk-^J z2#OG_HvmuDrZ8Mb4x~6_xTgQ6=<6xnZ@`-J=@y_kzE}O~V1AlM4*%&W_7+_?WtNzZ zbZ1?g+YhIQZwY=I{c%Nk?bh-%0T;WWLEs?k5H8oO2}plaA+NXFuT&!p)UXvxE;G(@ zOf!;XN9g2{1jEjDR5`)$0QJkLX!Zk+Y+>8_h6apUeq&4fQLTl<@IZbqOx}S6!|M%6 z0ironl!79p5qQJu2Ar7quUFB!pP0)YdAYReySdq;mR-N-1vQ>XWW16aquU-`DR#}BMVdS)Rk*wT`->Q3SiLTMRh@HTX zPwsVd6nXL}#RTryGd=s8Sg4|r>yY=ysSla6f9QbwAO`hT@B zbSJoQd;6t4;V)cz)`VL8g*e`9vxUE}sg`5dJGCN&D6g@53KUL(oxE6Qe-m;a@E`|{ zglfH-FQZ*$iAu2y=Rt?}bBLpy1%S_Ad^{5RhDt#TVF005$N_QS-B$HnuaM%V_p0y$ zu1dFqh~OoaY`eAAttWP`V=JO^7m(AG%ZD5GRN;I;J#$dN;Tt2+=M~F?4o~Pgf!Sj zZv1fXZf>Ri-wqy$wk=asJcdWJ zjE9qV*q@*n6;n*?=)%L!pVjA%M;pH@PY72f%ZSbenPba%Ci93#PjC!S& z=bCfL^93ja)1O;Xkd_0`JP3f}(zqGVTejD@fK}>*Zbw^R%%7(a>x?IEnA4#`#pQhr zQ~mcal?$!w#Ae+vo7dGqn2(ZH?;<0V|1IG|bo+_$E92wC7d@=RJ6Lm$bcTjsd$RmQ zyzJGwAc1cy!y{hnxyLOMihDW^Y6uO>^=P64Mf16-?yk_ zVa36l8XDtXj1LUhk35(rNbZg3S@SUt+q^X27CCIoFkm%}*!CN6Nj|nY2?Mw2BRlnz zH{#pZGYlx7j6Mj>mYcD!st3_i%?zb}1w7hWC1Jf&!$lmIH?zCFMd{`BDb+jPbbvgl zoNl0$?kg#pwY@>-Ft#A8a10Gk;vglm@(<}woY(oLn4iky8Hvi<#&JCa10q=}ggd_>mH^?9}ZPahg? zdI7TAmp!WN=)1+U{vV2iax7*NfJ;gIMK0@M4~4rD{S9@35p&q8NKGI|Ej|b#c~%qZ z;$`!i!lA`-AlK;py4MeAMC=I7VS{c04GbPu^<>4)7MItMM32`Bh}r)&sLQU8x4+}h z*=5uzq{J(C2t@GTAh3W~DX{af$;<34?V+k)@D~gGo)Hk=aVyeP;)u|{5CtJrDT%1l z9t~XiT7uu)prP(_h^RwGv!?~lq6A0LT1&8nZfZ$;gJdB6;YRFP3`K=l1B#?*qEt99 zi4v{*D2Xe28RHO20=xUDZ$6k7CJ<7$^6+CBNTe9V%%Q@PAo+Ch?aStywY_SoAY0~= zYMO2=!bxF=NbN{-9nMjz1bCD6_pvr673dm8_ z&JoG?snExM{585O$M-+{m(F`y`KZooc7Z!ToJBK@={MVM*4K#oGA{iLOY$;xv)7dP zV$2kd2qJQFks632;z6CwzQOt>dhCLjC6^CbB4iwS^y=hB4FJqpuiBnZ`M}OB{kKDI zTlg`86E!=|Z~&SNf*qeDhc^Dr904B2Ky}D6wh!+h(;ZWBtLxd|56Xtz4dhg@Z-p#V zc5_v@G;s{1xQ~395$~IbTBh+vD&L5o=FC${|19)7$S%lJv~?olllavu5h}W&8y^S_mnu{42=LE=F{e?R^Ulz7009z`TC8gib9) z1(A-@6%ofeX5LqxH9FY-GuAX4S8{$d;MJB;(40|us_$HzkI(a%y{uwvAY(BrfIRCj zM^Tef1??SQ)v_^WU=iztz;nIgU?FiXYhvdfgqD-S&jLJ6DhtoN%3*dYx_Q z9X!b%g4Qs@u$pmX5Lt?##!QrO^@uR5)@hCt0L$Bs4dja#q{_!!ma`T{zpTLC*(f2^T1P;Wd)YC*D2oqCz34RN&BAuwXWbsExyTwfa$o_t5H-Z_37y z+_rMk&w|A{p4fuZi(5oeR@nuCL^(}qt;^7QP-T_&@%(Bz9aLAVN3YmGEJHg+@&NJo zL~gLAI=S^!4KJOoSCP$oWidn>vfx&pF>x-bui4>aAOtjS$6|+Fv_^MG#9W^cuj8vm zS0Y{dpOA{Jt=)27)UqV<*qWMS=KIF%5upi(0Ai?w45a;p6bY3_hp&j61mp&6+_i;c zTxl&^e}6u$rji9zoa>gU8EDia@00wtGM3AJK`8NITmf-;Tt2t}lvf~tH=pZ!XSvaS+_>SU zx@%+W`dX1vW0QSYYcdKD2HOiBt-Zr19G!zeUy;&d7moFdS=MnHM{c@C;75v7KC{7y z&4UCJe84Yp<`89LKv&Z(BMdu@N1l0Y#NY1WFR&XCmA1uxwa>_pB$KL*6SDa+1H6c5 zfhME6?qZ`BhSG|Zlm+3Jlw1$z_9uV?l=6}DRl-RFb<&M+*!Rd*e)^{X32&&ZC%n3t z7dM+XZ8!}3>iZAf4@^(9f?V>M8KhjV6K98-cp_P!;L6Yki5#3VMh~uOQ=C9APFnu? z%nD(sapK^RMlkpK@uccDGaV#T-@4}jsM@hMlr}*5HORTSzKPd7Ioef<_h!@-XXQxY zbt{m>D!BdLY=-m|)0BgH=Ua&kv+&gay!N+>F~`Oeda{>cMyn{=y|UUlWp=F19arwL zbkepI`|lJ015Fuu8gBKAfP6x*c$b)!@$_i~^-&(o4)Kgp@#?orHsO+$qX84<|Leh< zmDv_ol@Xi9cBU|~zm~7%1^EKzsK&_5Kzgg*F>l9XT_GHmuN7mG@nrkjhj<516C#Id zH@hAI`IBcOa8@blwyc=`f%LkykAs1{Bsur)*=0E>QT#qPXqHX*iNlOyT1JUSyX?!l z4ulkOerj?fJe<7wJ=-4$%EzPIW5E?AJA@XMYr5|sqvngi?}9fsb6U03v+rKLnXl5b!pCUIO1 zL&BXsHn$c=rW6F+T=mO5&12n-CPkg8Gf@l|(E6Ami1^igBb;e3;JqD_ty(mr)JNzEDwx-E@lpv1K!wZm}%AVKaj zjKGAQ_(fz;fu-6{WL90GSgz}odmI%)D6WUt9l+eVUOrPKGx0BNOmeij_Z_uV92i># zzUu`?1$G?%qV$895aX2kCdI4EdGojR$bc;dMQ21R+AK%g5~>{DJ2YCqM+%cB#Rap? zMOZ7Ess-x^o$BZpFo_;PQ_w_H!1hdyKi{;nTka=nSM0MZa<}y;X~UD{$l5f;yPsj} z{PKH!?6_hZbg%s%t?&eTfIMV)J$rjm#t(Uof8jkum;NC}IWQ(LKfSrjd2xUoz&*Nm zgRg0?M>25=ww?N{`7c}Ky;cA2sj>C`%WjsvNKT}c&8_z-Ia%HxH-T$2Yo0304yCr) zdz7>ro7>FrVZ{e?#oYodr9}os>DAl(p)kZ^A()LV^)nrIDXk%ijfGc4-4IGi5jdUC zuKvDnVS-!TJ&cAd4y*8=^vqD-k5W+8Ym{>%V52rl8t&yzpaeK6AK&oyWp&Z1eD*K} zgXz<5ufl!!mU*BGZ?U|}x(eWQ(U{GzA9c+^B}9{pVh))x8oB86L{J|L(1rH=P@gri zz3J5U!6R+T@`?775WNv3b|-tM2eBwU77wxnZ7sIN%uw8FNG05EQp8!^=}AGyS%B-X zktkz(nKACVGg)AVG&1#IMEjJ1MWL}IHIh@bl{j+oH-34)41g-l=|LMHkF0Sbzefrr zlNZH`uvx+f5BQ9jxgtHcTnCB% z@Rl{UER2d+HdsJdm&fSf0HVcuD)`Jhae){xZiZO-h7pVz<)Z^~?jLfG=Hk{FVxF^@ z$gZJZZlHbi!19oB85Zc5P61YwW!_D^{PKJJR^qbly{?{sTgTpCIp}e_Dx`dRJBnD$ zxq|6RUId0XKwjOyEE|xS84au(M7dx}d8m(@j_y3(-I3EB&6NFZec0kE)WKY6Mz*69 z*BYqS_)F?N!jh^RP96Kx02Ng;3rh|x+nv%v&Q)=>{D)+NirhaGWSb*9*kQs%Fg~b> zv!m4yqgD)Ia|K&fv@m!`;X-q*3+3=|JGVH?&zF)|SkA_kn{DY%W= z^?{&X=WMy^MU^?-)x|35H;!}z5|P7N3~R4q-UPoF#$bKU#7{2j0G&Zz4_m28=?;^c zApsRy6Exx!9c`!m2`S%{8(9k5sp;{LfJ{)P%$ZIGjN>R_YS)#3a??mhsv=t+Stp+? zoA7lQie4!@yUylL#<17r$>f&YdRCV@F1NaI&j=8@SzGh!#)2LGY*hXB>%4PGm?8<* zTtRDGch>2;y>maz@OzdXlpu&s0#23`R`g8V!Ij2rEXH}WIhDEp?9r<$~b|7K@g5!8!?~qt%XZK`QI@Dbl%V0fj6>4^nW# z{-L>59L#o){+nB{qitvqGpMDLTHULRm?cBh9=hx5Ii18yq4x}w#p)|P zs3tFFmR#UkY<$^3{Q^>r*2z`kIHAWwF40-rP0-sNv8OC(yt0kcX%~PZRC`fazG4!n zxF}xA)hK#~4RK(XjEbQSovxP_bsp1*EjuK4%KXI&?uGbjYm%A*sQ03R*6P&GYiH6Api0WtZi8rSlKn&( zCaLE&*YOm8EPN&9$Eg16IAu5avG!d7GhH@eWBvrQ4(R`Q#MuUZ&+2AGhAA?2vfA(Z zJEQs^jcJ{Sj&N@zOD~=!&oBk~npjH~GCc0ri}_ z2*XUOyih$;Oj;e@V@{W7RsNk4es)mV7y>-SrigV`7MmT4X?%7H3rv>qd|O{;FY2vY zW{I6_U9{C$<8IC^^dI$Nq*B*(rJh%v{TxMSsDru7T${$mo|O8I>Ll}f>|ECDYnKRY;Sj;T7D$Et97*8v>9YWBMa9JiN7RD;vvzlo|r!^q-wnb2%U*+ z_J^QcreP6bp!M}1n8rXdxJX)9s&SVDh5$W4!oSc=Hi-=lt4^I!D`=$0suE`&O>n<@ zXS#55w+o#iLCG!*YVIys-kzW;)>U!^ic&mP<8X3Ak!$U^RqPdSi1aYu3PusQ$)*yx z2?^+ea7X3ah_SrQ#8PaPGj$_q(Ogt{!QdM(^uKG#szuDmPdQ%m>71^5zmIBgr*F&c zww=~+3Q~l5iOE_~d%`{~na=vh6jr0oAaf0MEAF8>1<0Q(eZ*8yymbS&C!2n-T7&k; zF=dn2vN!#e@>i(cV8v~UIio=J2_nliC(1y`e2ebC`STHWEulTf$++GYP@vX6E~%-HaVItCKrLRrD(mrE z9)tBaH6)bIY4}KXST(I&MN0SuAr%E|7S5)K&gk`MuaxSrS8%CxMVoq-XO!8xBYfM` zTxSS|O)U+Ah9S#Rc18L1!j5rsVgr_B#66I$y2A<4hB#2r1*}@3$VTID zlO`B30IXgRk@UAm!P+JXSQ%r1)>`Qng^PJMOw|?8|2t@4RS8WsL zH^ui^nVy`yQS{d%V_)3!-?nlBb5z&_S|xU(oRDhqX}A3MKM5B)$pXw9N!Uyy%tu)( zgf6K*loLS%CC`Y+kdslq-TwDTNf^?_Wv2YEB)3Z>sB8DjL18dP~HT{`(m(L$?lV9Cudlvu$soUzHo>TJA z*>P6oOiD`i)*xHdXP1?9V{?O0gOMzQv*Gc>kPz8;RON4t^z(6><)WZjOv>&AXRmw| zt}C*O*&)O>M7OV)vruC6wytOjFS02d*yKqklo@u?r{!|C$B^LDG^3F~3nw-CzU8wR zB}}W8ANSH{T;lWm71O0@eGLdUWOM?O2*Psa7J=gFyH0gTk1(vL?EsJjjBC_7_b;(o zOP1gD(@>!+zQ7xDCwn_4YkjL4^mf_YFs67^n43Q4m*Dk*XL^qT z^V6|pJ$8MqI8ar0&sh)K**ScZ8TA{}5{;9utsJVf=Emm+|Ep~aaG zm*!85>{We^^YFC!OlgxNF&CHG8x(jt^&Fao+x)P7iD`zSl=kI5A*sBuqCdfa2LC(q<1bWUP#^S=r zQDw{Qa2nr@Y0Z}NCEO#Gd2Y5_^#Ge(&rQL)C#t*SU)S~dc3u<)E^UK|LB1tx+|k#r zbseP9bcBRrg(Z<9Ud0rCWEtl`I_z1u`8OvIyu*&U-xT8q(}LD$3_F`VlhiCo%pIaT zHWOg%zc=eSYNk{drbwVg(!a(pubM3w%fLt=euJ`Vxt>JW5Ijc|^SlV=50Taad`;Rr z8_-XEFvyIn%MLTvg>X#rKg%uRZ!@K;pEd!oq}da3KX%hP6bw^U)yb`6b#+Q&vy!$ga4MhFOt)dBIE3VwnCZpvhC{u|y~f?+|M(&RD23PsGv0qLp3< zLT_-@*5i-V2<4JtoaatjZ3#tvb7jo}3pI%gx-~uSdr}sJUEuYj2rgl(um74@p}y76 zFw&nW%9@>c3yu%c^_n3a?ZyoU-ogofzU}jq_)j)AjL@6j=kndtrrEopE)>^3!h|}l zC7kO;U3Bpa;^yJqMB3gKxLn8M_RYgFz(Src)384Ij-3ykCV8Z z`cwBCQU#^YL^q(w>yU~PkW5Y{vG|R6FQXa6qua&MmJAkj4;`shY=T<)e4fc3NA2d9 z+m@+*XgI-AXVsemp8=kUjsVsrBbx8woo#2QHZK4pR(P>P;M#{rd zg2u8sKOhONG0?P+HlOhR!U0bul9wK0w1Hd<5z~kXbq~k9F>_IuG_>DeAImKm%V)TM zYp9>{$W?y(zS+`C)NsU&H_h0jzqHe;w~yN=YV5phjm8_l0?zA#ClfiM!XxPZC!tR{ zDZawxuX8N#$(*VVUJtCHDYGXf5%s8wf3P!%r>eA>3E}&?uo7!3`-{tw5M3rlBiQ>^ zIbfe{$)y)hxB1-pmTFh`kxe1XP@X7r?GCj^;0$yUSSYN&2+|GYwaJ+66ag$t(Myx?pg(wO$KV~@iLy32KX~268@pmTIiqZAM@{I|=)Q103 zJ<_^|n$%pf4+q|XMcgyz(|3%js{*Tu-1Yp`iCF$2MoP3q-ED`31i{V)I3mW!Ri&vc zZQ9Ri&WzBK>k`A5PaP`I|5APP7AA1SKwPT+l@Szja&4?Xsjo_q1AMhsiT+CpPe9VIHr(jP>1XV!XOp7ms?8@SEM+0{G$dUf?$&UMiU@^hw28 z1pf4$a-%xN++!vdVB`LnoToJa)fb=#vAB(F(rt`$w%xm*_!rUT8Ca~6C(Ys*iK{UD zuL~ua6K84_cX>!(5AtAZj}H*3Oi2{SQ3ZQ$w7-dlc#`8JRQGuQK9IwnlRj{~wn^zh zW~A8i!ISy8kK%Lz1S>R%)b>@ZO}T|ReKJmk4cEp~WI)UhSWW;u3WQ4m{wp}Wg#OsM zG#R><-3|Xss$l=y>tVhh!Lory71>RrnNoiOMh7};)#tK4{lxRptY)s|^d<1NW#15N za0086ioo>=L8vPkQ`Y+u3P}%l@(vlB#OX81*zrE7V(htbuKUTU(21{n63=;)oBVH4 z??tFr>g6|W{`_xbSBECNg}J$hUhiK=rTY*Y7bfh7d!{3rzsM!?wyrE#s?vMQDj0P6 z^ZIzFu9~KPug`|Q+k5|GpLY)A;azwUK|~!mR`w>i6ZJ=HTeO0l^}*p7(3pt4x=8Vv zQou0EKXwo^dk5=3*5*DWz<0FwBEOO)DpSN!~E%GCc0mhMo z3>WSTb!z)<64}VYp)+5tPy^z!XB*W-tXJ}Jc5X!EVUv}eKRW2e+3Jf+c(($fIUP;I% zc*JDjKQ&lmpOf;Kk9*C_b;#6q(a4<@g2DsUqkb`0@^+|?JlG&|Bcy}BoHxD8z z{OM_$yo10L5g-D(`ca6!L_>P4gA&@Id#v_S)g+|7OLL_O5n5~M@HMzalG(Ji@F!rm z$DQXzx$Ue19CP4=CO3#=I|dTa!lFhCcFn>O%l@S9pf`SGjlqm}REaubGHvOOKLGzG zZAb5TI^tet;nu_7Dn*0=5T>iC5c?u`Irc}>yF7dqYXQ5bx$Zz+q4A^_qwE3 z{_h#Nvt;aV_eVI1RB$PP6DN8D8%+lH4k)#ewBg8U(%*ENN~<%8K4&m5?dAKaSGA7w zy`LWfX!f5s_@FuIxZ60dQM%ks6&M1-wiAe+*b?QrTFE-Jh0}HjnTN>oZ#WeQNNe-u z<+FHXR2?TnFt9=){d7rOX$v2xi{tD}?QATx>GLCGjHCOhzH!Y0E%>kPZ)J}5U-1Pi zL5B34=5+l`fF055@v{+4hz+6{eT+yFNiU&a!Y_1n-f{pkm`y_y^ zsA=|cS1a!XAz7@HDHWb#y(o5XB*@8VD_gZQG}1bDJS9xN=U`ABG8+>b9DW$ly>|lz zObSzBucXw9MsbJZ5=U-P!t=JJ{|?Ntah2)2lW}Oh|LYg)m~lm{-VtOj zU+LVn1w(?q)hV|*_~xs$`8`NhhQ19iA{Jq5#+tItO8}%nm_t}@^7|qhh7^m3fs*TV z7O8-SuA8lC3(&VmZ$p%?h*DUep{@awsD+Awd5^K-f_OEF!jv@7!u1Gj9k|mY7O^^$ zF4CLS1sc!@Lk@m`h1BsRrT*Y;a_d8J;Wpb;8#|f!K!uyw|1Ci9coXE`n7aLvb8vYo zyw3STuk4}!ejxbDLZ`x0F^B0SKyr2sRj-{$=2}1D40&(f=(Dx6eEDZEP;PedB-Y{y zIM4c-?{6qxqa2LbE^o9ezd|m7_uL~eheFyXKW*LF$9Daa?V2wN*w$H=<=Yh zCcsreb=^AcD|Evpsoe>fT*)U}t}^?FikI~lpb%mdKJCT`P~H-*I^1!w&2o-Y7$9L} zk^V2F4KUbxV8Bk@|CJ@y%wqOjK%0<_aZGn1XP=sPuvbib&#^SLzua{-1;5SQa5PSz zRL8W$N!;;sKpYDWKjnHwU2)K2($j8IQ%2GJl0sdmPhLfhOW*8+Z2B{|=Kzq)`L8*P z2d+$?!jyo<`QI;8IGwNnB^r9h%C}M1^MTo{57$7+6#dJB>i>;{mN=kBxd(Nh8L(XWO55HxYX@WXA1J+7p?@hGl9nmRGTMqc{FTIJaZ4l>@+xOi`1~)EZ-U z11*~Pj*ZTQoi3ZTST?Tvi3(NEj~-lq~S z6e<)EpeLdq?s3Bb09CbyWAD+-=XyQ2i?x_yIS}Fs6({$QkvlCtl7-(jTVJ~wF!pCU z?>_gL{Yr0R;2d@YQ@*6Jq^`|;oe(5QdSMao!hQ-U5;zn>vxmSK7644N7F zDbMy%o3d^mjBzh6i~qgpTs@-Ml`E&;(HHFOJ`E3LZnjCN&8Ce<1p@DUusD3g;f+ry z@-`5#*z9NFVK5S{@Wy+gJX$IW7+B zq^a(QYoD!3Cw z6P(9>JEqU5?(Vhr%0h&=WTL-*Rm5h#q=nIx~;k`qy$dJy5fhz2nJ$45p&7@`6G9po)&-OIAE=a1`y`@^|@*fj)+# zqGzgVGG&-M*q%oC%_>~_mPP@fmtTwDkH2tZp83u3%f`m`6akUyat`T%^&Fw5Z+pyD zK1{v0T728?#9hMhJZuxr!Lo;&Jcqj4Wa7Q#7WgM$1?y}_5#C>hC|q5R4b#B$pFwZ79$=`xbVvHvrk^CLG8CVp&mj67bTU0Z??Cy}OuF1ZSE>;_-8{LlQtjneKZ{WiD*xzSdilFw)8 zT$FXr>Z_NboGVrSD||0&b^CUjdN3>1<7Vec)dK0yil` zGSZRW>P!6F-dhh+rgIWH`mW35)ZL7rnH5rKU&2xH5gFZ+LLFK=duCu2Z}&OJtc5&n zLlnv=4ivWn1A`%s=v`B&tutPz6uw6R7lU$X#(E5Q^<^(?qy1y}?|lP$1&QLKQSrO-`Bq|yiuiro*ai9%=RQqzR{rJM z*h^v9q(0mv>C91NSidKhN*cNX(fRQydBgrewqp*d)N*th1Z@)RsdjC5==pN~O?A6n zh(Ve;XHs{q8|RaLo+dBJU26(AQd;{~J1*>EO8R)$jJFyR-%^E*x+K&7*Z$T^dOe>sNa=k7BKqF`G za|~|lWkG3*9@{1HU)QuG7MrlJ&&q=G4DCS8jcM?!(y;g%MNrKm7=Z)E#0mJta zpUNI}L7efo#m`c*6Qhn85aw>gSlqGg0?{~kgxnuW9q3sFXJqZk(?@e=zcdbe1fZtu zZce`f>Ft;XTVyv$Es7Zgrua7k*MvhyyoO9CUzUD(XZ=_or@xvG0v-65+jk- zG)oT8UQY1+)?HMvMt+>BE1v1PQ?4fME1g+_x2P=(D-qv+!)x2XQ>0XwInf^fe?)b0 zAz0f)EM{7tpW1~(JYua*Pim-*#DK!Ls7twn+6pnpjDooW?AjVVVMNuW>V2-%ADJ-D zjl-CO6+`#>n3PSV0PlKByeuFhq+1y067-(0% z6hD**l4KJA5!HH*DLMQ=tG-Y4y(DClm=Xsj&cGaTs?6DHa~7@GBu`0%BH5bS_FxXZ z@VNziS+qxqmV-s}VUctS*Kv?nRhJSTE0elvDV{_&uLako}@TfmviozW6$MckHt)06u|4LMp=F7IxklH*$BA`dv-72 zks}OJ>!2@+dTUs2zCX%XadWKu{GKXRBXoP;ty!DtcNo_c*56V>`ebSM(d}eNMfr%V zQ?D7}iXgQvMYvR`KSAHr7JH8sz)EmF992lX3ZIxDj{HM4y~iPEy|>P^skwjLHpqkR zdYAHxIiwkXRz4{@SDEEPll88Qm@K0rinzEFM?I%Kr*Q1oEL-E3%bnL3(3w0|C6!iP zIY|lr&&IT)6Y11%ZJ%Tol=&tA6MXpoJ{*JDfw;@2D{Oq=@i3Fc)Dc0T=k3*Q*Xs*% z?+~$nzW3F%CZZ;tV@;%ks$ANw9!hYRhEB=pPcNJd>2Q8D_xE z2wF>;MmyGq*c|`^(LRcSj((ohMkMi&Ek(EH4Yi`VXn^aHhIVoS-gt+aMQ=2cX#h`( zm$vdpG9zDTAljJ`(^_t4w>GQjvtr{t_jqc5Kq);ILoPZ&8E=&xTx3#36;Nz{RZ@U^ z+0@T;(}b$K;JhMLDV@@V|p2KIJ#UnZpfQ1mhZ>z~qUcliT4j)#15| zR*5enRwmkks-W7v-BU19qKxy%mM0Q3(p!lAr%FPGdx|J)yXDr`C6N_SLBS6OZc*wG z4P&^tu>5`fIF?>}I8kU-EicI4=CQ4ejPK~<+oOZ4M2!4>a-~%t%McBuY+^BRGwT1kDligx}@*&ETpVD6fKBHPs3Z_r5+bs; z{9gojn26@ch?fi+3cI?8Pufrw@3~ z=))DQRbK;&={1}*nN`j+#M(G5QVEH{Goho1FuoxkH*@>HUhZcFn#Se`Gh@&a+gBV~ zZF}s*S?qyKCUA_q&WGNF4I3kl@&PAqn|0YK&T_1k%vAuAm2zPn)LU)a98OlZTxYd# zQgi~m5|wA zrgGBua4E-u3 zdxRa$s4cMXkK6WiBGFWb!-9RW7*CfDOv?HJBCA&_G&72IcqCTq(xcWIG<@pmFUdAC0Qw|(n`MB*hGyV&*bUKMn} zwHafVrd@+Qm{F~z{r|oSqSkz3&FCUs!36W52l9c;vPI`fKF7t$na`r+2!>I06Y0!| zhOM}=nX%$-oF&<~xC2)eAWdRYd~bm0j|}w~)X%1y*NGt9vgupaJ|~^R2lJS!Yc1nO zEk=tMC!y5;lu#WaNYg(*1r$vBKxQ#_jn?+bbce=)U^d>Ia-W$Q>UTdI1> z)Z>0!%(dvnxdEgt3=BjrC#Rukn-aB9uzp2f#~Qj^}KhzjPBbnO-^>XjDG|*NVeo%&#X|XKIMC${W*< zZ3<$mHtI_w%elD;Nl;8JHl+{aas~+Q-sWwCPu|q(x)c5>9Y=>!O$+L&^)&yTxz!0DrkS&*SX{fj7o{z8!EH44C|+1m|3+qu02PwHnQF5XoX3li1Rp@U+?df$gb z-tr8Vj~YN{Q&LSOJHOM_-;Ncu(=e^n7UGzpf)0 z%^wI`;D+Y*8FRO}Vyuptl?irR5cU zmpvyzZi5W=xgjLYXQ_Gy`Mrx(2||XjT~TNc#&1X`C-YxPgce`o9)m-D3r4dr1*7eH*t-j zb4DF}M@%_`EQ*A)EMq-F_j?2|FV8JlZX>UMh6zj4NY&Ffc^mn^M-q#Euw7+($-c=_ z^8QF|l}dZFLhx(a3%HxTEw(K0lEYWJu{J;y5c;BOJdC78)2Rh7;I02Xa%ahiAE_rH zks1r{6e)IcX2^Zsctf|Qv!cLJW3;BMGWtc`t$mM)HZqw+?Gjsf`+9eYvu~Ykn9=|B zi$yvx83*u#^BZ=b%`wt;($Tw}SRxE-Q1e zuLFHRp1x`)835gR-EGRPRJI+QY1^9*(gt(u{m3I(Jzx#t<_ZhxY{4|GG&!as6zYV; z=YROZEH2#`h`h@ua_6%)6!UGp=#_apSGZNO1<) z3egn;*Vi3wq5cFp0WC~7H!@@$5%%MCo8v924mXwI&07g)QNrMSj9IQ@Tv-2KnA;^V z$?q^igRwd5UuV1vI~(4v!(_)nr^d1pVZSFHvXVl9QFT&nj_ABEOAo^)qI0Fj^+??< z=*&RdS6(3Z5`vty)F-xbc9edUWl1^dea&k1g(J^EX?F(R{=ta+6>9`Bk5F3%>vzvb z*h6u?xP!Zn7oe&R$jkmj2ywM4*0(B#kvEB8P-l&;&!~qG3A*j;2*|_Zt#JcyCqUF3 z{1Q1j;6t1^4?8kKsVS_|4)wR}z5Iy5%=5S5uI$*`tiaKH31!&}JZ0_I$P{=iTh3KE zw;F2Xz-Y@`u*>&=?fV_a9zC%zLYn^&a+@)78P3N82_d0s-ut#K?eTFcQQXC0p|jQr zN)WS%(IX3UT7CjXwvX(442)RHvm&P&aS3fiul)&gR0(f=25Nz37i7PA$U`mI8{dnu z6??qVi~*sW%Emehfv4HGusNm0UEIyc*e2x)qe<({L&BANe z2CUj~LHhDu5tPoQ2|8bsB4#d{B!t&|$Or#irA|~7#kr&cP)PGjuhJC=%F}|D}APbf~e}28o%j!Ym+qTb5NKz^SCP4UxQ31s1 zCso0vZ@0Avf~3RVI&gDR$-h?Wz)|vX-0`)Sls03G*(PvuYfJp=8)@H&BWPKETFny? zG2huVOCi!R-wtw>@JNw%B1Mbn_K)C}P4v5}`jv5}_TGm2y)~l4}X;H5g@m@d_+1fpKeIM%wm|`a#Ij_hszEkI+xnQU#jjPvnAKo+ab}Pk4?N(1>=c zuz~?@tR?Y_q%*soPEPlY!FlwvozV|zqK!}wo}@`6&X~Gui|&VN99p+D?IHziov}8tiP*cX-P413xGw-%lPCa zSR5jUv0@|~27UzUTYLRCwR_$>1he2_D<5w60!Zah9QBX023(dh(^9|NdaKZOuxEE% z4}{>=uDMYBV*u*jG`U6f^j$nH{{hebFWp==#==YTQm`O3p(!*Iz=K_n?NtG-8a>qg z+^Lp^odT0Yt*^B(GDj7K3kB{%@-u{+Ju9`^E?fT{;}aY~3DDkpG*L`rbjvBBrNpf8 zYdUA8MCKij*9U9MM;n^<%te&5pqsPY@$)B5FO(07>y(+ZXeI*3Z#HhGkh~RCTTC3@ zMT|nQfkn#`G;55SbD9(OG+YhGyC^SS1)hBLy%T#5d(WXK8A%NN0Z>v+LU9(?HMY=1 zQDejO=qmA=Ck4mAyrdgr+z&sUSr4r&(Hwv^j8T+PA(zIVfw!n=ZIjO19PCpl%}u<= zHnKRHTPw-90dL7V|9eyZ;w%LB`{cuXVyRr6A7XST4Px}^TK`jG6xFbfGdR)*{!$$F z7TLRtL`6X9h}q}HJvF^@4!T9x&Z^{jS=vPhhVGfdedvdc*z{tRTTWoH&_Fs$gnvz9 z*IdnEe_aJ@T**lhzop_G%aq~cHo#K1Wh|uj8{BR55bZiwetv> z^g3ie;+QE{??}AbIs8y>hsg!shznJy6jWST!b7fjM97MGZ~EyePyRj0qSyj8p3;f$ z>!}+4)~GRMd`X3fqKV zr$6JftxLT?(3I;QMVT}sK(|O9erw#3XFJ=j^lI7#Z|arbF8?%Uf$3Iq_C5&Jn(Q|w zBvlCBHmHHwMUL_TLkk=*ewpkxo5efUJbz0c7{EN?!OC4zN0#?q(Eok2Irb@UVm&}q_u#o6$Vd%AXOX7Kc_m>jVEw& zW>3j<}ZClbgHI6B>KQz1>V9v^2XRVN@3Qd|w>%fp`rN@*N zcxko)jKdPf0lXA($g9Pl?pK^Fw<^PEp5w+M=S-I07WPRVjfG++MnW1_9lCy$jO(3U zl)nsNL>lcEeX;sjFsZIlWV^RB*UXK|>E<35cwyJ-2n@m{K8+!Xs@Auev?4ks%Zf?* z1JNEjGf_vZ+4covCV~=Mc{x{;(6f%1cb6aeZUFy^tJm@GESh&LhB_(9vhS1_O?}(q zDswb?Z5Y_1c^?9-)S_x_T-G2jZaMTtZ<)IXt9;<^qQf{TC`;&u)jV!*+4AHm3O1-nWV5$hGjb z-EZ5S$Z|vZx$1U^DAo$bHEu4(r?U~ejxNX^jbmPDJKWf|5eO(fCj7Fe#(F0wK6k`8}!L*4g zn!r6$3=dm1iPf>s^et6nMRbjn6kcjtbQ#=Wmg*00^3#9=~Wvo+l= z28!1uY`KaXN27;N=Jug8mJq{K)RS2$wSC0@$zY(Iu=A>Xay!-lEz5BG1OU~Jr z+%0rc{VP~tU?=WR!1wj^>(C;e=~cE+PbN7?7NSesuNM{@UrvCS^Z|F=06XgzAbHiT z0mH0xq!z^!iV*9X`ND zkO0cjs1Av81!I?RS9C&e-s^FwCBDc+HNZZ=u-zrK0(AwROhSW3wqI_LfTKk1%?y}>ujX~({qG|<+XhlJ)S z)aiwZ?pQBVT~r`|H0IviqV$>J9vTvDCslS+z6_c))d?PEOV@qqlr1DjQi|diwxD5k z`z*(vG%i5~GbSdSBxOmL*L?s8gt4f(8p)l`{FZC{jOL<;zTuL*K7AH!vwB?{yIWy1 zK+15@^eld5Xuuze-)e3{fr6OgK|B5H4>6>MCh&w|5ny(kU8TEdIZo~W>G$bUsB{Nj zRwXWHG6(&Xg~>}P{YyEtvik(cg|uVTf>kF~Gjbk7L|&Otj*5yGd^Z|y{l0PfPl6m* zN6Xk5uv`9Z#D@!$Lp^I1J9oE{#fSDsJLk_Z@Ap(_YiM*`D%vq1tr7=Paljaa-#% zsHOSvnmo=h`gAHt{VkldzpRMw;5rak(~}J(Q~m>Q%ni;&xMKQWNcW*fwrBeqg}=!w z*qFv(aTs1Lz=BxJex8y3WexHD!|R2lG+Wrq=j4Hpf%1? zC3c&$MS2_`LWT6vKX&mhB6gfO^U|-gB%BMsqDOKeQ90sc>GbJf-Cj0bP|gvw)7TqM zox%-j&wj0@Nr-4L}89C{QRTRIzd%(;yH!^Vi}R%3s7LcTV?M8tAKZS`vRfSCY2 z@jM)M#^>vN*A4c8=8fiS`{r2OM4eQuU!n=K6_qijD~yE1k-7(QIK^`>cxD2mSytbr zj7d*4QOnE=PYd35=zsCA&wr}YCJI1tpAkwB&Rw@;5qLs7DQpdn2Bb7SB(#`eAlgja z_=R`o)laLtZ5KKE8IuvCY%_HGHev4LbEk{~Q_X#N@DnIl7MG^h_xJGkvKu>$#b7X{ z2H&p&Q7^OyrKymwmw&>|h~lYHr|tQQs+Yfy^z$k>aj3Vhz9*TT^<1 zeZi)4k31jsxF18)$>_*;qD;jRsN*)Upb@5fCACR4-QD|ZsjBn;uxfa>qtza~MQxY< z9kQwcHJp>(O4k`|RP_y>D(NG^1;@>Z-RtrDEG0#cFO&$oCWG197*H>@HQ86x01pAd zJ(kM>+*;Su%sd9y5>A*{wBscoM?}1@U2H{p^BDe z2GNzV)JSqg?je%lb8rN$JPU0jCjpLL2229@!n^k{tqS(iK#1j|?=|SnmU;+CFS7)-CKK06Q z?6@7A8~Obi(&+7Gz$*-623fLaVNKAeNoPqI#508_)~Xty4hR0kGEX0o#~No_mtC zLRA=xpVJ6*n(pp-6T|n1*Et*`!Xlz&{-chp+}MvoaEGstiANq0>l#>*HqKd2S3?h9l9o;jIV1Y2$t6PnN1*hZoskWV@R=Z{VPe)(E7q}7I^FxpAGkZb_&a+Br}giCqZU?ipq%GeY(#PiSVS7r zw+>PBms7M0n6Ekx%eO-Oh+i3S2l$Mj7w8U_*dnS9&E@pIR6M(ryWL6Q7FM{ob zq;s2+PfiMOIlOElDvf0AvRgMUwO96{=VI@<+VxG55xS5BBz<2XZMZLF4dfbgJHLjy zoK`QuEEA09%9tc|XKaoVYMBD)5l67eCthKN3!eUzTc+A^#Km`j3BPJ%m(jl2W<%Wq z{rPHg)yJn~$eQGvvp-&)tq$AOUu3UPVJa}>h{5smFv>bRPnO;@Qe0v6)>Z~hF2*(; zK?hc4hrVOA4=?7Y%qea98;lWncX)S5!WvngywN;MIPIs$p=Sp9WYQXJK>S)GGRC2B zr-3%@J?CiNS8~#MCo%&b?yit>Xf8(3V^N@xG?qBq!V&mIg2A0`tJAf3E}F%6B_iZ^ zt#g$;IK&m6%*E`WQ?7b#{^-fRre4vP_QiFA<=pQv`sw4Jx6sszYFjtM>;FXtHan;D zlL#TGjw(!lvq@;v1g96KvszD6W1kb1+ZQHuP!I|$6LsF08zjR!2g-xwSAJv=SPd-z z`P?H;chpxWRVhfEy86*9b^cHD9piS|c7XtFGmhscT9m0YO%6R`5(Fz`7PK}}Y#OrD0g5AQh9LNZC_aQz?)(B%z z21qoRNWOHpZJAGs`(-i!2purhD=&}TZ{H=8eEAmfUHPV9t6eMbLx!C7$FAsNz^NJj z_?<=kY0d4GC$PH$wv4_0X*zG>=CzszJ)K!HR7`ZB;%z}CmC4Qu&^~a_-sI#q+-f4{ z_1eQ6<06H+&x~C0Nb(CgD67G!YW*)VK`|Z+2Hpj#gC_@ctk5P9${TnZEgfW1%#ZBz#qkdhoLlrl%4kNI^1pskJ zm5yZf9c$}Gj$?RuSUfT&p2W)$X-r;}nqkD#(8Th|@#ZxmLkVHAfJ9I+HahYtJoissc{eRZ{7u zr%weKJ`NpQm6Y<#yx+G+DBWNv((x2Rd(|3icR;keiYzE!in#$Ek**|My~mn<2ZWS~ zNaPIeHgcLH&z}6BHJ>NU%c~77SY(@~yC-gykV_xpk~e5|{VH1~!zU$DxU+kWSOM$hFLk$v`3}0F&wkC@NYh#iqP>!=! zXuRyNe7JKq*hoC|jmPO-C17A2G;AN6BWa)=xd%c!jVqojXs`>2iFlpuNxQ;Y)xENk z_~?T4kn7=ae~PbdMaGhQ`WyAxz(&pL*Myh}g0i|cp8!({b<5U8aZP?8g_jRCGbEg} zvlbpQifT$ZNjY_+-PqYMpe(2~yv%nbIG$1^h863B8PEoT88j3afuz;JtV4Y=T-yQ4 zC}4WhqVv0Ww{+cb>f9MAeoa`@o|R(-q%5ClUOk){4Mj!^)AQj9WHx)*U4vj1taKmP zS}TFn%l_2_D^GMb6D-q9Vsf+OpXQyOA9u{=m6_rQ3>+!4eW7j<9pC)`K&H{doEc`R z1XM-#5cv`w4#L%F$wSZtN$LDX*Kb|n*`KUqLDAn@&(ZikF0Ph#-^#{Pzp>wEd5ppQ zlA5z5xt!Wuyjqyty3>(zPNySrF=`?trccfkCE0485%|E5&oe1S&2!t*KvwB@gTJ4f zH?O$&xHE%nVr}Xwr%J>083Kg7^&-b|T@>#Gb6`KVq73e78-p>*cAp zEs}GyL|+VAY4m|4B(f7x67>YfBXwp%@bc*(wC zcQQ0!Mkr;A*6|pqRzFtpZ`L{AC$}Rbpy-NIVQG9mQXXVm3*X++P2eg6rZuNhqE^?+ z=Dz7=E<)+1U-4-Iw{6;L*}KvE{&^2miWRV7^-6(#hQT&WCl4E@s^8fFKS030x19UK z*odH!Pr#eg!A_G7)s=FgrHlsk<9YdWU*9SwGrWz8rEGJ=zbWGu0ke*=?wxS6pW42XsKeOj%1oTNPj&Bz zzBt7f1L+z++$q3ZtDiMOx^J>-(4b@OU2&W_?WU)R-_2&F-^g z*|#XS6*dS)Nq)hlR`*8YTBJk1jUip_w0zox1CdP$B`>OklBN71mewZnS;CsP``gJM zfyam`s~9?NH#{3OX3|0OD}d>6i`h> zv4K-X$odh$fd~qWDpXvlB1emmDQM$9$VJP{=~D3Oy&zUyRJ9&u$))7np13&U15KKy zIoCbgrPvCBcB}#IExoMKZBU%Y7dXA_{@4wSCpYtnPj|WKa?1C+@*VSTmJG8%kns8r z@uj9-gClL~mnER#C+ptzR0Vc5Vmy+Urq}5rCs8EsE^F8{O}%!moU0TXj-sVii+h6RN-;8SON)v5z*{> za-KsTQM9d)88^!BYxmoUWA#fy}#N%oJg{%xZgqm##AD_3fwu(LBLOEFwV zAUF-r+vYQ@>!`}(9^Nrs#A)mAu^ycgQEjyQ4Cw-|O^{H7c%s%YRPJ?_SFYr@MN$X; z4GbY310IqDSlXxyr6+FH+}^G@^Fy)qO?&HtqR=G8U)9qGG(k7ywZCx@bW;C~k+U&XfgQS;@-A1`!JUn^4;E$%f{ma8V117Kdk+;OZ6=T3Sa8!Ec_gBN<-J z&K?wEW|1W9z>u}sLcXp8+7_m1*Y3?HrZ(}D^S)WNIbniAQ_GnpOt1t6KXHv@)%Xjf z)hV`Ccwv$^1^5&+#?8N$L2Dot7a6X;cts{BJBYbi9NhvahN8n}w77d%&ongkhY;X8 zqbvGcy#n91?2!uznGdo)=7JT-uH##kun+tkR>r0s7Zu>&JfYdy&U6s+FyUpg|D(DA zNEG7&<^+O+YmF%bEyzAIC0)(j{eTUwHsHkQme}{A*_TSVhNs+i0e%4&WY|jYqk~m0 zOXDLjs9n1Dlmr`rT62r9ly2n6suX)ga5EB<7SG`?*l)1HE*H1#NCcCI}B zFMKUw_X*M*xwemR#6y~UBdLnna4`HuLc6XR&1?%~9K7?W8&pu`i-zTIpF6~IJT$x2 z=zgVN{y8;p7xxz`(vJ0Bz|#Jb+l?J1Hl zH}*9$6wnBdwJ>Y;N-xf#WaSxXBbmc+POLKjgDqfom)LPupwBfe*-5>=_7!gT&<@M& z`N)2bpz=hKL>X7vT`6BKufdHG;^EY=W*44BLDTpqf58JhaF8PY>HAEt!;Bf5T#{)) zx#q++$d%?WOid{-aX$A2@P1$z$NP-!_m@cbBG7QE%I54NW@h}RY;22!RknONV(1kK zhk_+0>)zr23988@XtE#rUsitSjEG479y}>F)*=chl!x+V#^*09iW>59Pt*No6j*4+ zhiS|M!yhnxo_?g~k!b-&v9BLP1Ww9x17cc>b%%mq2y7NxlC;UjcFjpc4~VA;8_iH{ zgW0DC4`XcVfjS3s3e~{l8KBdk0(4R8Tjx&zNDZ3ndeXdmAUnCetgZX{;xp!^)uv`# zfIR`TN=qQiwYB_D^_|e7U~^)b zCrT_seH}f~lCb&vZt=E97$KSr%~?)1W)wAR7R4|hf_4VZ-?(0Z>?azp4i720RlpR1 zq4l1vReL~6)s^}?m(!(!ZoD5ipB92;hd?wAZ$A z&8?;#a!gxk_6%p52`Ao?F~{>w0M4fCsV>I2oFFvyx8BusVG5S3)yUN=1Jqs!DF2u| zD^S3P88jz8t(Sv(+?CZ3fe$QT5l80wSy00SG_?!mskHep>DkZe2fHS>zRMwpcRB;RGi zCq+fILq3YRoH})tvhn~m#`vhEa6ui!tW)=t>54}tiBL9GE;8jOn~ep{JUHoCj8r}f z8{=Mj2rp@>%wE}m*!CA#N7Qjj9X*}BMXD$CQ% zwMcCxV!p1OYSg;PrN(7#wz`;vO~rJcF4jl*eMY<$^sBeID%x>lz}j;9N%XrC9w1%gQ6EHztw^x*$vTv1=KLRDq{&O*wJCYSue9z$~(L62(1U=<#xG zxvW8G<@Du+10?sJQ&)iIadPt}6Pe-S3u)*v&t3B^;n8(Bdo60x?a!SlZ1Esqvh5}xNX$iFTl_5(5STtP|n@E8Cv++YMjE6 zX&ZKR8;Xs51cSn{Njoj-uIcbHuuU0KoVbSloEFDV#II)u58&wX4Z}-Gex)EuF zsf8aeKPU6&@$JuRb3UZf<@#?~dd9!(Jlxl?wTnhJN8*F|LBRF7%=-OdvB9@Uh3$SS zC_SRP;s*3>*}5UoDC=$^V{Dm#IfSIOwV17|8-c((qT&f~po1LJzB*Xl$+bjV&1Ged z@F_Y)*JeE%Y1Zmyoc`7a64NR&QeHjolH$XPfaKlAn!>409C=WToF&s(CH7ws`?(Vk zj)Dv`!n)u1SHg?fDaU}|Tum=1|E_BRQ7ZYj>*(b(Bp+|gE`SDP%m|kr|ITR9Y!aLz z0@pnC{VFoq0&=g*4$$!4h==H5nqM7ph}(A}cmjf3;p{uqe@!q6M@-+~VcO-uEq68T zRGcF{IIZGstPP;%p95h_wV+CQ0_@bgK4aktEcq0~6w|@cn%DBjC|;GEo=E&N>d{9{ zyhmLK0Q@gX*An1ig=D=GCtVE&c*pO5?iNp|ZZ$yCpy((zXdMKK*tDbMFk>QV!M_EJ z=>6N0`xzO*z^fYv>_S)7531ellrl6&vdNaH_1KaGmyFrR7ej_o>&>z?UNkC0f{F87 ztcw_cS?cfz??4gL(I9-s6OpbGVF?&+XDP=JQQUEa?NEVv8MDmf-283O^7njb9#Cv2 z0?v$`FsQ9S)KVCJIBd@6Hb|!||73+Iy=y?+GD8$*@FfyJ)!lZRXw9NHEX-v*)iS_BGZvkYd9R1ryDkvJK zWTeqz*Yg`^tz}p+>wzF#n=6>~3)WCfJ52L)Kr;2hXh1#=o6I&)Kj#`%JKMOEcZS7) zH6Wl}ZkNYXUM&1mCSV}e=5Yj>HCsC+{-Y18ItQIP92)W>&@@EJPbaFJ1F+IQ$=;4@WkfAw9R+mED*Qh@d8;r(3o;2jUrXqSnE@wB<(*y!ymb^Mh<@C{P0m-DeUqV&XkjyT)Dn z<0l8P$ZgTg1bD2y=wgn6nU8(&s6kcEu;Jim=N7eIy#2a3G%5~vOgx_bj2uk+!?y9K zU61}dKs8f=I@4-U7^=b(v=MIdwdeUJ9B{r8VTLzC>;dcCG~tZ=kEN+YFhoQtS5nit zeZPvJ9JppjicbOQ`8tMH9-?}_%Pbjd?F8Ya%k*el_9>&V2e9x zz{q!)1iy8^RKU}i(+UkBtm;%JseC9Fa`LKh#+N-NHpIw1uA)F8Blw(PBSDV6=MP?TvI0w#^|l4-u7r zKoL;S@ACU61@|Nn7i#}=XCVd24O&2(etle$L>^%ib3ze_hO4Xe>R8eFuMq#+py=ds z^v4Yz7jS!0O&Gsf0S-XTD4IdI(TZS4-l%jqas`xTdm}>LWZ$$w?@MI#de{2aw>=Q4 zQ~}U-C$`H@aM$@R2=jUFWjAU;iACfiX*T_~K} zu!g3(dhd2k9zt7&M$=9x4eCm;_8xYBx};W*;Hx}}7oFv2NU7X=P#pVR@*gxszV2T~ zE6zteGV$l~J!D;%rhP#+Ba+p@ozpDN1odX&WjIGWQ2*Sj8qbfh5YMUL+7#`}@#ebd zBmw<6fW(sljGhr^^&$n&WQOaP{CRumd2Yz)eaOJ0BXFKBR2EIv}pJBS#*@n6j z5@duPy^J@l+M$wc-X=H5eOBU!KoF>Q0k{R9s^*L6UW(-m4RoCJn=Uz+L_(>RqY*U1 z$F*nZQ|4|{qv|-VO7Ob>WbL!w3jT}!KZ74hhMmekM~l{X6p5yxq*r@CG&9SIYVefN zFJ@U^zCOBfjE1z;Z%Xw#1B!FaQ71A&fQ4$ddGKU&9ZT}|MTg)umBiIagR$aJ7ql@K zu}MTHRfs*w$?#&yw9|^p*$NXEgPjU>pO44d2&we#+WyW&?oA~~|Ar+P zATQOM?^OOJ$56gO@fL1lAZStvG5NQi0ms<_hk-C;t#j`XG1~{d0)h?4ca9FMWwXk7Z z-%l;&c=3@ls`F~EGHjEInaWEgDnH;|0feJb6~Py1jtqU|wlp}8+|zz`$*H~NWR9%2 z<+Sj&Lfd))B*O;1xGpzu#Xch+JFpi7J-XS=HF%cgKxz!$_zh2c&{N zh6h#EOKGu!@NNmQjI&_V3a_1HwIzgTi_q0QY8}ha_B^luQN9UnG$@pk;=?B&K5Da= ziAtk&ejW`j`UfL;9%)jd{G}rc`l_C-`Q_Gml6QAT8vqmM^cT128iH(G2&f>H)_M(g zfW-P1r3*rU@_-`~OmNowMa$^YT62Pc(lVaNr+&W z7O=QnRhY6Lcoh>=Nobo%C3wy)W7}z@>oaCT>CubkZn+#aCvo2;kdTSauu*$cOQ8%> zCI~P95+C##wB9vQxN>Tf z{mqQV@N)V#7W`n7@kSYvF&Bb~mw^_hutt$v64{+fV0E)9Ep zWBwuwr+k3ML#0eqs%8R=iZ~)p$IOhnRd8#R(}33fA!9gbWCoKAaIKuTT83))8B$>V zlm4x^j7d4+`=})=%I6mNPOXWy=N07+HQGM@;v38?uLy29v@QcYjaXBilZv?l*hSiO z!0?iOG$Ug0nX+CvQAGu@2Xiwi9`vjsBe4I;o%an}97U8qr9N9-f2c#=TPPa@g^6c> z*_`p!?(`?9?aE&gOJ)3=UOvxpusVG+RPFrZ*=2t?$$YsFoW1>cqx%8U(T7tI_HNTx znSvl=Q7&7*M9S0D%49!m76MGQK4%`pxJ3}vR;2L?opXn8(HRD`QYXGUjJe}nWdq*m ztdf8w?~4DK$_LLlB@1!0?aab7TJw{rdj*ExEhhYw=eKgT*Z&}sMoS2l96H+h~&5?k8y zMRAtSnB}lix9q|T;6fVz$1wed~x>6g#sX&dKsOJo#LKtDH9#;W<*%|J)bx8)1m0FY&t3(DB& z-y#v@Yz2Mqv@a0%cpI;lrWH<~XPigtO%AgIXmy7$M$nu1vga9Z3es@)RUO=~#hV*j~|5 z2j@Ti-pCUv1unTbLZo@^#kwfcUb%YUC;ufdIgm;Y@&EX~3FWG%FjxKqqgG#iu)2JB zSGHMC-7_gum?jc!Fo=mdXo?-L%69-=DRyV#57fM+j&HHRB4(g15J^(15fl#0m`UE# zoAzl!O}lGGvBBFp*lg0{A1K`v(+xV&%k=0XgCKaaO<6kJkv{#0%ww$w;7)wh;b2Mq zsgzBQKXF@~%G~x(`miSo707`-zn{IFIhp)woyyuEIt=sKrPQ-adkC?7sfFYDu1iy% zISC`ExDgo;)O@5%kCT+v`sEkJry7cdFRrr)lG^zJv;T66L$IJc*siMwPU&-#9IqwF z`|-&F^T6SU8*7HDGK2Un|HYzkVhvgkAg`FGEBt7Q{o<;+$vr)|r4igEd988^g1Bb@ z6FYclhx)hMG~K1u-Y3eh#9|8{lP*-Ai(ghdm3=Tn?La@xk1y2mb^klNsEDp?+E&K9 zuh(lRG#$X(nX^gXSN1};Lo!N?->3EG^i5Y^aR!5}^VUk=xIh4TE!UD+O!=j>;Rc}D zQt{FqIauykUR6ZilBngIkZ0>Au`7aa*O$A^>rc`2QC|bba8K@$*}mRfVmL~?*d3-u z;4U1{TDfoXEce89jwobx{^qL14f=tsh0$18rj9af4Qdkr3Gn-pu}ao&fH-n9#s$a4 z2?RqOdDQcAR%IPJ-i-i&>AkRbF)U3$T(_fd{?Q?zhaiQ~;mZPY+%M z`jNU)W1829Hn9~^jxhOAHnGa7|E+VhO0Yu58M*kxy%<>3#^<&0&nO`N5@9B2msmeh zvQb}YN0a`PUdOqycirvRMn$L-H%k&TT z%*e>+hiAMzgu=d~-53_=hOfVNSmnYC4IqYa792lx!GrnY@@!Y#4Y$SxgTLZfW%$@o zNs9$Gqh(1*JK(VHg42NUkQmUUEM@u-187{1zXOSnf!i)mo%g85p11U1ov|E4j!N5p z`r&+ougE7Zc=@j&Q26AJOIzR90e=Eq0S14d5VZ}l>V1c{xjDjQfKGL9#$~VzQ{fOM zR_ccvT{*Mxg1%2$CI-%y8Eg^32Cy0)tYdTddKDZp1;XUX)^D>%mjow{+`Ho$&rX4= ze6!^C1!Nw<0LwOo$|ft#rIcPqEu{;|ZBgUu=uPz#5yY%na-QgBP|uF_KH*+C=eEKr zt`Zd`0~zIhsV5-!X04Ofd!2ek@bu?K#E9I;7;8#%z1RC$GracrS3h5p2{ifl&rN92 zQybmdr9H*`m#mt+ruZoovGfBq1Lc#vW>eBI92lV7V&4L(r2TLe!;ob)H9Qvb^;z99 zm_inQeSU(heu7J!zWAG0`^4c3M*z%Cdc}Ty_!Vd8K}g?UKLlV*mL9YRDSCX%F!v7v zATsx+WdlaUevIBna!x?qYQrMXMxbWVNPh#`qZ-wKrJ{3sey#hN_ z)_X1Fg}v*kMmA>vf*~#5WkU(L`U)ylPNtBpU1{mT-0n$%te3AR_p8}#r3L{?YmH#V z6~rcVyQ~~wmP&a>Eg8Dpf{{+fy^Ex+@^vhdQs8+!Ge)mYNYwc#;#60*AQtA>8$XY3 z{X#TJy`?vGU!T#?LK0BC!EZ!#&93Nb3zfdZJVIBv4xWU0A0*#=h0}kbL~f@Te(B4y z7;65KGP3qbUrJ(Aunxv@v{y)H}I;h8po^<`KUW>N^DGj3<7FTgxTk z<%ac6V4uokCu^2jjHn3=#~Czekh?>~3J{umPvG;-}r18O=1{y()BM_;|{ zS~{$kxCy_~)#5CNH{Mlw39n7;zSJlReJ)qxI8VatQ3kSJ%2tPnRkyZ_6%n9+Nq`mC ztZr>KaW!QwxoOYJ-17c!U~o~pn<9gVd-_)x?5SX#5ojFFtOWgjvd^H(MfwVNt4Cjk zm0WX@BgWsZ@Z#1{(*f&A^IHjNq8kMOGexI7#YJUOb0T+>qyhO(YrQgPz#l{$T4$APg+l_51uL@OOpu$nixdg|s!$Wo=6Su&PbmBkHSOuBg6XD6-3 zkgRw>s>}HHb6(O^=^{7q-88El>UO?mj}qKGKmRj3n(B|5UEiP!)98H2SF=6*euhE* zRCExc-7-Mtan`w=#=w|+Ob}0kCe9d7>r_Tz#;F>47@p{?7!v+Z9?CW+= z+qFJ3oE__>E@8#$KLVm3mw!Kj*zcl(QqyX&D$;e#X6z&exsK zaDY=C=(Bb;GRb)HXd(}3>jmiOqH$KBk|+7YyLy{B>gGArGXSHc9R3JW9k1IaZt!1+{*nDe&B$e+t}eL`V1+O0y(tj>#;W^OJZ6&DVtg^FLP!AN}l>5{V;a_`voAC}j-NLD8IVXXsGYD2ws41X)qlP)IWkVBoyJVa?R^ z&+o3n24qnBNG2n!v13~oII?(@u;EZPz62sKmx?4@rfUG!?-MBKu;6Mo^YtUV=9?C= z#&&nT@DhzeEFmXnUFx+yXSJknx{lj-(~i3t_xw(EFKkA~%BPAotmb>x8G~<7sdhE# z_AD$r*+;dr9fH|RuD-0%5lzVELwe$M6B=!1ceS9p@AO_W6g19_{h%VF1bcaI* zIJh<>!HGXZ)3|_vmwd~ScO!dI{y8MIK}|gUH6^en7jOQZ;`W_~IgyKwwSKI*GV2mV zZH8nm_f9`8Q&D&+YCsm4V-z~Bc}kiOyvmcOnBhWz6uQEn2ze2HxJ);=1QC?ekutaA z0dX~C^d3HrFldJ}W3h$bvXUoIp=84Aa5F&u3fs@nuLJS5vINc>knvkKY_bvk*6SIFfmULF{#?Y4N#~ zZJVh6cv|oyq0R3_Z#@S;VjkCxXR=wJiJpvC06ydYiJhYd8hc9&TjbbSt1#Ps?jFfX zE%^JO_d%!H>XKDoDHm~bs0o*)$+Yj9*=-3#1DiA6KRFY7Zl71ywxaJec*P&i!e`q% zQtgsA?)1EwpO}d$q;! zau&MMw2g)UY?P`4)?1hQAaI0ufr}(aX2*DYnjaPlceeW^l#f3b4f7{{g3Dj`2v8_k zKPg^3bGyfvL>`mISe4hYJC&)dE2T3W^n?yP&^3@Kiioq0vp#wXzQlx+2D=JFd#9hQ7^@3 z9qDxhgo?$6BfsGRwgo<05siWWqlQuFvlEF@&J>K{;Mjg?AQr0_1#>BK<)jK)0R`Lc zQHihXKT2QU3G0-Lo5+Maincj94fq-tOB**!fBH>Y<%-ctoE0cc8 z#-315OEgrH!D&B;=cp}IphXp6M!1*lJh}Qa?GU5a>6esaBA!&iGf`#?(01KCb02?- z+riqcoZUjjP0b}$GIceBybe2|=K&pACO0 zr5KbW1g&Fyje5$a_UCl$=xh5lZdRU{!J4-h#A=u9iQ$)+b;%{^*4^fd;hG1_>p!#* zgmZ;p_7h0n&X#ck{+m4Ddj$yNb_UcN;VD^ zbF{GlTEr%3O!MLug%}2x_bMAlB=NkU-B~?b9H}|r2@Ye>*;}Uet7e6Dn?Ia9j*)zk z<*VXp7NLO;p53jaU$uG(+A*6>cN9XULt~l%X89~~(H{A>;|L#TEG{U(n2!rGi2_V3 z!{?VTt2=frK{@)b^6jLNM(u*OyDbw!C~=oBU->a%&F&6YC5=y88$!K|vH6h;NK7h| zK6L1C;Q>XK2yab-UPA1nuueJ1Fq09eEsdng;cy~NWq&pLZ$8!F6 zRT6J0kq-|;a6;=mT73@S{iy`=$;E1IlI}WO!6DJywD0x1=YGV&{K}M3=`X6dwt+d9L*O24kI4e?3M7C?=Clz_NGoMcGHf=YBExgqBZ? zG%08ZDHn~4bOnrw^M`LhjwvzK#OQ_|S2ltoB?;jm8c!@WirL9-o=?>Lo7;hS4ZF`g5D7Zr7_=ws)voa^6h8RX(C&d&dN*Waysr{=+Jz3qK(8|w6$QLfR1qw;xOZobN%Vo)(ovbAszaGlyb zMGqY|5f0|g}==SDDziikXm{r;nVqCu-F(n(6s7+DVgop8$9gPg^;-w-Lzz>a0xowwA z)zNp&J*E!+G!yfeY@d9i&vn;ZHWgV0~z+C$AtKsF6qVExpl%bwV{dY~%d zX0JpcS)M##{&dEp5G3USTi9IPYOWam*zM;DEKA=Mb>q}I&As^G0cF+d_(2Z5Jm}9j z(YA(Ko_a?Y!xV@8xN)7rlA>VFoOx>TAqpsuCn>xaX^-1&Bq!gJkO|Uv<-$)K)~qN2 z{bA0x0FtIGoUNTB>YT3i76B6zCukLZe>ZKMaXs7MD2*XNP@;GE(DrRR14x|RSjM5_ zYXvt8K-SWqo+1Or2aiN4EGylTs%JC=Se#P3+U5Z_-8HCO8}dpV5#ULpqI%96yz3qT zm5mBAw?}NjaTE_@P47F*f-V5cp72s5S+iHc0_|a`B(ae|vV<6X2R;04EKPJ3`?>vY zmqSTIer=342-b(t0B%RcB3(0TL29Sau3&d1N=B3VUvAud8WD3Ti2>VaAIj7|8Y&pX zD+Z~eB=ifLt+pix$q6DRLBJTR^<9nQN-lti$Yuy82Oqv-n4haoL96~5UX|c4WErFq z#91tYbWM*lu#T5`L@9&3gN3=vQbZnx%%zdic4=Cg@jdK37Tx>{~4?bam$WJbI_ zRLkU$hKBlsVb$fU) zGqJ=|NX@=x!l7`k;eh~Uvh0|VUBC8~^z~{0fXtXU-a1iZ z1zQQ#m_$1ZnMVcx#CWLFnf9kAEPGU?+7u4^YP0@f)1>`273E+u^3A%)r2aG%!*7eS zfA&zjjaJYA1*`#qAkciS%gEfMQOO-{enQt9ZVs27%N$M;KfiOgCk> z`DWc(ly)1|*>AAG>=)ifx>I@*q)^4Qt-~L0pmH0J4v8jL-<>ivPGGcfJP69p`;abjTQA@Iz48iDOAs%gjBf`&u=!*?+ZfMe6y+6jKQB`? z*l9kZY`!~T7Y?bpwO~!iYbRJSv3e%?qy-+pd(#NATj;+m$v*A*YwVQ^5}XL$Zh#q{ zP~8fQ>q4=%(Nrn8E}wx*7Kq#Tv#g#N`t)6!Ny$WPTgI0|28 z#XP692Ebf9GBQLhs`Y%;rAWWf*1;E&Z6xfj zdQP-K(E_&}+AGf8nDX2B`6$5yNZmSmEIwqDDIwfOp$N%IB<1r^;{X&@S_)c;S^?`a zvtaaAQ|3g47KuTp!0uyM2JP?D9hziOm${fe0v;5GlFUbA^sgQd2hvF*GLQ88cfdqey3!fT@7KDz47&6{uvgm(v`=o?f^ zx)+Q$4Nuee7DHzKi60T8@6yc4j0y&ta8rQpw^nTp0|dqvRSQSbj(;9pV}u?6r}MaP z4td_0ZYm{=Iib)F-hqS8Awvt{p3i!S+`v=eiI%`$3|`~7UC6Wr#w~7DbtwQYzI7MN zV1dBsFNe^9kg5trU;P$t&Tq~5V&~{&o~nT*3HA0ebSn7<7vaN4wL~|&g$grmRH7&K zCECUPn{8l=F-h3YbDmB~o9<=A=8a~rusCbHRGk_eu0ygA@vdjUkjNzCQ!obSl7OMK zd>>oHV@^qIRHRzuV_x(rrA0<54|s2_9 z#evh}){4CJM;MUnU(meYmDjf_H=}@a;oH&taNSlRbHnjR-4uHFeK^+)GB!p|Af1$3 z1u6+ARzm&!8y7OunfmpSBPK~^LgzR-mL!I4myl-S14yoR_!&oWa|4j27!_Kg1)mWKWyTmH7B zzWhmy?Ito^>n&_{z=?mGQV$tHW{LBeVjR4Jrd@4}H09KMz$H(#H7fVf%=MN`>T)h6 zGF&|z@g4J(+5lQZ@%PE}eMG3X$DgR&FsLAqp+8+l8b}YtIA*sFbQxZWNT7*q?YipE zeP#jnvM5~=)=M~rJode0N%VRfIq{PfMlLSFfHeH@ES5U+%9Y{jK5%gLbSav$Tb*Ir zHqu)}@j_9nHO-l0FiP+V@|ihU@W)CZ!;x=>M>LVsr&CRK!Q5lRhFcwyyunoG5xG|l zhBUj7ry+ucUQAHn(X+HC>$Vhz(@36~V)gdZ;J2TXKH|SLYcZ|S0@nPNbk=gx<~^qL zI;$@rDLVIKeCCJoH}P0%QvNFq*CgoG+eeR;$g67kbBQXEvh(e^vLhL^`b4VL+kMYCNCS$=#OxaIzADVz@ z63Rlz&d2*nvw)J&ozhHin!mE*HdA?H%M z_CBs}KVxyR%SGi}!~^E>HtbTR&TPLyS}6k;k)-A=l5qL1h6!hEpZpYNkpl$`Pp z1<_l5TO?^a&RdyWtqJjrrWk74(U2r1jpB-6nx*V%UJp?_IPk{A1rg(i0rP#EM} zrDC!f8oApHZedGL(QgdQY(zA@8i2~4JQAZIk;5&2;<5LdwklV*xIpi35@q^yBJw}x zCNM*m$M}mpV?EkS0KN@9Cg9GvjnS<1u8rAGn`y@5-h|ym4b0@HO0Q=D*L0iYBvJ)< z7cK26;5A8*;6@vEdijwLox{JMmP}^PeOhUP3n@Sf!K~78|8b+QJsAqEK(ae>SU(9t z??(=-{!YQa)%Xmx$UstkC3~3lqWXwWZM()EJ3MAYkRnrd^|zR4h~(MLC$_Pdw@8{^E`Jj>%Z~=?J3+*98BTzC8ci%ngz6h-s#c6IT;X*t{l}n@HF>=Pd1&Yo2tef&XJzuqv!%>O?7BG3 zf8j`V@tX!=GJ`+~s*@pQ{HNwGHI;V(q^ZTnII?SfS#X#Cgqku1CP7(!`(m4ce0$ZO zwg!Qk0`QHb2|{E#Ao^^_IMi3*7RgjVk+EWr#^p^8-830;I-W9MN(a>~03R1UC{cI6 z#S%6jgBC7-qJgB=4R%cGuUg@M{O$^k^1BaYmulQVOjlPCT;s(%;kAm)VF>j{(CUrq z2_gQ!e2rJ$?%rD!0XIRA`;iuNE^k?gYPP0)9ZBY6lpAJ3Y}jx1LoXQS;Mo|suM%^E z3YcF$MApNW7~VrQ=hc%DcgY637I;?%s!tkRZez~5PmMxp z_LvAaydjG&?q=`Ss?4%$rsddYzJGiww?nyVY`Ib?AK?ux$LNQi@)%L7n>1j~7glyP z&O%b%`XkcqUUnSN?*xlLQ8CR5Ojy_(mw@-Z(JGNUfcBcZHl|`+zQzSAr-5`L#~Drzi~#B z4p3C40sQ8ls&uGcX!9Z8;z|s%abRSv%Wpx2QhUko$2q+vgzd#STgLpZ70<>~l>KjJ zKgD~#Wk&Dod)d(2|UgdRy4YYI3GBP8=&5GK>Y<0@aE%}i1u)qs9gS` zlJ50)MW|9s{6pv9f=rfJRC$_(QidJIul>!CR#N+ohSO*QqPO(MBa#v)JFV$@I|Zex z*q;tLC(vdRoUOWKs&(=b4yQtkeAJ%>TFp9`K7oOw8Wz{NuJ>0SW7C<7uTOLH%m3V0LdtpS4(&XLz3Zd zYD8FnQS$eQlnYi3;)&L1!=*i2>vwS3&(n3)vtnNBK1V9TFDkCF8!bk9LL*wW**}P> z-Ib2G=5UW~ERtW5?Rnk3B6p_6`xLk!3}1n01@ya?2r0UkpGV8DZH6-% zBJ;^JG+Wx7YHgd8KL9!0BYSACuue^V>k^ybkGx|k>Hy%|YrPCtJso_%+OfpeN8SfP zIu@4Hx%+j5`hWIwZU4hTj3mUt{6eqb1=b2w*Rm)d*sU1$+fGpi@u^P$n>KX0zSCiC zeQt^Tk>)AB83qoE5ALT@F-B*2msbwiRd1O@z!&vOnmfh4!>ZlD8c-T4O-{ct)VY?P zLe)fNY4dtyX#aE$Zn{y0 z@3OB_IBU{DvydWy*laptI0RfCm$4q%zi*O)<=lf(+#}FD`|%#72*=(?qi@^EgFPkj zby`?{O2;VfPXDAFb_ehrKP;;FLOG$KLTi_mb!kUYWBTchyDTLt-~v=p)5S{PGLUVu ziDkT7?S`N_FYMCk?n>2=aFS^{k|3UZs&BUlx?GsA>mJCpnEt=)fV@ao2|R3Ir_W{? zL1a#NE4@G2j-9xb=WkNEZ*$!60|OzbLZEUp9AWZ#8Yu z#diL&1_##!-};6JHcbe}ul<_gt(Mj^I2=fZI+W z+!>`%2@d8H$bEI?fzTA$k{+nWpjVR!c8)gX7VzgQ6ZiqrlQxw(5D?NU^9wL)8#?AA zDiWPpI0`6l5m}}9WCU8P>l;l!wYYS00@XSLV+$YG=o+onmC|JkpL;CrpG&wD zX5ZHeadh2%T!1>f2#E@YH3Qj9UX6R#Y&ZRsY2vdHi$5H+PXe$sg|$8Fpa9+r-2c!K-|DDEHBCL8edAC;VOwKN2F)~+ro(u1 zB8v8L6k6>{+tq|mVb+ws{wt7PXpV{s;NzW<#ihsKl!K$tPUM+`93CqpgdQEH#0BA$#^{~xuTU!vv^P`97;*7R10*P1ZSt=e8RoTzN1-Clm(IyrLm$+8Nk z|0?WHx11Q%am>ygMTBM7#pN*khRPqI&H|loDl-lCL@4qqM}k@4NrB87=e$du%S4gK z9d#n0o%IXi8+=zm#;Tp7xot~qUyV2o6V!B?5nMuZ(Q4(4(`r0gKTK6xS>Jr@WM$)1 zvOo6)`dLo+Or}Ek8kB2?Pn2LfWEpHeF`bH)O(q-Ei^l$QAyfY@n{V0d0O8oR(s{>} z^_*Z3j=Mxbyl8jgTI0uZ1HE!(2|)b?JmEe1mDh@?bFWMYm{^cS2ghmcT2Bo$;AQWY zjk{wzM9HEb>d`jWL(T<4Eo)+cO}mf)>XzA)=E2A{?MOjuGNb{>h*j7V2JE{U7iUIK zMYSPY!S<8dz=%2kK|sF0+S-vHbkRu_P^DNe`b6O9> zFk@j8XTNhJxfUVP)dGbriY)7^<~8_>SbLbXB@jSqc>j+U5KJSmAc@*nt-WoCb5f41 ztZj;-7)@{M{ZVjRURjS7`g(?_f`=eqst^pQcQg)fnvQfJbbf8eN4S$YKUR_mCmdkn z;8yJ`3ZKD>i~eEc*`YuHoIq8Ct9O%LP!=_3Y94FXrkN zxejBLCn$H;V6Kdy`G1f)rpL1y%5AI&iP#TR`wX6T_(|?}XNDi}GS|=wou@{18ReG- z%0N$*P>JbdF2fgv`ATtT{}V0C4(#YgEM<2p#xP?0^r9j|peIJi&~bJqQwMk&!GTMW zG4)$%q8JO@cYGXn^r|+p_SuSN5Yn7hBf~EERvzWVU6}_9D4D$q^W&D}S0LFeYtZ?g zscb^qli?bO^kg`S9A&@)L$`e{1vxB+5!^^SnZzwR&RiwZa2Jg7n4VQ?Ev&%`5cl|cP=lRC63Amy?Y#cUZ2yJA5U)g?aeV)&zvpD8N zx>wZWYF9fTR^zJ=&!GXJUmF2J6C`strxk8e-Duv&I-sbqk-iljATt*Fq}KZA%@ZB~StA%LzB>mWJOfZQ;$xg}rZ*lNcQ1S&LEhpv#$ zHT40w3~k*2%a9a~QA6~|83i1e1c-ZDL^^havVO=t1u{<3@jk61?kdI(qYUPkOMhfE z2D(0d3$=;YsDoIpjO0WAs!dWH;7`XWFzrbn>$b|iy%pmIDdvM$xX>|uK(od9FVK_m#I{Bo&@&&Ed zPb_-VaD-f_WxSd+Qgr|NK3$&eyBtG!SkrfG=jxq)+S{J07P$F<{_@U}19B(^V0l;Lj2#ztBV zL8X?n(IbbnwV2Yigvot1=41h~W%}}4%ZcYYaMpG}fY}>@2Ba^hwMkK$I%IgCP$mtS zsBI08WS*ubKHduj2(~%D9f`URTKsNnO$VTa*+vWi4UVXF4@6_}ZotJDQ`NuSXd2^= zxwoICZv|Q~jdJ=AO~Tb9W^yc7FVoeUf)cof{6YE4v^275xS+G&4FjkZ65~=Xb}Bo| zccL=Ab97N5p_z}zZ;Op#RRVpZ8w1*i_Uugx$_(6%>*Ahj z^}RUq*}|#rhlr_Qk$0l9BR6ll8zxD7`i@!?&T9|J=Iu$!AVo zMUr@NEv3M%N5%HPb?|Y9%L|fOxFMcH`7h4qh?G)Lbak0*WR=Qf@uKSX1se<1#!d~e zv;1hs9n!qp{US{$QkmB>u9AiM=PbIf)Ds-R2sK!B z&~W@~ylh*G_8L&kguWf+)aGc_e;k3aAa`oz%|%smid868+jyH5YAvD zD2aAu?AH$^ZN(BOCkHk_U4k&ohr7_xqeQ-&{G4kkePnlWfT_X)8{CN%T(%WcEFoQ5 zCkhB^@tgNJs*A}N9IyF>$EwX+{RueP+iqJM3|Y@T9+%00%6de4-7drXkR0!`DWbh@ zD=O+uKO%vaOqe2p zZvinbG<`*yggZfbkY=yuH-$sNzZ1|8I!ES4uck@I!=4O435yS7qSh@#y6jT_X8FfH z5qM_b4K_q~I~^equ-}=K=mPOp2Si*2WlABpM)Wgy#&^)9VgZYmD-`!$N#@^r-q@ z_2znkmJuu8?=EZ`q@^{ERCRI$TQB0%2kY-uCgff&I8FvRPKX71;6_!sSVG!S$bIl( z*4*9=l&TCdYxRIjC{=S-s}~Q=O~nU>Zf%?8GhBTK0tQgfCv~6}TeEL=J7{~+A@yr# zCDExeY3iED0?IHNjo__(pT}KE+#8uE`BwYfpwtuC`d96IEq*=~H*|3cTo4?5E~l=; zWHUokfCe!e-8Ja^|JmXV5@_oO-C;t8iRUlsQqD&^utpMBL1N3@qfxxq%Aq(rv)|6- zxTE$(A>rD8ZO+;IsHo;QI`>JB@xDL}lwNn+eB5nwkPCPW0F$_F>llK5pV|)y_cGT~ zsT=vrA}X2Do#`Db`Cx)nV))=xE4kb*PqG~k1wn(vo#!`LV^0f2Pc~1)JNhW7=KU|H zouX+xU=$Zvm^PMRj*o>k4-&@DKS$yu{LPLNfcK)Z@Hmbg?-D_&m?GDVLGg6>#WkRLnb44ph zE^{Qgof)!M)en!`OSPG0{BIT{pm!KR#>qhGf`^-Q{*HzPZrGNiKX<=Mjb7_w`7SRqGh&{zJbAoOuOE5X z17$mNLAxKi#tu-t&OZYq>RT~u^i(8*d+A;`Dl38t37eRG&$sZ(#3E`hR*(?NBz$J9 zU}Mw*3l=LRe|UNg9E|5{@N6!V{hu&5hX@jyna|R(^DV+x1Tfb zSIACfAmcsv~3D3m#U_yQ^SU$I9%T zsLlOsBBxiuR97;F)04)VF*_H8&Nk(aW4flNvtgM!_;+1hzd(%y=4uA%Dq)ap%uJY( zL`k#kOksd`m5Z}{-DdJd>ta$pxNUL;%R?6TeBs@0aqo7TlWI;V3sB$hW6(3LRvWUb z!2IV8j)h3F5=;~^niryISU+PW`tZVO2k&P z6)G+QUOd%aF{hXJRvc>ip@j= zt_C@P#xUN~N({TA+((N>E#q~1w-Dli_aJd|!a6yOHzQ*0CC+gthf1x&}*A<49bIasa}*vxv8x zb}qABj_}cM{(I%G%q-V8NUe*Wmw01#6)Vx5KyBFeIL!*hLel#gjXSBXh2{8_i|r0Z zP!vS9+0)`>?C|{SQz8LAHK5YC)q&@H7Z<3KyU>N-j`j-~A7cM%L$j}HzbmV1j42sh zq8Gg#^hdw&Qc&)o@Lr^?h|ZU{a_2hR{(!u>}3FuS^j2Ybd5cz#~W`u*9HRj&c6t57i%KhMC`l0-;ftZZIOo{|^Ftx7u9%tJq8}mCYWh$2g9YO&9s>+hMwGd%q&s=nnL2yd zt1#3Et|_vP(p)Yfdvtd|5X)=dM3|PJ4OMlWeZ*ty<1uch5@s^YCcXc{&(#R|Zj&8w zi9pc6Wr{n>)XIB9y7XHJe)ZL!Bxo^Gg5F!Dvh*dWL7mX3a_Zv^SeV5~zi9_%icHM- z8Coc9y#MO;)3C)Rt+uWy9Z&H|UU=K>=rEDR-xB@x+wH+18i*Y8 zz0l~eUT86c`^ke6W3O0tQ(FdH5t<@jNE@jeEJjWT$*DNq9J*9oS%4*l1fVRFPI9uY zbFM4@6b_Jx!B|3VWJLY^R!j|EYE6^3d*VH##(|h;i`lZ7@Mu|Wd_B3 z1hmudJvaODaH(CyMQ3;R_t--EoBMssvAzp<63?!KW4ct5BA@vR>vtSgAB6w??CBk> zf_v5pA!Po&8}pR`DdN}3gW$fG1#@?HUMIhXH+ULgZ!RK4ZXKK*Nf4pW513U`=X~Wu zgnZq63HYqe96i+k?v}7?O=KP#OhU@4Z_>GM+yyvVVQGRAo5yL=S!(xnz>8KDOc?e% zq3^5{N}3W`qhp-W+zvYlz}XC(Y89xAs|x!Y{Y&|La=R2&FZ}fxmwYwc^134FgP@9Y zh~_C{?oH3ir5{>_2;0D>)xFx5yAX1GggzoGWcju7Jm*X2QT=n#ug}*lrFVrA7Wd;1 z>MiYw$1AUv0=EfBSpyGLEOI6VOHb8EuaQ{nmRpfLv6u)_+fN3S5@;O2niY5d>51{; zH>-|;25zW0!ZCPoH<@U+{Fr-ogg+lWZ{0`wj{X|DGrcast>5@8Q)tqq58SIarSz+r zaEV=DA{;$B{q9R6D(38@mP&y*%tBpaGs=HSIfW0@-OUZpPPK+haf^nVKI$`k9KpWBsGMy~1 z^?J~ZCTX@NHZL&KvvIO{#BOCF+sv^q=GyWG4lhQAi$YQ^e#0I|OelVu0Q=Ix(mU?H zT2QSBc&N(Gui$fbuRyJD7(1)%I6?Btczg3Y6Cbe_6_;e1dpkyd2 z;c;S}JAp|HCf?uJ)ESJ}p=t^vB0vTv9Ruf-PZ1>-KeLM{@#_$^V7CroSeRSD5Y{73 znG`I)PFY1E-3!g-0Hc{ikI6&NT!@=2*7^<193`ncGtv{JMx_%?hHiIl`bLCjB1 z_Pk@LOrSevUmx4E1P@3qy$ zz`dcA$wEh>h?CXvE*NIKbI$W>1v!BdheqTsT9>&NRAU7}?4o;wXWv@v*D3fGO1V!X z4Qdo~xnWtCJkW1pyOztY29vvgwT)?qI&yOjd`e-~L@mlGkOG2JB#h$AM4WL2=yIoX zTA%tx$XS7NuvE*Y?q%H0mDG!pduve^e9QL-WMG@bGpbFRH%;k|8CM2{EBZcXio&x9 zVs+B^G2GSZc1_ui85bHh><=w43grfWI2HhY@k}C?XVnRqMJ8t1t zoP2LT1C3)z!ZB=(;Xw+av4>KPx6@8ai6F=GKJVI1H1j$%_v%Y@p@)mmdX`T8;nw)l zos%XTu0bzh7!Nd=r8R=j4g@`XK;tSzfH^>xOV?(Baw8fQFnl>v8 zW-+>4VYl3X&um?Q4-KS9Y&cMgy71YV)K$yWp@=}0R)VA0qcwu>;3Oo)+_X-eVL_F% za))Q`*}^ereiLcHB;X|Ee0@rQRkOYkM(q)a9++r?$LfqK{#LCMBnh6kUm)x<>&qU3 zUbtvd5zr7(Yf%*ssI5cCt_Arx4#lzN90v8o zBp&?j?#{iBUrkPxT9V9CFq){CxRt>7+%15KSrKZur;~LSf`(S(Vqd*%89M2qVBvv(J%VW1@(d8Hq;Xr+}v0TR{jy+9J`0p z+ho718%&=G&e|AsnNQ6pMpyotyHg$oz~VY_v}x;%(tFqwjJ1La`o z05t>W$H9_c?<}hU&hX-^RoQXQ&~|15-?W|dkd%tz+I+eu=iZ>X0mHx!lyje-D?+VTVKY&35bP zm)BrkHrml7Pg6NFY10Gr$~m_xBEM?Y^X9jE~7+7S|vf4syb?g%c@|R*bF76yN;Qw&DcXQ-T3dLw3t4Vn{wR&TT zQoGZSzVTZK7^XG-PC=!q5%O)0wl7y-1AX)YWA^}^*cXzZ56Q=_JR|uTq_D}9YRph#5&KKR37c{w3* zi-S~Hf*2V2fGvL^UEu=yli860+}ClinaOUF?5vU%hSb?PaG%U*SW5Xw2wD&;rk9pm z)W0ciFNT;{?&?T^Crg|FM*#HP)FEN~ES2rT{9#U&)Z&^`T;z+dpiTc6buqR;9c47PS-A&Kqb6y?;$* zmc#u*=b_v$3MD@%fSiWHqGY%@aGgXat6_-el&Oj0>j&z;w= zSS02Yuy17Vd)r&nu7-C^{PWUss>kqr2Bpf^K^cgXfK$d0VgrK77!(4j_MV%M^s^;jf5z4fxxXM1>+~RTUqQEu zHia;ucT|G#j>Hd}NTB5OFx=J2qo7}jco*ylXUDi%`76Cxzj?azXld?dSKDen%swE> zzjV^!+sIH8*_iv}YZv-he4#7w0JI5Z(UUTn_jq7o%Th67>%wr2nNS*Xa$|QMSLY&c zgK`GM-e8s-Fj-RrXx7@V>Ks+jV}639|PNkP~odq)2yGE{_?Eq$c<)`uKF>&dXbP@b|j5)sXz zxrQ2S(OUd&SR@H2KF@=phUGH~`1|(=M*ol7l~JW%{8qo2NlX#f-8K)SZVZpKqc$K z6BDR4^v@k<%lEOP=su>DB6=76sZl)mB$_4EvVHzIu&OSc{cLjpvR_4j>uM56pkj%& z20*BCa;t_)76-{Wb1fJP*dENuj1DE_MT7=B|9FLxGNZ~9R6V%f-q7#r-4Cyzz!Twn zHD8d3!Anv*7#$qNQ3US{Du5dAhou_BAhe``E3RJi*XO|zq?8Dp#L{?1`Hw5^3k0IG%Nye~ZBmD{&GF&Dlml`z#<@wArqEZ}a0?`~5zFs_5Vn0WBFlPNg_ z+#4NXo}X4)A;Cw5IW)G;POKpt{ILjXFz({)r%jG&gsX07Sz*bp-iep7yBq36*X7k0 zIv-qJhegB7Koib;OHbsBnTBPqAk~J6;CuR{o6SROZBS`Z8}N)qo?X{~ao9_e%)aQX z1s+sZxtorjPwuMh4$M3P_KtK+T~c`C=jo-U6G(dgUwo3Fu5DNEM>jAlF2h0d z;)}RWFWxa5!^xyfC#>!!%?aotyHE==jH%nhAo!1nd`2j!wrk_m!OIPlJ0@!W z`zpsxPMpD9OXuBfw__#B8hH2`a$?S#moj0^`in(s#<$q$F1i`J$qHh?a9th6yBiL4 zXgi>Z6pgbUVDp0JNM?m-2?jYF-?T#`dFpWzg5AF8-$HV-f5VrlrJwy^uRmV?z%lXy z8y9@hN@Wgf-6s<1^G4W!P$$l$qtl_VY};Kw@rY&@bwQ;9isI%Y2Y(W#c|PN+p!EGS zmg%CBgbN>L#yi@?MPduy_{6LHf>iJ|!=ec;yxGX9jA$mos)*&y?3dIGvyZerk}FJF zt{q9D4?7BCdlQ*IjuRYE95fzd=FZGp3pULtQEG=~A-LAD4?<~KR9p-Mau~)*a5xRg z8Ufl5&?e~WEc)dDD|4-{7W1_X#YOkXwJOPueoc&fzi`5Nd<@#4*?T3at?T(3CtF;P zimv`*h<_l5cNdIXhz3R zN|BL!4D9j2_VCeXP04(jx1&`cB^^F8t-RJn8WOJFp=t(b$~ZGRC||rrg2%+J_K23B z1W-1TfWKwc4E3KuP~2|SZ`VxdhkrVK(T1A@cpddyJLR=k-_8a4VF)3F?+a1`ngGz& zQ+p{Y2&=%L4`dRqJ1}9J;7XcOjmFE`R$;{pcXuEI3?GUHF= z@}|#oK0N)|q~ZtvyERwVbT0q=uQ=Xah;_%knXlHE+PDZuQRMCWK5MSk#uzlQ6oslrM`wozjA4WYK4`CMglG{tfC9= z_Q-Et0)#_s%Q^JRtY7_Ceyy55#sBw!csg;t+L(ait)E(s6S2{a$$QE^+3bZ+B{q8;M?El4Ja_!xN zO%)L%n$$lp9@gQXObYTrI+87m z?^J}B2@6L!{t=_mF7tT~6{&2FCsBvstF$S0xI&9xfJs1(Z^08L311k78fsLh$%Bv{ zn-iQs2>NiX=hIdk7rH-=(g68HZ|YF%y9E36mM}Xuy-_v9@Z#OY$pg6nXc=cF9Zj$G zYZYSs!MF$vr`bbL?1?Xc_&78SlI-TNAq_08D``Zlm|R}kUCQt#LHR%F4*s8^k+XuM zy=LqbHZ{cN0ag~FvXziovEssekIL8}b7bvmY`vfc;vr=QymhzDTib#T`Q~_Y2{LBA zC1PU`U>ao|=jQZ7RAUJ$__b!)k3FE;P~nSzr$`3!BQG^|BX9;Js_%cjQGI2v4(x*C z;eIpAjm_$HvzLaHus&^DC&~HRc*P85Z3^1zUer>7dr`y&L%(uNQwjdglHnwb84pzk z32=AF(i8!1fs_sewcr}S!99(M{itAAs%adR|7q;?tp#iEF%Sg7b7+XINf%=%s3=R& zC`%W$oQU5*%vSMyng{Ks2BAN1TRPO#zQ!E$AuiUedF0qzagHvHVP+ti21f;bwTKpZ zK7|D7;+0UZ+T+c8b#Y4l6IH*x^E)HZ7TQq={5Cwq{OhP=r}9uVp>7&i1Mt9!zVR4MQ>s zoKLQS)H3mhCi7pMu&#tPclW5x=|iK&vP0oXC7f#}PKp2k_M zPHVU9*G3S_ykycwUG{yh(nbd()5Vf|`iXV68f-D7)7Xo0+#3ujtKkf=!RYk^JzzJA zv_AF(UiX#2?+X#HqH1}nKES-pvdp*+y46X-3WNa92LG(aO&4;a|3*}TB^`Tgi04>S z`A^sLz;mdH^fB1;CwzLV$%YWOL|mMERq35JHd|?-L^30ZqD39(Mx>r7_@K8aPe;6v zRkS3nk`-{ng&lPlz#k`3Kxwv8*yF$TEy50l^t?<} zm?yCSLhzH;eyclj$Miw(L@}i|hmojj^FTwuW+e=yqMf@1&Bf~cV5J55E#DhXk<#lL z7+0;81~Iip4d8W}1WHC)blc~PChY=rh+2^6Q*7b|aiv3Rw+LnK0YJrGH@vpyxOz>& zz3uty50S_c9Oe6BBZD+b#tFkWWba-@H*r4Zl-WwCeIly#tQG3-3k@cyEH(Nv!XK7} z>f^$Y9I@Ot_A^dM3e^Z{cf-n7i}fk#U#Cp}He~aIi^X$g*tpW=nfP1jV%5qyKTL_? z!e(F~)jT5_k|uI)@qgrOK_i>jm07&( z9%yNcRB2`{xIIfGxsg2^_@oRea8hE2fKi9LylBo+J?tOq}eQm4YoZF88_O&WD#oQtb#Mj zhI8XI?`L;k9nF<0G+OUaA}9}})~C2&!)L#xpGr-bEql&QQck{f0Qd%vB~>2#dHNTm zoPGb?fZLa3F-N^cngs^QQHA{9j1+i0%a<1iRBY{QwS7|<>Md)2CtYWK{YR?qth&c8 zGYhEsAeE@3Sfo>{dj=SM?V(Ye`gK+S!q9M{bUwN)ss{B0ZzfEk@?41G`5Z4TBvdJ= z)?B|7NC<)R#6mIY!IjSCgT}EROPYsHaY9W?&n19?qHzcuIiUbU@}99-^Ppj->SZNF z>lanu0Vq83%37Lf@OrK;oZMWd%IKRHB*z~B1t_p3c)Oh#*MydnX^>{wy|%<`W{3-g z|BpHxhpryBCB$!!?Uo-A%IMOK7967$Uu{B{wajRL1WXZ1T9pEnE;m`y>{UHA?{~^PE^w{}8W<}l5uJ`^< zmWM#Al4%3kxbBYm<4CJ`8$oCxoK`cV-tX4nB(Jg7HlSA7SI+Emdl=>)=BM6VKc=;5 z1$g3CHbemzI^HoZm`gnI62 z+6by*5BB}knl{ljQFq70)4ViOq6FKUm^ZmdKZ3fsfh@d0^KH1X|INGDXTAb{jFblvm`zTa&V9Xua66+5a?ItyLUERyYiK+S%m%6!5JVgv)|uhSjPE_@^CLowV^L)dgAJL=Ep0+2XXf-H#Heq za7F#X@YDTt66sVMkPWTNS%9S0NmYcy-U?HI$Oq2p=JMV7ruE&kOfYKjFsqt69rwuU zAT4#V4LI=FaBrxnp-@$th3)+AF0ZJ5w zvSp3>>5EjI7(J}fX4A8F7RS$5vloO%c*N%vhj1wMg>{sRjqJ__;T328tafFQCaEqK zK>^9^lW(UB!R$VsDt0?|NlKygF)T!kl%QKbmSxFyHG4p|&0pjXV`B(FzUdoapq64M z(*p!MGnqt*s_v&{>Rw+-_)cczB)v6kwgJPWCEDA7IKn0sPbnB=b@A&J?xw0ah68odbu))Og_dLf5J;;iKx-RY<=0CBZW1 zNaV#F?QGuJmWNV5G1FO;v0tO(o}tM)Geqv}8grAvyaO}neE(>l&+SvJ;G9Mg;Q z`T^|4Eqz=!9bYlk^x76)Wnns$g4XM%Z^=}@0u8HJ*riiHaBCM~2tr;$sCO}Eeq2=OtXIEt(v{+fn*ymSHz9?i56wJgsI*Ex?LGq)hEm=< z0Rd8NQ-P{~(TE~ zdu|k*w_F!dZXL{#%*(BhkLTj%DtbwQSeIweyzq2&w=qgwtzU4c&cXi$EeP3> zapUq8F}Rh!x9ZB(?KyS_h;zFG8lo#_MM5w?PcT4LsqlqXSzJf&2PI5r&M=X>M}%%e z`&n!pbbS|3GO$kAXAz=FQ$2mA9Y(8zVC(uj))FGTzMw6f8ye|?{G2!w$Z@7|hv_}( z3KyAxpRTkwiy`x8;w*^cx!Kd0lx=j)&f2z4aigM>>)3e*R{m>sS(YK+_n{Y8@D5y)2a(qN;$7xZ{ z7!-9)w?uz|S~CM_uLaTHH5a1;d;|=-2`mcyfcS{WaMO5?%2?Ip~k*5^bSt?Z$@VXI3PjUFUR3cTdtaDQ3G0L$y zR%=2=Z??XWIplzoUwxEYJ$>YZYzEMC+L)114Ohz>Ll`y^Gd)G~N~D-1d7sjnkVkZ? z8}>8&5aN~=-E4PFZ{> z-i4^AXQa4+dMO9!u+zL6eM!?1-+19N`wynZ0&kBpCz+ZKitZe3H2}$@IsNO#P806b z*L8qDMJdd{780|4G-)G#7;f+8`?UOof-@^Xpg@v*Iw?%GNr` zx|5hKl9>KW3Fe7$MR?dPk{!_N)?i8Z?#}FWw?P_5FKQ`xIIY0Z;gP@HQ;y5Cxx%p_ zPihLs=3Kf7R_f0u0>9Qz$9{+@-54|qx@jVO`4NP>R(z9WGYzRzP+hsnCjjWd3{yAe z)UE0)*yHfIrrug|Kx$1v6zpm};GU4|Qz=VDv3V%8Qo`>Np5Q^p0|6taZ^pE<0hn&I zS7T%|Krjxy{|iMD;py^m)h8xjYm?Y0f7CBJ~+-$ zNgTgAyWoS0k10vJD-6&$fz*w!cZ`w~QUUgrc>G^|j1_e4kVwy9vL4O`f4wnu+W#FJ zvb)DRnUX;sYky%&!05?Ls)mT)0>br*0wwfCxU@j?b5NVsH)Py-MTrk(n<0e36?x_G zX911~gMC;crNx$Ouey92tTy*iH%dWMEF-t_M>o3%yG; z9d)2Vnwdy^T|n)^E=Jbv#X%bW?JF$XDiyc-Q(7(#3YfhEyVv)>?~qw{g*Flj2uBvg`HyMw)@Hi^-({xirWF~M(SzyVq@TZW|yRnOlLZKxr^L+ zHDRN3sE3K=Z~k;tOMz{%+hJ48XC4=^wAIzrvrWH~dIR(i+cB1A!@aMi{PWwBhJ7vu znD}#`gXi1e094-&cVLP2atO@KH#CI|46PRedR7I`87n0C-O1r$O}mJCo5THy0)&kz zKiuE;kFRCzL!4@0TX+MQ^R+ruY{;$P_;h+=UE}&wo|D27QaQ!t7*QL#$Ub~YT0;Q< zD=RmiXtTwX7#yp*4) zUFCu0zPVS;<0bHxeX)CeToO+fwCYw;N5GHRa;}s(3*6}G!+}9UgFi_{U37q%J0>;2 zq|Q27cq3^TwqkA8($J;QH+!a~jK@}gMF)sTs*nA+%H&t5lLjQ`MVwIE)|H?OeB;uJ z(BonrriHj)-ve4_lhHe7)=+MPhT$9-#=2KC=F2LVvfY^(=~|Lndb*3I2$*N)Dab~- z^ffaA^f2Zjymp#8y@UO?%F5{cUC2=Bj0P?GSW9;8Do+btJ7Q5L%-ZNaZIJ-S1OmirR?kHx_M!psHE# z8l&dNDQx$4mq`Z^jbTI;%pAvb9>wj<@%U}RiF5d3<>scA*qF@qcv9@ z8Xo}ejxHVLy}#-(U+HqC{{u(KQ7OlLC7gliQtc!0s%R_rnl2^A{{e@gx_{9XHH&P= zlBM$%dtXP%t4MNoK0@wST-%5`*#B_bg=4SQRj>GT(uGfn&aaN8hb$r?}KdULafAIR`YL?w3&R!K@uk6jj&}kv9cjxaU z(9KKmag;-gzeZMe)v|< z@_0;se!1H@i!Cwg8*}vhw3h!Q00qgDL5qMK<`DI__-vAK;6*lTSu$SF2FNnd+Jpu7P*< ziUUtyooo0-iqc|bU*f#a#uAu&iPldStJ;dvr2H-`SFH)K9+smg2yLBu@})O*iK_$J z08=wIufa}IjG_L`x$W!E`mY1M8k%OYlTCRp)M2j^@kn7F`}gIw3Go}Do7Vo#%oVEKtln#z7@{U z#6LHDk-i;y(0j+eGRO?NXml#^>QP`I10K3RtkuQL-0|%Ssz6w_zxa44ypbZxgW-TG zdAe3MJA$cG0+&DhGv9{4_cqH^D6}g%0ERs3urL?P*nY``a;vDAgrz&LAbPG7kT8_g z98Ny$#^WK|7_b?%n`thHly0b#NUw)u^OfkIacvwpQ82sX{o0hfhloArJ|QnQg`PFM zvaY3wvau15n0i0h{gBJF$R!1=W{@XXX1ZVTSlG#o`!J+ZK#`p+Z5P~wWW)1BhJ9z~ z-;s_amS~9igULF~%k)#P<^Ju*VgqI=eYCniKPPOIao~u7Tuae=fIs>gXfd16)=y0n z280|lrO+Nl%P3Q}z^1YHmI^hJ0(Q6QAM?4#o-p)sX&GI#s>0!ahrHa!V+RSB2X^EV}OnenPXJm{OK!XWhawt9=ZM9JQZU@S&@L2Lm z6+~iaIeEBKeVP++obFlr<%KB*F?m^wEb};-6e3lS$c{;r3?hSH81cs1^IBt2kCNmo zFq3xS$y^uxwp{-zG|30H8O-L-nEWpF5FD4DmF%9!U!A#&c5M0)|#;G-?zYkaHEl z-;s-ZDPOx=26(ku>;}t+6Ykp7mH8`Cg?|AU{#IV`NqmS)dSIEM*_Hsy0CVQ`9-Zrn zJu(#=#@)*w1P+&l7tRH}7^FS=?M)e%9u^oJCy1?Xi(I<=Eb!nuBHC&Yv^b{PxwesQ zRfKr-7!g?tZ7043?17HH#j|a;Q06zX{^LZx?@+aK#0U@d=h^;!?Qe-}!CW)dJx8nZ z6TKX@6|AU5r9;lMf3wfc00~uRS(HS z3UeN8`VW<)k^j??|8V1==6x(eCLl?&tn6g|(B`)2nMWP;W0dOAKFZxS7kK6=rUY3m z0{ZHza=5}8`0k0T29$`E^8>tJ&r7af`RvoFl$feZC@pyO3f|)@*Om`A3g`sUmuOO7 zHw(&hQGwpm%@+LpONMo;IOUcg9-6e_GSSTL6Mmb_-LE%}9n3H#?B#`?HEsktEsp(F zU53+;q*dOFdz=TU-I-qh$~VAJAjo#=5)xJx;6`-D=U!P?O=(uL6BMQ&Y8^$K#9k!J}6Za`FwiPu9&-9cyxm-H!!v?o};*PAQv<`VS#vOPIva_ zWV6i(>@af*K}=x^+WMVuv_TAdRP8%za#%xwq|iBU_jycg$7Etf6{mdA4UqD@>j76h zg}&0)^z9u_^HiopZ~~spW(+`i`F4LcU4YkyzJZK-Z@Hk_ni4`BD%l<7owrIv08`!K z*h4ip9H#uQ9S_2e0w=vf$?=j?IxdMp$_(FIRPM1IrB;EaWyh}@kn^Cu9FTv5J$I4c zf@eG5^6bW9zpqZkicV*fvZG z%6rlS;f`^ga5I(I2{p?4lJjW!(hR{?p(5B%bH@g^l4m^@jRDhj@dbnogm*c~m+Tj19!!ifT~jr%9IWhX;HhnEiYc z|9xQs>|$}l$Cd`Z$99D$sqnep(oBC~wQ!;$!pQVYpcKi-bKa>GkuYfcRn>JnFb|=n zuzvr>%DCgznq(oQB2Hni@SyONqr$k$HB`6ZFS0bb@)e?E{Y2l7udKt^-T~FGtEpM%M8#@fNUg?foi)rw z|3hOR_rJtBFduS$I=Ci_8NbRv>ov;PrK9uor=r_zrgLbff?$zk?UpUNfLNuRXE(vH zTY+zG36FDY{Xf&JbH8y%JO&ls@3OW>68ZT&Be`9Q=t|vf$bu!hme8}neE=Et?$viW zKH|%C$-zn!C=oshPTNYV*uO*A?BAgz{ZHx#Ek{vu$vB& z+zAKZtq*PWq)AY-Q*#sYlvf-xAO)5cU^ZrADsrr>Tds$!Smf$-SvwWnA~`!Yk9 zy%U=}D}0nKI;Kzcfb0X40>(vZ)m5l!?@z;%4rmxdK6G@bCo}7VLN8Z_J}I0d?WC^1 zrFnjsyvhxH)%55c1ae3h(;lqS6WEsAY@hcTk6bpne{X1@+XZkN5}B89Te42FSHnW#oA_k64e^-A+H4pTr}dnASGaV z!IlMFyoXfXSXk33&C2(G>Zd;Y0aKYj%po0}^q`699@i#h0TtqZT(6cluYi2~e9b!k$S? z^^e6i6&kCA`N1YO>HO)8_%|E|J7=I0UxG_0lgC)KHh0x02sUi3C2-gkfr?rHn3?wG zyr;QlP8SzW(NQuFJNH27q%_Q!;AfIMtNLagT*94*e&!>xGsv`>BScv39<%nzcPJKv zLqlU1zarWbk2O8`>znpP)RguIwFx zKQCi)>4?Y9K4h8slin5(-WqvU|7GV(ziVZ5rrZ{BKT=ZXZL-_s3CO4 zIPAFJ!>)Kq!q${U!DMi$H{!So+FM~3afw0O^vEYwq-4ZAV34{X&~+;Y)%9Xv+>*h- z5oU>EitFMRuUwR7t2{8q=yQ{9JhN4$;qpQ-5pw5m7G4CSh4+_+r z*6ZYgnKpyzUm=)4YY}|J(yW~#d^0!vGQg@# zbkVo%=&1y@SYZH2_fEe;-KEbm7foaOI#h-fuX@c#MRuh$46@MWb`60eH2-katr>mb zwI1a^jlA2hOu1)C+ODVOIP5}_H<2=FF(L~b?|%f~gnajxNdrkfz^p>!2F4Tg##%Oc zrBHKZrqJ4#7e}0j6feDl-?Q7J)OpP1AH;Eb!1z$WQcs0RH@`i}>hM0ww4D-d-2xdW zr>ef7>i3R)Dho*?@_DEN(bj>jSY0#Wn#Isda( zk(>2Obv@GYrVrsvQHEZhlK&bk;5D1?uZHvNlNONzVjgd~6`$?nM>{+>gUkFvZX)i1 zsQ%jeLaYooNE^RHwYrrU@M!el1j5^Cu{wghQ*PF&stx)T&CKi?nqFUc1612)Ig~Fz zmA%veP=O5IpWYV2+58xaJaXH^X9>M&yTiny?YLc$EgJsSKYq#{Oj#m==u3$VCP@8{ zwl)9>NPD|qj<&|2HQ8! zXVBS?wztJxfH;{UVvHiWA!_K2sm91ZF-*4OyscppMfg!6|~6ycdA1N1k{<)VoUP*S?4V6r&o6@HsG zbL~&5Qrf?~ikj(ab%`*X(*nt3V_;Uo;p9m4fgr_cN|H~)|0TJ`fTT#Xom8<5X8XLF zQjGAE-7)5FR00jxPpzm*&rrSl>$&f9uEZ4<(fRk$o$6hF@l z{)qyWfh*ZX=ai!}7B6mmcFxcjF>1Vw-QMWdrI}<De$cF< zyu1<1K6-!0aP3w!`S(O!;35yBdE(2R3pe+BZ}uT}s*>N=`71H3uvp-bAVaTbvGo$>mDmJZ`D5nAh&2 zH>ldQ>gb@{pKAgs0b*E+uq>^c=XgK~)pD*u5@&~pXN8uhSbOj^B{!T;Syf#9s{ii5 zYRc`OiF=cH1T^R^;WCW;5;tJw0^n<0gkpnLMqw1P=-zY)1dpSCfP>qy4txq}o-}Pp ziWB?qMxg#SMBoyBQmO~w!g%01Gq+d6U5Cz4Z}pl(>xIgJNC-z%%`;|wgw2IaD7gsuMVbcSJnDo zbr)4vi0ZAbdG~O<$||nuXF^h3fC%GMxng63Bekn2=cV&ZF?A=hURFDG^E>WzObLVI zZs=8!^8^8<0tfyMT3@W*iru-lZC~RYdj`0=kUrJVd1lTaZIN@I!#R8+K8PO!5H*pC zh0MoZh&4LO%3vukE(8Jl)uJ3c_wE)9`IBxF@&7y3a=HvxcE~cgV;sh#S^yB7gZC?- z=%=H!1X@FF%I-p43|uZJtc>JI{LId_FLYb2grLVG?a3UbvGa)Q%UUBcH|JCq0$%9w z5$Ct1i$NqWag*!HT0PC#Lkf16YGXnzBimA3juRIRR0lc{R^c|KLdD&Ns*pu0dCRxo{NDIB|@V3*P24*!dy zlkVC7q@X6zn<+9lqM8TMz~LRUcN6|I&UIP*F1krFQYTvE8^2bROi?0EQJYkAb>Aa(6urhItS(o zVX4QW3lWt*F;LdOAu^X)2LyHp_L(A0pK&1*MeG2cEW;(Z8>n}femcEe-q~zqUt8Kh zzPY8*A7(w9KyE1M^^EvH939rO2s(;hRgvLujeq=aqZePq1hbzDD0np*t!!7>yO zv4AC%Eq%D2MdNFMIOG8Nw|?_i%$97Zihhi&c=RD=36M^c<~dT>oo{SboL9 z8bMn|SE-alw42!;TD17XmNZBWz~1`#c4Qr!;0$&v5W)6I`U@-FM-RA&vvH=K>3{^m z_;%eHtM9cMCB9FRkWe~~Iu*dlaOa_ludIkG`>;;MU|?*1^Aqf)aJKKu zFF+{Qd9$2S>vDuGNbOurpn7|PgX8`u`Qt95u@AJ=&rP5J70{ku80=4>bcPtEt=2;r z{qtM4N39_4_jT*L^uuu-HNxfM(vq4;6ngsc>Np6$PqN}W=Q+AtmgOxWn)WnmQL)=p zJzd-zg-`hcHu|V{y5_OwNh0wknQ~^J1u^^p=LFrOW7_0j*JWW=RXNKk=OsDamHc1p zZZ^?jXKlCyxpqMGO}!rDHlx>QFyTnS4Ax1J^cvU=`K5mrb{KfN2*??rVw`n>r)Hbr zxk$9vL291#>q#8O3uMUJ+POXDH@PliY|J0Op|u*nKWRgWHpczRM2VtWZb4{#5svbE z(GNgZDbdIEhH?4rEDzj~sUrngG0glN|}o&Qih>vJ<> zlQEiQzgWn9WM1!3nuAAmu6szg!9#{N3*p@XILgrl6;{-2o;dp}DnFf&r*MeFcfTL| zLJwz=ZwBEeKv+jd0jB;19%`Q2Bq^CHLYO6(|G}%3sf^#3evbnV9s#a6Sg{%SY!>nV_n)_t5{=~?4l)0-bbk_gF5q2a1lPj zb8`GQZ!vcE_mY-mEyzPr^3XMBD9Q~RWf8w;Fs<|aKE8)7>7vtr!j5M6FsL-j@6CV$ z(^*xqir%aD5V(V7eC`cl>N{fZF(-8Zx*%X#;Sib)(iFoh$1S}U{yPLYXer|~`{K~= z;;zF^Q?O0PGkCC-GAVf5f28cACB+(a5qHG}()>Q%ZS?w9KO#suti=`I_t~C`(_F;K zf7PBX`A;QIjFk<8j1v_AH?Cn_hT}henZiXNsDwV^=?&c~o8S+Tx3%CJoWb4r{f5c# z4VGcn&@ z!{8u|A}z5o=v$^{9va=I3J8Zvc~OkSn_x)NZkbi@->gh_d_QcU7#9DwWj6 z@rx`Pjrq^X1D7~lXgK7#c$z9ni9IwAL6x1_t*Fz3aHo)I&_&8|oF86a%$uYK^gkF& z6$iW`Gs1Ec*w9AkXzqVOuPz%0C9%R%0+g#L`}ov~`k^=GeK+0-E3k2+gueS_`pBj) zE1Rw8!0r)2?VlG?8Y>r&8tSK$iZRRqY#4lZ*tsEg<^|`HQ1{9d@KW0@6 zc?(*FEu50~mwMkc@atuq&^sxZL7c8)_HUy0v@!cxziB4HesV73LWk70q=H)V4qtvD ze|kPwB?0Cuit;+rsLa*D0C+iu8_!0ocG7y{BmEctd4_@ek7EA)PueW;ol4!_FS`ns zhjOb#02zAJt?7mhm!Pwui7?5&@YLDsIjcyfk{`w~zYk9BOD(nts5(A90S@aZ}c+t(Rn+A6(a z0(PAlw%%lRyDX%@QxR7AivX9idCHQ>y49o)Jys4UO<1&M_V?x6m_y|tESo~KOP0A! z_0s>QRx3S5o0Wvja!r zkE7qQxMfNe&C$5OzFnW$xa*R6xBH|Lb@~)-ga-`<`e_Gp08LjMXJYUo9@NTvI}C9~ za?(70sUxNZ09^Xla9XuZd3rOPaq&QS))dlYdyG$%6X^LDJ|QZ+roDfVb|8mCd8wCj z%wq#|0yqqzeDS$ACsmU%(bV9yLo&6@`=lL7B;AH%#z#nN^g0S?%H>evYFuhB)F~4H zUMmOiXw929>-07qmaEWd-^%j!wN}*WL9EmZBQ=2v+Q@4u*lg0K?D|WPT=iv+!wsw$ zIcWW$0~d~|Oh#*Fak+Vf7sS|(2D5$Q)-rI$wtJ!vmOkr|5#s{zbI20UoZw=AT&gHr zB;PYXLiVNtvTeJr_GFJvJ7Sw}$6)4Fdc;Vg3mx=raOW;{y=Yc)Y&A0_!ZYYm;(lcB ztJ=7TMH_T?(*M!k1Qr4eKhJuKzOtk)1Oz<0#i`wQtF`pPnKcls*9lfpr+#@oMO5oN0@FnEAAQ zsU-?Y17R$>X$<9EnP=v*I+Ub}GpgEs4>QD9+Ist*lK1c^2s-KJ`IslBtu#`qw=5Qa zBU8lE>fzWPl+^5u(P2{1;}dL*Q*Vu!rDol@9}hzRR|`w@?{Eev`4PTtw7wDPwH^r_Fp z*=(f{7DG=(f^7bxHuQ$U`iRNIkms$U|P$B zMQfEYx#4eotkK?toL<(z$r3nY^b6!T4_W_yI{>sqUt5 z#j7)qWHi+90@wM04JVw(Xt@wi@!8g5$9$3hJLgW`;7ZEBriE|JnGH%yiGQ!2CWb|{ z#E3`_dLDwyIAA2NF@aiz>+2y5_yibDZ>T;#ivW>E#qnYhJI4&n&+c$+MMFw@&8UeN zO~2SoT6e*R;yTv7?Sey}KaLVhaU2pbl5?`B7=a+XyE^I~S%yy+9LV3$%V>xIxbU>SB4xTh&)MuggbAT09zPBVI_FGiyoRGTglC~pseG84`m$|g zFV@Hxoe}X<*%(o9U7v%3G>NjkO48b02?l0Ti*HC?suaQWf=0W%Q_ErkG~laFmT66T zi(9M$Y$)(bkKIXqnuGa!cq`@H#G-g9(~4OFuJTT@1|CD`9YW6{vx~2D$V_LWHG`4^ zNEE?vJ;!A|@4WntI`I>f!58;%S#Se~Cbuka02>AY@Cu~I6+g~m6xQ0LMB$_k@BGeUAm#uX$3^zdSi~3|ULz*kMjU@xBi!hL4r}r| z7jx0H@gdXY7**o%sIV167C+f(5=Uky0Tqni2`oC1OyNzzS=;$pmLd~1i$>>vY-FoN zo^-@=0G7%gORaxCV)=(ZVe?N|>2FpHew5O``|uQM#d`gk&sBoA&7x!g2$~Yhbfx=s zS2nqqJMi*F?!4!6SGyA}L1-S*xJ>Ow=sU+UCQKs{AOvi;U-}5UNZ2fwZ04dufX-J7 z_edk-J_5BtUaYW*(M$obzJbrfc)Y+LXha6@BvZ1ZTX*|AUDw?*5=+=?ze~NxTeebT z#XPip$05tb^a$N3+qOU=)#8?iB63p986f4e_Pdf6M}I1x)*LjZTHTPWIOI<-<-!7% zJvd;)$1^Ey-q)4Hj07f&amDD}qr0kJYQ&Rg3+{hz?V05n$>*76T;X5w{NK-$0P3u=aJYtQPxc z4ZKLPA zGQMcmV}^WI{AUTnPj`-O1ktwpN~(R{E%K$C7&Fe){f0W&voS_g;8iYGguDcRwWjQ_Rs zmf=T1Zn?i%q{|0Qbt}SK)^{Em%eoAk49*}7h z|C$~Brv$9s2rmE;R>W|g`~DD^RrZ$>95hzx0lhlIC11bvQ1;sAz0;}{U-E6B#_eb@ z9a!Oc@|8Xa2K8hf%7;5g7w0CbiL0aZY(D)IcM^RqpK1itgIuaW#e?*rsP@&!3z^WJ+D+kb)W( zO?Q|d|Ki7Gy2Zh!>7u8T5T~4`c7KamuS7)5+{&s`3=pdQk|}s8s{7VLlt!EFU?sHckfqzd0Q@prc#G^yg=WD&ctZ zGP4-FE^ZHh`7(3*6dJYGjB_^10T(Y}U>^e|&eX02=}i(%pakmKN^H!wqW6XZiZ~P^ zd3UuXlP$7HI%noJ*1zi7oD#R(0~&5NG3@SZb)yz-F2P&u znpP0UBJIgsaKu{@>^-+r&1!{k7(eBs1EVrB&*Pqf&#k3waz*I*(>!AI7z_)(u z^Sr)jG6wR#AL%Qd>P&5kt}NEZ$`^+HY$Gn5aZAU7EZnJzQH1YZLL&9C0vHnp*NA{` zt-TZK^scE^TVL$4Qpuz?OVHqdzhk~OV*R}OshIXig_hx|*(|>jIghy*&y>G?x z&u5!}-^5f5C}gQZhN`hptVt{YIthY@OT)70-=(mzrt|ggVMtvqINQ)fNKnjE1)_n> zLsU_bZ2{?>tU4Uh@DtaL_SjV4Cm%j!i@;BJn7v#Dgu>Fqpo*aQDl{)oD&d>=b#C0( zR;eN?{qC=_*e3}UD=htOyuxuRjmJxRP9rxESJ@mdA6W-sS>g%=dz0H|7P6&QS3?xB z<2@SujB7wtoKvDIox+G}@DfEL1M56at^P#;&q9Yqtke;_MBx$%&H#|TbHRNe#X@X@ zbo{S`(Z-MBv4R_wQHi#u{B}@;Dy^Gj?1C2loO(DOi$xaKW8i0o;^w#AdC^ytihgA8 zM`BvF?Kb45?oZTYm=>!bFmUNYZ+S8=5>|~g0E=WO1X35Lb_LgTN`t0gIUC zt6|Jq)41UsM|KHa8k+h*Mqcp63KG7y@px)yf*2A{d-gz4bIB$qIrPeD_EdHdHQE_WfXTnlNC<;k$m0ld^VimpLta(9_9 z+o-T;54(Dz_l~#6CeZ}Ni5FSj0hk8};p+-`@TOV!MkGKj0MsgLZ#O6DpMlO>@?+m= zxJZG}GR|&I!CZjZ86lD*!JA|&w+-n2fd80|sV`dR1&7Xwteaux5;6XzR-zlZ2OnaR00V5HarNecWyJRnof=lkS`2E z0U*_yIO#XbPfecMM}rMQNYf291&AOD^{W_5?ih{`1EGq7Y99Q|Jggz=sOO+Yy4`aW z=+&^XL=fE;7rVlB^9Cu=B?*^o+nL4khZSSM2ZH&+BejflqzilqYE2@^EL=>@d50t$ zfwH3?F>!{SruT5g&Lr?*yO-Xw`_S{DV!bCOF&eJ zC%32Apz~+xGs=-icaK)qMJkDUwj)9Wy7}Oqh|8aR@b332C=BV-zKxB&6?rOA3s9ox zDWa@(a=3qpRezjkf9_i2fEl9JxpVaxkwiQat`hwyFC!s9M1nAlOT~+M_9jTYBZC)p z2C=e%cWh!rD1&2jjlKyA`(Qi2Mh1J6Q0!F-fVN!Iw({{nS-WodUah+a)53`MwS!Bx z-<{onKI7H(3$*Dd{U6lD;iB3X+5YwmD+LiX-w{`XP1_*2L>uB2q`9e^*Iq8KIc`t?2R5(G`j1hn^OygIEzD!b}~r8ZjQgyy_j^ zZg>f4o3{EMqussX&tH`X-RFmBU%~w_zgB)&r05UJ0wkQ^^$PulM}y~$+YMdH1asor4QB5* zyA%bfvDC2klPc-F!Tz^Nm_)-Q!zJJ^!lGYQLJtqy#X-OXe?`fM^65lxahrE_&4%_Z=_qV zvd_{nDQ+TN;dVn@N*QmMJR*WquCI=(Y`cW0?GxGu%nor+!l$WIor5Rze}$ zjMW4A>J&lHeUS9uB(;F!2u9(UKWESWvXtZn>jE&)PyfAvX+Bl}=%0tv&*eP{%jO2)EHkW8r)if^e8*B#dPvo?Lv<9r6M#1m)@_8*-|{ae z1`FaWQsJ@qUfEuPjd;Pi;hMOj{D+8ab~Lfd9Qi%Vn#EA_buIIdSYzq4J+r)IJIU-< z*09AswAi9={w&u@I}fo-jdfdH6uT+>!w42K&y#0m8i>K6)sq6sJ=mY_m`AkBi6C+M z4q`LtkdOoS2%SBL`)STlDo`7;x`Zr5wP|!bMJ2LXnNgTD>_%E%#32V`+37JuE+9(O zO|LKe>t>bXQ~b*2T*OTfE@<6D>A;mPV&Z>!{u)2ern9bC&c2fUMb-u|jD;oul?v29 zTzIq8gm!_xwRe^A^`c1tv8=<@7h zWmi7vg^o<>O5(-M_w7^oJ#XU#godL29X=Vck zkU{iaydiBM**vh?Xk=>mWb8-BXq5Hh@Psen+q2Kx5j6u3@-{&HginlbAP%25rd(aA zykBxGjgZGpJA4M@VLJBZCK^C$X;!w`~aE2^6+F~LZjp% z&8#ehD`eAc`fZ8mC!d6-Z&iWk9MlHm1?ENiL~{XKc;|XGa?^H|IrKhuymU@Y56?$E z3ooKavpnN;iIE-7-JTfbh$G%z!3AD%jm;|+Qw;K1tWom@CVy_ggyoZYM`=d7OQ23tB+7CvE_3+6R|hJ1SM7 zBKk)-Vglb)i{XB3556) zfENj5zb{Zey>h>E< zTNbaNPN(;E=ZHq~{cK>#DM_GV|NdzXuh28tvLl?r~I2o$Q3XKnaGR%`+`D z-b~HQDlTE0zG*NNS>cOEJc^=W>JBcUjr6a|;m$lKJ)yvjqT9&!Uy`-&f^nOr*GaDj z64u=QWfg=R1XqK%$QREYA{`^8Ty&Tb*~lEzg+0Y(goJvQk2F^g_uIJ+9@Uw;tH#Q& zun`(86MLeRGd4M12T5LC7>ZO4C!hlrsa`nYUDlWKkWVi)o=ql#T@OfHOu>kE9&80q zk}jrbcx$xLn_4y8G0HaVp5b$P;9Sik4eyPXKpxit%Nw-N)?Zt`fWMEI z+88(yAW1x>!4&)p+N$Hp7oc4;sJ8^*JjeKlSWnI9jHGhe`S4@gcVVDYh3S?sM{mjS z=#V5t2xhO1R2&pM8kL;T%KxfZ2VS8EF+roRyqf3`Hk9e?z&>EQgaM*JXt` zQS2VE`K!UOgr0uFiC;zx7LTr*BFQ;<(n`uBrN0hfZVc9@3Y_vF_bfABy1T;*PXy6% zQO~*r+_m5uQKxQF^jy?CepHZ8w%{pAe%t@O=aX})Q>ua zJ6Aw68bOjPKCpBee_F4{=mfee15AW*F(W=ZDU5RB{%YcG=fZRQHhG}>+12Pjyyt|F z&w+l2_nDMGU!UVXzQzfff{c4e1$T6bb`7GM~BLF;_!|$M)bL ztm(}P`H=xlu_mRXHi-k{^6qc8R~eBb@dILp9Vh^P3kU_H;!!uVZ)ytQ`a+$NEKB-H z-Hh~78p;NDT9AX;qJf2)4d@}yX%LlLws~+KvGU^fGxEtWNP*zp(XVU z?bhE{XrS@1y;kx{)BIB&N!CGX&Opno;*h(3yXFfW7lB{TGKb4`LK`NUYW)gjFgZnwmea-b(PT%kdRR1WrPT_Z zO(BIHj~G_6_y{dy3i{2swkr$g8Oul0*H|r|VZVZrIIgTKLWtuGND7|eTv5YAX?Fid ztk&rxHYB2VB4?b?`}}8mNJJw{>A$hEc8u&~if!mp-NiqRs+}y;GQSgxLwsh1Q_{@g z4|Ts`lVXGj$+KcgYx+b%WgJ!&t=94Lzf@e z)=oPMX;gNt;CbNscAv;pe6uqq24o8JBRI*Mpg)D0IZFt#2@P80^hY~AP?BYcqNytD zTMq06wY~kvAzYPv?o_79szKT{iZ0aBN=^iA9Zp z@^t8)xONnmy%v5e^Tbcy{z2jw#m~Az<0;^T$%Gn8!4Mv|=GqD=Wtj&dAfZKEAMBuoGb| zg#R(VnIz7Xn+d*l97}Cn1I^E9@_IFjo)ufNLRzl<1#H*#4%trAf9I!>+qcP<_MoGF z_DYWqYO-++M78_$a-{K#oYJ;dpWwS_Rvc#igk_lxHXL}uSgF$S%@~qaSO8+1L8tf|}F70INrUK@8{&XFuvJMmkA+BkF+|FK*P3086T?;RjfsYxvgaC!XvFs-UFd^;Ne2A` zQhB@(JXNz~xq+KiX4er$zVLF+IUT24kWn9}vN}n03l-jQpk|23rmsr>TjH4f zDO=th&WuQiOLEYtR?RvfGGIF--oknLq&)A3rjUFE&J8triU|yB!3}i}Iw$BP1)oBZ zpkHCierbIdZJlT7W~tTfRI6xZuYe61GgUPi4M3 zhqx+k%9C0D2yKL;4t0t}VM#5S%lkueRz+)KlXnW1jbeMi;rdg>LPQKPAgb^fTuyKN zqXJ=z7GePAuR3!8TWw_kAyH-Y7N}>d7gx}Q;FKh5D1v!wI$qKWj~;lUEPXxNzro07 zg!)mGaj)?eGdy6H)J^K0)n5=K5AD*&IU%lgY%svM83y4H+nFMtNfbigS!W=`We3mNE&wo^4StIjlEF(q?47+94Z;pOR|KVnbv%*9`9bQv=^_-HE$?T|QG4rU8Xuc}{z z-G2-qTo3Va!Hh+L;|Ad@B9^sYN?_kyz)tS=pi6>XI&AQ2C+y$G8L0dmrPHRrg)NlR zU#P}%oQmF|WQ;gOiF7&H5h2J*t;Nr-2#i9`Oc z5t`9mI;|X^5Gqax%QavF+wPGH1Xyn#Frz(@ zad7;DMH)ez7!(d3J(|WFcCe4mC8wFAZTyU$gJAJ7ASmC2;pQ=YA;4E1F_{%~V$O_! zz;OL)x`yc9u!4TX9+WligwM_CplYnwebT~>Mcui z3%|)(n0+n8VZ&tIj-;?-9kR)$^l%{~nb{g8QzVJ^3mMB}af)L+`}4e->7eN+@Ih{2 zQ#{=`t7cD%$!)rIaQ=5xr8&aWP|&nn?%->DgC=D9Vs*T$x#2Nu#$3`r#^w|O=f9Qr zOB2N--C~eo_3an2U1h2R1m+PPYLV96w2n?;SS!%xc^~JZ!EKSPuJ$}Fjgaa*Q-)k+ zGtWVt$0-U6U9|5~Cx>?PIGy#4egmIW`leen3DIUgWZPKxG|wXsU^MBvL>a=a5Xy9 zgCevc*RBpIQa`}FT*k%?Buw!J3C&M=T@Ocxp3b~AHQet;@yrfdzzOq+Y#yy?;K93g zdI9nOe;g`*3Z*t`JA-LX`-Fn8X$6@=R?)po{`OjWtsnvKFX`Vo>t<1Ox&G`npb6HD zA2S zuY}~t4(nZnt4Y77OF;H$|L0L8RKF33W(GfXaecS&y&y$}{{~A*UjkFnH63kNVCYDzoufv-DL}kNA z9CkiOscNaHICxmkHMnw9tPtE z^w_O_ zVIHNE-v2OmC^xu1$(ruT2NUVyNquA%2X!=P@rWDqnL}E^G~ub;=pf9RG#((JheR{q zxXg~5{m39pN`{bUBBd{3lqXkxf_W$XaY0~+dyTUQR9+-AVzWh8-t;fU%RR(; z=|Zlm6CfC_d#DxBwH4Xur&X9Kl=u+efv|-AR#p<5El0KNGI`74o&UaQt zzy`mVyl*x}0i z+5Z6|ii&)+GMxFY^D)XDkE8gB^9V;0AneH`=(wYwC=Dp4SS2#`Z(S6EgvOD@Ot0{; znCw5?v6B=OX!LJu%*7$?&hNI-?anli-1hX$p??t+!;d&^;MplY`eg&YQY^7CU{D^{ zax>eSHgkgN-aN?kSL>5>AuX_4GqGAh{MRE}y8GoH8sGh%%1q()@IC&EF&7X>rmEa~ zZ-&w`6}A>)jDKerVx08Iwp~q9*O@YU|ljpu8L!^(C%3p|#^z-yBLDcB>UO8%LR)nOa-7fQ04o zbUp%(uJ*M0Fgim0*i-}XRU^RRp=y`aZg&GnfrJ+`oliE0wruQ|*Z4)qQ!B7ooJEpY zPXcE)groEMaWnQBT;?sylU|7<^vB+(eJ>yT%tnCzfJ8f5K$4lQ&vBZB1WfDge~Lw} zUYt2A1@%I_XA#@;)Z4gx4qXVdNXUcU!c?ylsz%Pe$ih= zNo=?p8(?XltwKIC;S8@te?V6iRSawOI;FiF(zWyxv;kw#4FV5D(LU8-$R=>lxDljI%tRoNqpI0P zA}Q!;DeNw(Ye+2NAtP4h+e@rj7<^2|RMWP|KcFE@CP6X;+ooeRQ*fe09?^wlASCvc z>b*up=JAIn%}>VJS~GTk8@B;=7R4oMb=&}LWOsYZItkuB1fJ{z*zL!=_cEZAobtJ3 zFapaOodzLfSvXB?LW=M%hk>^46^HW6%u1t@^Pev0vpuHmhvJAFeAzf@oEK19h5Hav z?>CLEGwz9!NnNqIXh&Vc@RV&PVwNHpXenH#W&~5kpgGxuZu4IY-a0ieU-h9X)v(+y zo%rFC)3faM($f+qq?gR#pbmtvOG$-0!LI_x>E-N_zHfD?7PX4L zX+i)^K(fEL=%|>mATEkItK+=DfDjJK$QgVyszTDNrrOtUz-*`Qhe#Ds4K+)%BAcJb z2AGe!-`h`cS4JUoZOXaL^BI8D4@5T8S)AqB*f*vHvivc^sF@)kC-X-30Uf_dyUio4 z=QAR)rXMHQg6p)O>JwutO$O=ueeG5(MFLKQ!{*%LDb>+gZOO^_*_?wO_9(p;YREyf zP8vf5N2YV}#zL@{jKdlimA3MoU=byvz4vxGQ2;^76D3Arb2Yk%5 zY9rjb98ARi)V?gos4O=OS9aX64Hl%5wv+Y`0#dtoZcFJGpwe5#wDZCIol;@NVj)C7 z9=;~rHTQomd19y+364g}ZUrBF!z0P8rcQow75hWY-5h^toh%X}!u3L*`;|;+ThRQj z#j@!(yrJ|4Z;7^Zx9VfJ#1mAdj5;!inqEEv6`ZhrG=MJN9I*qdZ@Y7t3l1KEc*!Jz zMS%0(Ji|e*t}kyH0TNZOs9ry#6ssoDuZ)Y8gV}%-j6t%?vj2tux~^_SrAXgltf5J* z`&`>WjHq06)=yFqI8&;Q@pR-*Ct>VxDNAmZf$P;w1b#%7=BTk5x3ZoTO(MYw_dlX0 z7Mmwe3;i5e6^<%f31US~=~(Gxd+2qFIX1nO&7Wac1K|X-^BHC80p4-lsDJb3NQxl= zxU#Efmfkg_rrFe6h}l+z#lBRDb^z}OLfd37n<*&ZT>k(H1!VlvfCOPeu-3sC#oXRC z&?jRmq(^aIT)?$D_1toIwNLa!@_3HJ?H<}B0`krpRJ-{m5nLuz(P%lh~L{r zpObC?Qtqow{H?CJ|KTt{M`n~H-*SODBAqT8SvvG-0nFw|-*iF!XWJ9Ami@F464aZ2 zHu=iY1ICtq+E7D;A}0Ndel+SpP+@C_m*tklq$UQY4H?mpd> zBf{MynA`b@MG+)2GBiQsVuxunh6do$qCJVvb0jRZP%6#S{#zot6~%x&R$8Q}JD-#7 z-J&k0Gfike#pu%4-Hemb!u%EADIa7c;Q$6cq5~s>3hk|wjN>` zN$muUC+?)D(pS#v+YWW5#|KX_sFKkKR@lph%@|W*cw0ZI&k*D{+}{{&?HJK&d;N%J z{@?Xj?ezJBLMtryduwqZyYwjBg)q;f zuViVk-i_4N7Q>ol5?`3aa z{Z3p$$$}uyZa2WV+TuuZ(y_uZCm%DOlhIgUru`+@l%XntOrQqzl)`P8nBiXFBVSnK zBUI^V&tr3@fWnbW0bV_ik5rlSfk+O$(2hTx`pYK zHL5HM=br7~#F+1kTGH_3_C)Qf2Pj$J|J@qTS4HM$v)Q*LR(XEqG;LGCypp0ndZ4A( zLS4=lz2-ANa(q5?PewR{mg-=bGQJR@R%dtqQa5o0=q~-eY>fMiBW^lg<7@BJKX~?G z%paebVYNu7$Au4ol&Z9!##9_g*kgFtjMnsTDOc@c=ZryX>D6hRd=Qq+1k->ioX)(^qJ^|WpIEa zE{t@tfeZ4_Lsmr|%LHDnYVRv*@4YMTfJKcjeIaS#c?9_EhU)Dz_*ZfwdxltmvykQ7 zq9puu7(Y@P@Z%(kH^Ys;HbZYzN0nbz96vT@rE8c`KS)oHzkE=qskOjM2SPU8c~Cqm)EY zUMvf!p~_C(riZp>1TqeDvPb(DE;sdld_m)t7v7l`e3dn^Bs5oQLy)hdyy#jHKm;6c zjIK<_3VAgs>(X3NDB-Cp*5v|L&^}i0p8-J!t%%0?rUA3zg*@BKM7H3ZcfLqIVz^( z<^II-U^XYwUTg}zCl#0aif>bZy565Xk4DMv3`=s*91^R*igz$k($eY1`;*8or3f@! z_iVX3If{-=xb7^PEq)2D`iY`m4)~K9u*>_{J?|F~-#(myG3?~En+8_gJ*R~_aql=4 z=9b>rB4OSqa;&K@MB7DS>Zr6R7aB3vtdj9=pZwF@N?>T zT)!DnxDy092}1r}?=lN_uD6|5E0hAF`|L4hf+|r5uBT%VdO?x2P8H(FgJ^0ezf^ z#hl&_P=xVyY0g|T=Q_&DNMi9SCpWxdc1+xZ0innQ(PAT0=bzFlc)Qe$9wAi3(2y)-3_ok?y`LtAI+ribNu`=uTIkwps6uaislNyfOW z$l{iqe<85zhrYVWy?)B40Ef9p$?~ zj~)itmLK)61~zf_)P(^*MOj&20~OD0>M992;DwtrB($j{610e!l6^ zd@rHkw6ebK`4?H2YmC>M&@$xxbDfmSjy1#AjFIDixOSC5*Lb#q;f!>#U%~VQSC>KM zO8+u{Mocd&|2`R08AgxzE0`eJL_aH{C7K0s@DBS$tp-fjMtgZ*Vx0Yw_{PgX2+lFY zfKQEjuCD)zP?A=|!SN5pDHOc&%|c{E=6t1=b!vN!0_e-TYZKb*T#>p*s~AyL?qywotyrIx{J+ov`9_gonMm!1LbRP80e2}n z`A;bPUI?DF$(ZpJ(Dq}X`E*K+DUV-FF0tl~aM^TtAh32-`5rSKT7(iDWXUWzzO`SKI10qv~ z@#=w!+zzytb{_m`4N{^I&l{0WBkz;H(=_aVTGTA=f-LjXnqe|}rg5BcO`|bD?waOD z5A7b0y(%TV%w`GGlh$e1?@DF0NvXXOnDW^M#OTN8+i|y{AMEh<=vvKo$$zZpHu*JHzX ziUl3QvkcFYNTMu}6dw=ghnwR|?UnFEa(Cd)HexKEtsb9th7lN2p<~HKskq*y`FnKr zj82atqJSeWOQ(*iMG)1!a7rvH`6-0keKckS#a(>QHq3d6jla*MO|F1H`i)7!2F)1P zKbv}6l`Q=?b#erU!SNvLEf3sNBUx=<*;_UqOyaj}peRVgIPbDP5ra^BC0Ix?TuYU> zixCN@Yyq{8g-IW-WJ?R{~(i_6B_ z@S6j{Bwfyb;@WHO4w`y+ce?&0Nh2@@ho8q)2G3Qe-dfksq`w0kcX!>v!LV8wZ(BUv zA5F`-E>Eug2vibF?jBvPNhufAMpUb4pdlt*@ClC(yTaijpwX93Vca+ zPmr({@i<23%}R7Uwi@MJu~3o9%X#$B!5aAnKhmVJ|Bph(*U;qUjHWZk%Yn2 z&t8pG7>X@yr|87UwY^&H6rs{Ey^ok>K+sYya$#8y4Kl=5So9q_e*+n;e@*cC-4Rh#ZcW=<=OoSu~!oWE^S#W*wQgwUlT&?XdtWPA2`$~-7%GDh^bG3zhf zy+V`F`#3-nU!g-f`MMj8CIRHJPP1TP*7|7+g(j1g1|8)|)56nbm`DH_%_=(ClgXR^ z;tYX#*n}8}C930I{mnA4B-)pVvK{IcWYnrWKg72{$lxkn+WTa)DVvVS>D5amNUJ@0Fjy6 zcmXEl9t1N26Fu>_^QOzDtM;Ig5HO)9BwU;GFIRIwJk~^(;!qNtG%`7qj7s6W{mIW`*(|rGa-$ zxZhzb-uFik@GH6b*qd)_pSuj%+QUe_0K6yV#me|mR0le*HMu6#IRjc^{D)x*?_glZ zKAk~Dn#~NwP!AoM@js<7o1byr)?G>^tZneg@D!Jql_R(q{T4|lO}_W6L?wG+{U7#2 zg9b%Ry7GaP?$jZUoTTV3MK;IVImS`3vz~4Jvj)~lG!#w^bhDZyl}|o`^{IaG&r4YD zizJlF>7R=`34wnWrHwp{QATxX%gT`z73MURN$f0cEZ;7zf&dh!PZ}S z0Y6HcR2HUY^U<#jLE{ANSAkbg(WjYJ99Sc_n|%cc{}GIN2@vJ4sSy17iF`tv$<3&X z->~sh(`YPSCB4dRL5j*WO|JF@cX$2ZmyuY=uue1Y8gD(UL?R%XY>|KRIq9}teQ$es zC?InVR_iqTv?7*QE>{qknfWP>L^cQxg)T}w4OtvZ9wX2eYe&v;>6Fg#D~IJHQ>IhH zlxuxsvZY(ObLloTE;Lf+ao9py){ek9Vbv;=zpW}isj!(}N&i%-FKqfFZbwqV4 ziGs;jTxZf{2pNH9@i)66an6}q$!D^b0Lvg_^JY|xuO$$wDgfK zRbhln72t2Pbz)$bCBJjAgAeN1m#LBR;|OZ*mLRX#Aaauq&Qy_;4v8QpYSu;+URSm| z+jP$kJmJ3I2?gKM$!x@f-Cy1)ZLiC*dnIohM9Ny)~1XVLZPENpecs8Tx1T66xm zws$F-qX`?)V7+dz{pqneuBNxhNZ~$XhC^Ug{2G0I%jEo{!F#!bVh?DQFGKg)YqvI+ zaKGY7E&mzX@)SORhaAoai0)P1f8~oVRUPoMgj5vD#vWuGx84L-Ji?tO4f}%8RWIl8 z;MeAu|Iab7n(1O`h`1JRT4H+0N9no{!2GBtS_kGqp2_}l0YQl_A4SQ8nS|MHMbKx( z7B)q^x?wJk_nrrz!{n*vtI`q_FZH8~T^j})(vg=(lN76804xn^?ZK6-WA*;{fMI8yAN zEPo3;emi$#yTl|@J`~4A<>Rh)(>_wKsq~AZtViDu=yD}P?X`?`BH%54TH(CMzNsrJ zU6(eNO%E{Qm+}a>0PYa4HUJBxG3_fPRz9Nqvz7h=4I=1s?)~}IPYMDhwqf}8Zm-M( z>BS~JSrzcG6qb}%$+9-!*sqyd%!b69`36GGU*#T2iV2g{$F!EPz$mp%E}`esK;FKo zx8VbW_$e4#$$+vM?cVpI1*uxL#Lp{o%y$&AR~Pg|!HRjpf^kc)+MVoc zgXx@ROaL5bQWgrPxxuF?;QET)RybqF$1x7{8rqGe&=$>}MOKi%4!Mkhkco8|)=<6# zZ3F~UDw_jN_oY;14EcRe!ofMyQ9ah+ah?BsmnbFpG^!#!3oo|EOWOz2n%=lp1Z+jmwTixB_ur1v{<6aJSy{Bnpu7(IVIy5HI3z&LcVtOjqBZj^i<)gPVd@am1KMKj zG%Y{0t3RSDJyNe4%-vHd+m07cjJwE%;wWg}{CS`D@@Zy#f^|dLz*&Wup}Xv^g1Lh8 zzkP4C*hic57cm1oU+y5o@AQAKT&`pZbU*buc*kn&KcKIP7KQ2c?=ebOO-H@C+Rm=Z z_>ZT42>=GLV9#hpVt7AT05C=Y-B{y&(!o**X$`6^5E z@w1AsPdZ=crYQtrq`+Vfj+a4z<8Vt!~4I=VC4Zum6w_5?y6vIdI8NZvW zICYOo0Wojnu<= zf(LKfd?F?7@&R04*bE&x8*w@iEosbms@e-XJ*0z1BZCPxr z$@if+LWY?iZ zi$clQjCks!5ltTfGcT3ru;bShwWzUdr3Yn!Y|oGC`PhhOn8IO1^}+Qzg<0-WClGW zn+}1m8_N8i=g(PTV%0FaMx0&1|Lp_xy?B@>U5g=S2ZVneT7&`LHlWz;4AOUxw`%VW z{6Hg&r->F^U9}WQ!`t$K$@b}8G6@g_ISf_4+)=7(k3jY!9YpA-Nm%{j5h1Pn*$D&M z=hJ4V`(M(mUVtbUIToZF)}!`#uKiJRwVyZZq}?O)ZE)Du$j-)t^-h>hk@(3N-!6L1 z@j=K1n2Ms-13)?3CBX1--%3VR4&YDGnCz8^$_v%*( z%r>xO2y%Lcb3A-HUNLON*Gzja4f109cxe`zx~umCA01wPa@EL`+h91Jd3SBh=9Rl# zZ=MbAFgeoOSip#H+vR~!@pO7B*j4P8G@@UwpamkE4;Ow{5->^zOko6tBcyFpx!{ka zMk6iNzI{R&@_X|n4hX-#3#ZhNz%rB>m9)RVa7J+fu%s97Y$KLWNH-T?%nFguk)HI? z(y`W!q^U40JA77XAwD2D!`#1QAO+GWER}A)>gW&Y&e#)uF?Mp0_83S>%{^!Fb_ZS%2XMHeSHJ* zynkV4QxSCnKtLU6bKrhdqpA66c!eJqN{oGIlGy~NP@&~Il3GDUHNPf1Cl9Oys})GNqE`LPfc9 zVuoSa(09EU){Y8=4)ajd#-mAXn=*RcW#WOInS;NKry^mQyZNinFQXo<~xvOq^* z){zNENb+)?pbXI6wwB{X4ud5bpNVb7_qw>%j8*L{%up5h*v?TY-Sk-b^t@xcM_aDX z-`uE3jV^Nl3Rv$swV`C5?{8yy83)*T0=JzH7L=0n*Hd^*(0FgJTl};tEKC$z2zZ*l z9Vv1wxm9p;-H9Q{DCD!qu?PGc?RzcQ31$9hlA-FBO`6q0^2zVO>n1bTC8fs)3ehIp>KsuV%t89KVUq1W|n=T zaQ!^ZX9RV2XDP5DaXnk)aWBF|Hm2T?oyw$J7G>VfTco|ETA!rvD-nEM$a7ugt`wBQ zN(IRoz&L$zC}6UFMsaQXP>A6cY;tB2QM)*>nIOX-Y#?-ni1v%fP1(<`PkG;h7bW;2-TsH>>1^|QUncCt*dMqxxy-3 zGG$DupG}_O2XFkJuq_%e`(C=BbusCQi^?Dk2Sh;jzuRaU&=lffNeu48%=9-EKtVcj z9Gz0$&{Z**)4OoH_73V$*6)Do`VyZWG5qDUPf8%QH0Bt(Z;!lN6J!bH+y~#igSS!_ zCUfA53c&yNAhD$y%uY$Hg81vzu0qi*2q!$yUpsf~IjarUa ziy&cikC7&JMap$>4N&Y=kRv$h78(%}$VSB}uJOCxi@x29F#snB57OZ4HP-whhvw1P z=lOPV{=5?#wKp0YPEnbo+PD_vJ$MxQ()gScKY*4Yx3B+-;#ih{u_}1CEwQ^|n=?Za=f=OzDu+>`|KDeB*G}(ch z7q{h}eMv4osqSzO7Io$(7$HoRM^2x7PlsMvSc{gdij*~hjUB+8;B{*T%$ zyC7ifFaWqp=}X$Nlf>!*!#SU;>mH48K|9!#WOW2Ur(j_x+((9oN`Ni?WO?!l+p0gk zM1H>FOa#65HBvbKZR=bHVQu?FSRrqz7Pwm@b~caBjE10`kU$r7a)<{YC0Wbu)|u|f zQvXaNi9w`2&YO~p8}|b^ryftb(<0Xi`OMv)=K4`?(!srj8HjFm)S2lsnu=lg)NuNu zgYgVR;A|IjUL-V6?8alO6b;*FNFh~v=|`7~cBea>;m64NteT97>U+pxDIHt^wS00- z+H4_x#HKZvKh=5$AtChDM|~ak^u;RHeJ&8w{FEwow~YtAX?qcr()X8J;6CW^BTPI0 z_c*H>6|5hJ14G#j&`VylW;{x^z?@A-8{sg(v(LntgNn!6_=D~_hbBCXn0&B!)HPnj zAP4dDXV~k75rC;J=CS@rA>rPr0~<#oNI|?Xm+UI_9?B4s?UmSD{lHHvdcU-1P(&Kb z2G6}aBV?jyu^Rvth9t00UHk#nQBoV0JB6-nW1hcUJ7$vN1!TL1!5)S>m=R4Xq|uT> zZqa$N-hg59f!Nhsk0jMnTc9HN6Qqlqs&Zg`rW>d2wLt%E6pbOyOsVSmakX}K4Xv$` zMjUGZs_-J$oL}!+ndKiaY)6+BmL{WCXRD`f;&3O(I=BmkFL{j0o~p9eA$quIA89)J zr8=KNgWAZ8p<2!hQ@EJPe|zH-p2sebn%n7g2-_@YSI$vPz3EJ;h>khJsUJF6Q~;B% zcDvtWq`#kJWtH3;^m5jl{4t=$y$P}@Su=!ecQA-XPmf4vXnTb3n>W{GU@IK968a3q@JmDpmchp3Doq zSzj=!Hrr@U9+2x@p7cavbPjGb{u8gV`zur#_5mrQ9DAm7P)%|$7w`a2@-$HOq+6Wt zH@}2iTo?H$RKyg*yR6WoJMF`T@VU;a@A6(jO`L@!hwD zUZD^%5h4iR8?ct<72Y!VCw?MnNf>zbD97iNVKN@g3BjySi{NuFb&aJaRINQ4HN=H! z;_H1P^3(5Nb!1n2Nh&dw;u{`Ko`h+&@=`0zHA6K%$}cP1X(XDvk^fAvU+`v|{C7gvR zl@d@$q?o1&IsXpxb2Ctl8dj&^Ea`RBYJV%MI$DGcx2FX~7osUUrFm@f5Cb4Lnlr1q zEvhgYfiP{zRqiLd z#B#e}zyiYfWt%pgT98xroG5-_E=}B<59^QwQ=%{YR0W>6swWs^R>E6OlMl z6P988PCnsw0V6go?}ga4_iCFhsn&2sV#t*!tAUU0uDcaeKu#|@HU{$Qsb-0oTmoMZ zVGQ=?x#j7Nv7>n%+d=f~=hTYdw^*?ODGpWaFb9fJg>}7JYk1vsh}9yFE7%3{_bYm- zX&SqkHBWwNdotn1mb8ee?yvyGPulp-0j$qjvvx9R%hEA`SBIW=J;}+iyoO2Zl}8$Q zGv7BW9UojrT!`akp`%MfZ)5e>Em^zZzynHVHWeWMri>eKCd84NzvBUNX2r#M*x>po zFBaq}G=TsjK1$oEj376B>1*U--c%vNr<)c?H9iZq?wU!3{`OdGjDq9D&ivMXqL0NM z4R0{+;IFAD8|`H0J}5MEzb?`PLRFEq0{HpqI7}FXC#8wKOn8leBJLhfnh$jnUGP1tggfi7~ z7x{TrMIl_MRN1EaynIQ3zxlSn@98P(o@S=-hpejvt(C$dT5#+>b{YhuaBO9#d9=8lxLH}{S(E|etbRs zxP}PsEN1W}Db=20s;qmSC4p5jN$U(X+Qu0tSk&U5uaMQ-)i0aG;nS`!)F`haJJ71i z)5~tzb{LP5Kpk zG@LU8)az-q`t`wgqV^_S%;12SCK5kF2`pZ6CFp{9hy^t-Tp_~eypX5QL;LyR{CPdO zqf6pF_>n2#b|qnv3=TeQMy(2`NCaVN+`~PUpOYkgf0~QpxR$6bG)=Lp(CFE?)BPm! zB?04)B?0OngZSW7L^J&*nVH>lOb`icW1WKvu*6GnQZn2bxqB!k+ zjx<5ifB5ru(V<#DaFqC0tmb=(4>L4#0CyXTVaKK`F?p1|q#7jHJ>_v@{bc^%sal}s zU)elhHF;LW@YKUKSE>AWAs`Sq`j28o6D($hGrnv|OKQ_bVNBB@=c+~JFe8Y5yff~kFf|LbP69Y=4pYme*PV*!Sp9$mEQIZ90dL)~3bF#CdHzFgdv>^X zcd{=&5A|mKB$(*|)g^hqG8TOo*T* zfJIoQkYa=V;co~}An@B=6W@q8bD&LdRm+7phGPO?l30o*aPUVKgM=YCt3}e#O+bw- zYEZgIp+eQrPI9|BIggPZUz8E!8X6q9eHQ7{_cHQ{DsE4&J&%i6xzjfUE>Y8`$brku zI7&u7$e$?nS(z`H;jN+4U!{At3^7y62U6-!t$<%*1_9rs%IsO^zox?&`(Gq0Afk)r z&0ZT{rvk`oxaVFG0QiM#qu3bse7BEm(Tv>@<_&LvvIUooLOU4@0jNc@a$zgyOWDOHMyNti?qi=GTKZJcvl5r@TzGwE&UV)(&!3zP?lDu zr68U_C`ymG;VE~Et9vwWX2|o_*7Pe<6u)=@Z)sdEIa{%;`6vtp^=CAvlt?9goF`lH z2ff%_V2GwzMK{`T)I-~qRIu>UI zk4ym2x0ykpuBmvFbeIof#U6ZzWF&6^BxL2)S>>Gf+LPuJ#NaYgn6X5ilfF`HKf6La zS{;JqN=2%bRbqDTpcDytV<1tG$(fe%+ewOE-u5?pU|mH43K6OL^JPS;tdx#l{rj`w zV?`B6(3=BWh_GbM1PxajZWlZD*X2y!n#SQzx+ERmV-D>^3fkHiurP|7CFJfe^3IsL z?znwcgBvk9u%xQ?^I2GQD3$Qza1%U`$z(LRz2AXd4m*Q>4F~+BnQJM(X_tNAKslh! zn`DDANF(bUeTE&KMi16nXBCFO$b+0J>((c95btFhMQ{Nds1p+wQvAVZl?*&w&JZiv zI!3Qrdp^(n$R(Bp1(Ry12ZwB`olnBcdw9 zgvQL{F1pEg$*Z^hG8w731E7E?t?92!$QW%uD2Xqf$7Xa({7;?B->(~dKk9UcG4<68 z;7H-~6jcf>6c|U|RqCuOs%0eIP-#&>Lr% z@hax5ruT}~h2&T6;_Usew`fDrWF<+RjY4kpD_L5D7-OL<(Rd)ZeNRF(h{f8+(c!D@ zbpY)B^;$eJ8)MZxI8WLnF}2JDhAUQ2_Q4}=Tjr@FeEJBujC)AHyaT~v2hRXNTk>{a7Hb^2b{1Tk>WoQjn!1@rbv&k+hFx^P z91iP^3ALzWit|@v;visJ?a98qZ|Bt?jK{?c^0yJY#gki*_#XHVS(|TSfLd<{cGv)U z#PTYPLvbmemuJ=HE7dpTXt3?gV_?n2hN7n>h2Z@Uk!w@=sW3=O{(U-%IjWnMj2`JTidB4l*z z-7yiWBc;Lr`Y%@jXt12*;+3kR7Dy*^!UL-KZ$W_MDCaPu6Ibq%-lPng7)5Fr5P9aa z)3MrqubSu@C&e~nWXtI~A@i*GenQ?mjWWaAQYb}99T!Av1o@N*KGUdz1C+?X%kAof(e*kW)bmbb?f?5ds}cfMUo{147! z0Ke6IQC)D)n$k0?ml)WTjQ)&Iz8z;gc>VH|s;K+?#?`WnJy?b*!aP}qXH`re0A(RZ zmpA2-RJJ^H)@efFvvUM;x6>#+R*HwT`M@Psi!Px90*s5fU$gEzW`3gBkp7$%ga~3I zg00tH*(4ToropXoE$$=HFLMq-0Ut9_C?dr zQG-7;H?#K0ci$9`-r0Zw!n$l0MpAT{`_(9(1CNdj10!B3@n{am=*aXNr zW{x1Ctnt=1`mqeQwnJiXd)c8A4vK7MW}rIR0cY6er5SnhLERBJ`u1@bY_P>>m|AQS zfK%r8Cv_yAQMcbIR+ed;ngq@`PB7x*{g}b`nleu3tuejAXymHpn0^Y*!)tvCcE}6} zm*^`s@5dyV==ClG(jBdoBRLC$<;hu>O?mZpybYjp-@@w?jzo66Q=ra}?EG$Na$` z<)Hhz{7jVz<8N|x^%9>g{=%29aT6g8h(l{NK|$)<&`#X!)J-0za6JM#H0NBJHXDvj zoMq^(6}vAxUM3h@^e~sms7smob7}=}vdAdEc3KG2aqOkbbw%u;Z|+aX-Ww}$D61Y%akFNnFR{Zf61XX;eBpw+I=5dWiN3eo;?R-D*iW= z0t%TwjWD*rZo}O^y|6wbDAo{LxP`*Ah!i-@x$*h6c>vQ)+N>8xS)fjEx{7UBaT9SF zoIB(`uaqhdM83{#1vln_K2kWLBUvil?*1FHW8R6~KBFcJ`qh^>0UdI3Ybazm4@m7d z8@vW>T(x8T{{zIGVut669>lq|4g078kH49oPKf1&Jc!*Bh$u**81xZ;D2%+CFUnK4 z$jb2EBu1giZ+92MV^tHM`9UZUg47#BOgRh_Z#bGlr8q*#Ve;`+f#cB%H8W|LdSSzH zO-l!n=jT^Q3F7;Uy9zu(tT5NGHD;UVc$P%V2xK+20CdNLFClSt#TvS>BIWHlRR{zr z8^aKU)LHQ#tU-b^cRWEjDIwj#2f-lR=8!zL+>qOED^&iHX;h@dVh##lkJL@wB ztrz{gay|`|J;olueG2(QI1D5bnt6z@8UP;KYx$d2qkj5QNH5sJY}djm%HJsR9$8@g zk=+KkA&d>nhZ({UvjX0A4Uf%45%$r}&g6RJ13|N7OkE@x{v|S)0F@;f*HbC&fr3AL zWfaG3a(E=8e8wI(9^Z)K0S<<-_zs)km$_~SR`!7Q-kP^uOO=59MysaxG=gwqiV@5G z&IaF;qc|0+O^Ez-o0z%!n4|^(F2-(F;(_rO9)w6TT`OYahEXdj&I`mGMR~XCxIb)N zn}F}LkGN(sn1sar)9Vt>{ABdZ0`H z@%R(ww2`bGKvFvs&siDBA(SdMO1?t$JZIt8LUi4QA>#4;Ux=Fwt$#=%>IE&yheTP< ze!>%Gs#I7YLDd#BF;OyOp0aJ`PWv6yX$X(D_~qoO<) zIC=6q&e+k{>WGO2bhb8H3ZBKN{BVvrd*x-!-# zucFL&emd>}ou(JEtAmY!tk9Y0I9tcT`+((ZFghIxHp`INoYpyhU^C2nHnJLoE_4GU z+{c=PI`MR&jVHhaowboZCE#N&zz zw@=DXs1<3&n+=u{@dVC-B5 z&_&AMM7!3N$;NvTty-u%{DoX+?_%sN*1I(eu}c?)4Bf^Jws!(0`Fk7rZgqZl!;ur) zFv&Twa@vP?r#~Ycexjq?VioBM?!)}+PUQ^uzj*kCBMI`H?d>^x{?pef)Z$&Qe2DTd zoR$rE1*(#xPN3Ei+J0v_)6nt;t;=fwV=mAEPo+s_(XRFupZW+`4BiM#?c6XBUsDm|AV znZX+xgs`6u+=kwgxO-i=?}icFza}w(KI?5baOO{_E~5R&s8T>2Q)uU1`@lbMQ{MCr zr8YBZtbNPq_cbTLn5iRO2v|o(W_wB#9698vZCV8Btxf&BwG1fi z1E(_!nGN46zXuDpe67v7aed^*??&ke(FuU&wQ)eM(aL_7vdMW)99e=d56+mC}^lD-Z+!e6RA7%Oa5Rlvz*rXGG3 zCJzZ9c>US)k6u%buz3JJK1yB;KJq*T&+tDF@2yDo%Tpp&|0ZH_w{&xg{fTsg6jZ5O zHYHSdRQ?b&gXH81JI)*N9znw@+|Cp~r4)GmM%l^{rK`xr05w3$zd6FX$l889VgVyY z3rUTdQbGj|l+9%6jr6Fm-*o#Y3aHEEv>wQ5GOgiUhnHE0fd8q)0xJoF)??apS;W{7 z8)APo$Lx)4Z;0u(Xpjgnp_9DPjEBS}k4{0PclGwf%btWz&mPYfA@-0k9ZvMO;GL+cq)hl< z*)iF1{$N@eeSUll)tluQTN{deNKIxj;}nc*mkw$8G(F2SrSoWsJd7M|ewO7HRxUaC z{hT8T?y0=(haYl={g7(n2yxf3%7C~5e$6Bx4aE^_(s-WFx4zruB;OY6ndOP(J^dP1 zLR;XojU0)WpCXQ)1%nCQ)3&D{S7_238ORgxgFG9(s{QO~meP<9&b+V2NA$tDJ z?sWczMDAiUz%iQuCCaalGRlOUdm(~QQyQr_rGR@KB0{D{$TOl4EvxGHuaL~?Oi9sW zbsLIaW@O!@=xY`agWg?B?hRaE728^}3Pg$~2TL6iW6^+D!IM*y6gAGM$)KTJtx`tx z2YW6QTtHnNPE8Mrm6-iy!$WCI4Wcw*M{ud%ft%RRrB+ABT#bu~jH_vV(XUECTu^3X z;rBPpLC!WQT=m6h5`0)>+m>k@TeWlj@-d;oIs{&da$!*H_a3kf`R_QT{P8x|0Vbvt zZ^~#YC07~O29#y7UwGkd`X`>+X`)0fpOQmhXmnMez-a%h3j|H3=vc6XNzai~#h)QA zBFo4v=$*OBd`8gq`**YQGhFZ1Ku8BrXajsELmd#L&HELlA5;;SP7Dr@5L5f~iaaof zYr}SZWm!d3o6a;3!+<|SKv>mqcZvN5PsL|=_Mf8F$YFndZ8p}AzspB#+VnaaJc`(N zE@*eD!QbJtp(2=an?d>sa@!?;;ye@+9^v*Sp)BjL#36y z=0-}V8I%LHAVlPg(?|qV9(aD2rP@9VHdAs_>!hIc^ zkdc54r{6)7B6Z)_RGV!Cg7!@k=~Ncl<|o%wT&-o;kQl}CmPS*e?I)2 z-kw{Uy+))Hch1;h!}`|-2RkiSW>U|tU@!M#oKz$}N4^FhZ}%XK_Yk$Gn8;7*CDbg^ z6!T5ToZ#c`XbBU!z(D*#ldL*D@-J#|3U`{!ito)Zfg@Q-L-XX1s)aWV3IyEF5%xOF`+t23*~lrZ=^s{w)ZG)#H^pe=`_x5d-Bqhm}e4rwW0Cc3W6n?^+Qe7m|TD%deP8%vruDrAO zn=Y_`ZTG<`&Lz4l%HT&Q4;W-7>!MtMTJ@OxvCkJj6*BBiZ*Nu_xA>b#1toYoC|jrU z;|{woGIoQlct0zkqMQJF&oIId9Uo8akP>jA6a2OLTh@$v?PRD(-vRy+ zZUrqZJeW9nEwDz?aFgw;RKNKHXbZVGrkYp4AN&~#-LfE$18ubz$(;ARcp7TLZKI6+ zo&;U@vVXz2?{FWUn%(PDrz{BH>S7JW#WCKC>5GvA^AwgYv!t2jRxxHW5N48&9?N14 z?@#G-UQClse1SnEGhVM^G=iLWlBnlmr`0ij6rCD|Q>Zb~pLYz$zQs>UC}z|>ltt=f zBEdoT$F?)>>Yz>xpI6?nfvd<#YpB;d_wQTQtij|gAp#KG1Qx!ww@+GCLJiR=wsB~2fOOc40(^GrMl1ZKZJmYb&KUZC7a-j21^ z3?r7F{Cd?h7K6EPQo*5YqBzVo=@V5Mhw3v-d~MY;>-_R?em#|bYVgBuNiWMTZL8oo zgqnpXAMh)kD-H^FHVpy_^ouay%qJ-2gz&NO6sbiU1t9()X`Hj>q=dTiw)N=HF{0R6 z6&{9M?$og7dHX*-J9S=ye}RA+kx%|V+8Da{@6^plC&}k zV9mB!$Lz8``kN@*&{C9J$a5Svz&CLO#`uQ66#AJPs=|1+!kXxg7=;x&Z3xPdWLM)J zlw}DlEC8m#=imJ%P)3+~g6N*A!XErNEPlT9;6e;oBQF4^KFGb69J)2-KIow@h|oiKJwiY&DW44H=y*Jf zH?|d=d~b>DYB5FXJ!LZa3c6henb;0Iq)x6x~3$i4BwBX1E;+6?9MC~9qE z*L{2?J;C|@hBu|#Pi-#2moh3rf!n}1fq>EiV!cHGW9)UAYL6d}(>C2^%gVmciN&oi zB3)}nFuftfL6dVGUl85&c9_q55AgGD&VJ>}pYx^iLoA@GZOw%9?2 zMs=TZ3K#SDv>?aJ_NgPVWPl#e5CmnajH4m^9xipeaV&^i{>Sk24iPtJ-?CHv5|HZ< zXINSX0O&I$nM%Z!Pd&CdW8!h&}~DNfmZTWhtDEn1(}i4HJ)?(1ZdrJrOT$CaJ1zj7_F zd$vhIAczcdxni_U$)AYLVHA6?k*8=t>9+SVO{TC$MyrTB*P|4PSF?J31E}hq4OZGp zAK`&|AQGMpSyncXNKWOLHw*-tcFZO&zrs~sn@VAC)jb20*0(HB^NOY5ANw`n6jc8^ z*9qZA?!sajMiea^$6)tnz7Zy(GcD^&>*DwMHQ#Azt{~c9t`dw`@j`>C5=q`}4wl;s z#9)$#fR}X zF7~t8H^M8*mjiNH05?olK>MtWM=2)S?V|Z|OZD^e zw33`suo$4yWyPDI3$q9=R-6*ja(MFlJqmcwIa5@!)j`_Ni>a#On*Gf82 zNS^D^q(|ad6R$H_ZN!y(MD$4}`v66y&s`y*A|GPZ8L>0{l&G@tL z8H{xTO~IiE{fTKi@wm0k1R&n7*6~qraf7#YS0Ow$j+FX=H0$Y2AS{w|pJ$S{Yz-T*dP>jJ^k}zAb{7nsC964r^ zG^+64P90`rCOn4Hv$cuz2cPpgX~iryLx`T`S?4tyo0C}6p9Wa$gpclPtCgrJb()ck zHYVE(?>iG5mS=t30|h&%@R5)SOH_AhXG?fCEKQm;x0aD6$@oXO>!B_z)lTA^4g;z& z>Q4fD7)Z!YFtT2TmxjH_Qxozt_y%JKwJ18@;GqXiJf>)z6oK#V@^^S{M$*FbRPC$< zANhuNp0?M;pe3QhB3V&-k@XwH%6euXPFV2X26ofkh<>-Y*gsx#k;+h@Xr!c^n$9(Z zRJh9O*1IY(vu5xkW}?d6&FwcQ;2WMSdZ99Ob-nFODZ$^A%jF00a^{6$iBMb}O~G&H ziHzWXvL>ytcHvTN0e-AXD(BQ;Q#I$ns-cdsyKhY!E{Gd1%Y!J(_6n+s!~#!)K^?8a z`kV9`?Y(UM!=iRSypfhtE%>1K{AQv6H z_RLg?wzbyE(FdA2x#>F`mS4h0+|}p8bN~vc+8%g~Ar@uHy{onli3b8vdg$ zL`~*kRZ=b|2dQ=S6$A;zQX(~#g%l|Ff<*F-j?=3yLtH_ow?V=%+@6q0S?Wo#K(z4p zOeR8)g9s~#P7d}i3(x!Q!RP1 zmM51ITac{Yrr(3KgH?AA-^wax1Pd!~X$JGRPZq{%I63%Ecw;hPY3pTvdjNe*I}pZl zToH@NJwI?r78p@|o`2JUM0n9PQB2#by^jV{H6{G~dlb_F!I%;MwG?Fau9pSb5^U+e zKHApw$xmIOh+wpb%Bb-MeIKMv6qQ@YsqLfi*>ZM~K-YbA()*ALvpA-@3lyCcN`dlY zSbzCV8b9N|GE*?_<$!frQ~6#Q4M6&_1(%lHT^z0g-<|uA3riaRF7m9)A&$*gMe!FY zH(9Qm91Mj2ghgNiY~OhVUey21egI1dq1cUBIa85MdWngru9ALqR)FxXmpuBA-!(&WjDDgH;xW)!VTQcrEVk zLx>Xa!#+Z8lg&pbS@f|ix>JgyF`%==)@9|$VVp_2(}P;xTSj)&BogXU9$M5?8ghp}FL_RoNN2NK?j0A@&IhQ^n z^QYDBePE{K@vFE6FSjj9S^njD+{~>*C0w+*emW_<1&X0GXp3=y0VFv10I4&h77kym zF8qc6i^Y?%Y|a^+zT=zuDo@s+XPUL&=<>gjr2iN@)|o4}HAIvtehBih7xx3c?fHwZ zRw&0J@_wD^e>&Y%Zf9Q}RJ-+3Casga&$s7$x0@_(esE-Un3aP(}?bgyK-9$_+r zzm0vxgt)S+O)`t$y*_UOBzHvrGVx$zd0K+ogrLpk&m3IRzyDAB{nf-w9caaMEDbV}i2_G82d%@3-{?m=>v7?Uk3E`n$ z)K1&wx2ls=lS%hADLYNfK7BU6t7Sz!S~WlsoY#;VM^T@rdSedg#WdTVO|asst_$%u zGVSUl8?g`z)F~2fK1Bc4nKlI@EfO_QrHSeyr3dbfN!WF}0LicEW!lot<_Ss|0KuxXcFFrML3kGv_W1<>s9O_{&*dU)7d1jCtSsQNR;J zXU)o6?}HZ-3U*@{WyE#F?6!%QF$`*ULT&*q9bSNI$U@np)RA3ax;3=U8kb1nYV`~= zaZ^K5NMMLoH%g^I7mh6-SGMM`F~P_NqGLwB9B*|8WEpkXlo1o|Lz81L zfsY%agutk1_6@^_4wxyC-ZO7*j3W6P>6!fJDCXtQ1pdlTOqWatfhH|zGTbgz(CFfX zrnfRIT}htbt6iY(5YxwY`x_y!1+8`SALp$Ej)?h0$?_rmk8 zg>0f$i8%K(rEI>NymBrtxHl9y|N^Z2}XuROH z09x8uFWM%zRxajQXiRNNfuV#s&-%1`vxh1fsJuNu$CrIxqlkDNV6WK}bPuXEtlxfQ z^n^40Q?dAkLR@ltGM$Rg{`z?iK+U3SdwyP zL@h#duN=AfRjco|Afq9Q_5t^e<*5|om~n^KP7`&4oKqa2GxST;dy|j;Ad!NMN2(cS zuuzpL9H~W#Gy<63+dw8JYpKjGoFo4SaH5@GzKEb?at5I!#JL8$RM3c;)7%c?^!?`F zWI_0IL!#qmQjEURt5(6OggVyv3VJV<{5LlHP{NmG-aFdh%ZJ%F4(QCdQ>ZOTHuWNj zXty5Jo2c4H)F9MX=X|s&x1md?<{d{vKP$3SrSyBmTqq33&)CV zSv-=-fH(w+^HPk4)Z!p=9F5X1bX$$T;dI#Xv(&6;A?B~Qz=^Q=Hc{WvXR6ZOv&0ac zOSxBf9WXcyB^)xn5IzM5_*X%dX!f&0=Ncf!eDU(5a;W({*z~w%l0cNPC@e)E9{@Z;3C94+&1rjfKDFhH2i66nSk&26c#D(?enU7*yyKTm6lFs%+Z4f3cNEx0ED|Y(q z)ZvGV_S1jQE%i97ILaw_|4xYzo-NQlSg1wJVa{2b1p_j!uBu7%^5=YLfKI+;Cb#r( zbqsrEaxF8*7!WQLK&7J~;`ak8kP~*kbz;_m?Br{XsnV>98$%YrbveV9=6* zUcH`(&g~A!)e?8h-@&N!#cqsED1rRfE`O4R+}Iy<_ahYSt{C~x^2Gt1BCGyy!t}%5 zTzLEX;OA>&RmC_Qh+$QK)bNx!D(eoz1DXDTvmySo5Ide4Wjn?o<^aGV{LN=8t9zc2dbAh?5#)Sv_tCZYYpi|lH+(bH0taxhkvSwhZ;VX#tiZ-z0I;XJyk>Mx_jbaHq6T4A`;2>fUuCK@@gUs#!Jm1Hs}%)e5CDrN&*PD zd7#J6#Zi?NPk$H)B-xv@@~fu}MA3D`U)U0B#W>n9DN@L_O0yEBD`o!kE{&<&zbou5 z@Znu9&KCRWM0mj=2xqP`7~uSQvUVS$WmKdwrkg3Yu7IN2hW z1Y|v@S==sld`9yzdY=?ov@f%EXup?3L>oMuQv`#5%g1udLt*$>P4skXDP;CUn0CF{ z708-!ixZp_%?J({;pu|v9V*58%DmtuvV&hXTw`&CKXwgs&@_>sPpEe4v}uIO-}dsKxw2Vwj-f!J5!= zO%#Byc{*q|_iY$MIyx>X0N{3$UUMRTZZ7_pgvh?}aMm7=Wc{G~7!K}qDeL$qsuH~p zwin79KHMfikN%Rq+$PTch@V(P$7yT4h`(;GL$3@rc=7G6Z2Lii?6g(J{R31qr(+Y- z;|L3kHOn)J1pNR&e&rQ&rI*BdUG~&6QiJWO9sx|gMH|BHo$l7q6lkNYu3BA$Xq6`+ z;cM8rMH@JbD3)L2h}1TSiv=KQ4oB?sLv$-&eukXxx(eecsZpzq-_i{7bFT9q(g2Fk zmuyn{^+iLw4VGK@9*M%;@e&nVu+Oz07xwc%lNSt_3?%A4`lGb$ODUS8t+Ml#Xp}$V*-6=L*<_ zn66C3rqOS;mlX-Cpnf2jW&JSlLhkv;@@*S>9r}*OPWo(ay@uBQceN%wEJ%{fND)7!$Qa)hn{-1TCv2k-7xKodMwIgtmRb1f0OwY?Qs0Mv7?;Hpq*RNj@d;V zhf#_82XcSB1zIS)%VbLprI4y<2{!*IcKN z>O>1Ql?;}XetTMhW0-ns7m`#Sr&gTZMy;Rr89CP8JfO*l&Hn)e!d}TmTH{dQ_ zSP=F~T8ma)^*{^mL zPw6*8m+@iMd12kte|6ZR${Ky8|B?YoM6DlR~cXKi&^RR&(zkN(5=HYseaa~;muwF~j}!PjGE86 zX?#&X{^AnH%nH6Br~=N(`gKT9tqD&BH{5k`k?*0jFilX^W$fsjs|GN#xtuu=>ZrRb zQOT40d=?>7WMcR%@vGe?8hU$b*O({+80M3`6rPmIhDXz`xe`cUY#6MyuUQT9W{%vA zp$^_@nUHYsnhL4d;(NoXaZ-?U7b3IX+>nsA}sM+uT~+UdQn~1K`~}|P!cmc zn|CPLBQAW3%IKJDOj0(C%y>MH)bz&!P<=tp14U<=FyUgdF*i4tpTh11?T@@gXQ_$z z+5ULtyZ0h(roMCLx){)D^1JymOU#XReaVJ_jA+)d5Squ4xvo3YlO`-G1G$7^7FlY< z8%7Oh4`8*1dNXLH)#-A=i96Bp+Lbm7${3vJ{ydIv@)E81wbM>ufO`_w=*JE#h3zK+ zS!|dRZ7fHOWJ*U_K}eX8Cs5fRc!9<`gifD(uPzL-Js(gDU;@Y8rU(39*YY8Q&`?uJCh?WLU}>)q4Hs+QJCD~mI5!)d z9o8-TAbt0bM`$L^r;IQvvX>}^cjiZ4GHnIy@pju4#ZxS^$q?k&o)oQROV~617w&E| zvZ1)>t1~jgrjcSACox-4QC=1I(Qw;K!D2~K_KX^-6v z>b{DpfB)&rzuh+lS5Y!e@CVQJS-r#}8`?riZY_pAgtca6te?;D5LeZiV!DF1$(Gv0 z%O!Qm3L|c4FodAXvC?UDmg3d#KolFP4lD=2rz-cS2zEJgSaY~o;U&R#B-VrC1j>&_ zK}2-gzwF^A?ODKll{$tppRuQiC9$TV;-((<^DkZBGD~YIKcq_c{q|3Ds@b`=hi6y( zXs^)`iBi567;1*htCqdKG>tBfPiooa{{;;E(GiG3ayv~L@T5;Q%1yp%WIhYP5IM_y zzT=^-%2KXstSai1-&t6%XghNT&VyCMUPV^T4i4^mo;+0q{hS_B(XvSXrIo6v1CUaG1s< zSes;4&T{x7JO6(CgiT&}!**u;gAH6Siv~5R!8wW$6ZBk-Kqe%XME_M&2U`45Ed|>d zAH~V&m{|KwJvHMg!>yzs9Qo~^Cq2gAm+;KE;4bxQ`C#Io1O+&c1eUF~(--Aoxy?7% z@fMSgSE}9Io^|1qj=0UPv1)^#bh5 znnNeym;Dw`CbKsj>hDWWXw8FgUI+dfzA5)?6*xs=6vM?<-W1=v;Tey_{e7H;M>)W zS@qVIq<6T+^;rk1Sr? zzhFMOd9=HV!vNGNS_*e(+iq)ASY)?k+RZ&(AWu7Y_TZn(U`PVZ;||miih~b{fA$Ns z0sJxa`oTOa<`8y|}&=&BW1!n~4urfrKwWxL$i?g!1yC2Z*OPmD>Ssl0Q1Z302#6Ds>2#r>h^56+w>Wc4GGDJtU)?gfd3 z-4aH804Q8*yTWqo4n{sqw@;GfuU2izx9IJrmQfpjR%)>*u@fs{07L>8xI0;3hOP@@ zOT9@l#Q2xSlXtw{a(aUer7xAsYZAVL`}mkP8lVBXa?XmF7)*^cyae}ynI^*i3aZ=L zTWQ9XA0W91y)l~=R$6^>&z}P0lysykD>w%rDB*xa*h0*R#%VD`PRxKy4R&<>~Q(H@E=`n+IHYhY7dgPos-X}T$sMy4`1TxIX5 zCjNiBY%LjNU}6|VlFI6Qn|={_Uyz;NTx>C}iUiN2LjkD&GDM$0^ z-nFDCCl`Ew?;8#gf;bJ$Da7+;atkKjn;HHe?(|Muhqbsv6lUq9XTIECof(eDLJjB~ zWrO_~URw@?PGJ2yWv69f!qf@)wZS6m{c&Ahr7?vefKf-v2hBR#jUXBmoR7m4*Fy`r zJ|#P+Qh|4DG9POZDF~9F(1g~qNTKbvluKtvcI6N_=i;Njsv%LlC6fjzM-8L#1LY>x zJ^@1Y(4#)U_NN&W_xaaeOQPaJFVzK$^8)!1Q=}q8_ z8BT)1?3g@DzGngAxA)e2nR}@yw;OE3%SQ?$)}(!v$MPTqPEH=WiuA({67VGARLtl1 zdqbYTlyMh$z-$op4`f)*Hpz98^H?m7@Ay}RHVFMsofRiiLzh0@FSf%k7o1QciLK<_ zn)9myi|*8(fh1!w{h#@@6>ll-Jujq{qX5%v7L3onxe`sTgK2X~GO~7Rki2RT;e)72 zCq^VgrGs|z+;~TO5d2}U3cf`!q;U+zUNwrOxCo`_pI><~VdJ#wXgMg3(6&uCou>4ni?x6Q-M}><4hnD8T4Ot&uI* zI+Lh+RP1;08l@Be3M=V3tV0RrA;>@&9e?XD6d$b8I>wqP(aA#2@pW^2E2>ka(UnVSaH2UNwGS+=S& zfEVmOqAtzkGj1o5nPRB&Uw`~bYcC2IohkXgp~8$?igB`6WOBGVv~vEe2#QKqeHNkA zdkDbx=T{EoWAp7h>}j4#GLD&eM1+?B5?&XI{#t+}JgB_HfT3a;x&gF691Uoy{u7wC za(ogIk>^f#NlS)xevB+4U@bHtU?%P`{xsFkWA&NEcO=_rnwG~F1&Y($R3za|t- z$;T^uY0Z60C@a0zKv-)4NPVGGY38PFhmrV50%cLhE}!}V#I#3NEGwv(CG!Tv%G(L$ z>bZUJ)Z}%nx;cwxTV({a02N-d-kcE&OEP-=(cxT9Tv7}TLPXfBYfwU0pG2(ET~+KFA%pQ!g!P6%#JfUz6#=we%69!9xHvT6M-(D zIt{XwFo}zW5ofjrX#8^U#?9!h$1u`74%!^mc6$2=a*8j4h$O^;&h#;Lnn>_{goFZZ z7=jg&y=_Tu^_wH&X(A(dQ_42P4YaQY`rBZ~ct&w8@VlCWtIQa=XP%h}enqP@@+BVf zT&}+H$P?uii`}nhNKN^r9hBAfApN+zW0kxdpX7Irn38iMDmwbFLjl*zI>|oVmE(I9 z6)ol*@ad5mba`>(k4ABG44BMfpQMoQ+w5l2ApC^`oKS?7*6H^0mM~X|`4%ATO5XBQ z`-&$7j`el$c=+okjR~&@%BRn% zfF$t(83-~*BDk=ME;>oGLi}%M&w?&YKv#!ZdYK9xDqQdoe6R*4dM#_2^fPt>S`a+I zC49?Ql_BfK$GAKfH1r7d0O@Nv9h$!04R$snoPK95Y3Pypc{a zPaRoM{vw{p5OfI`8W1NS7&tjw(hfz5lEaiVEunTXz?%7)ZyMAjbTC4Wa~>Ijm-~<%8H&+7oZ1x>_310&p?Z;0D971Y zR}!C(QQQJyP3F(gQHnRSpNh-f1)!Oi;CLhM8)wBWu-EmJ;W&7GS~Ed6&s;(_sjIlO z(1&!3q!74YwxG4}o?R2#OY-)<|EK=&Bqm+Pyi$2Li1vEm^c7EUHuaVWuYf`73sFT1 zyJ8CEQ70P>QvZ90iYPA3-e{C+k^SZ9h zYM~2ABSa4L2?QAnA0ZjWeY*%yK!}})#t5#fpP8oD!7y%0^|_$d<)iprw~CtrXE_$d zkf-V)5+E-mlZ}GDJoD)x|Jy>VAGe=g0KIqBM>5raH8tVr+cn{th=3@sZW`9e8>sqwmDi90&0iT6qTL^} zFg$ms@GOxg?uGZg;qZWnz;~jWN!)Ap9VYth<1IXQ?yAHK5mZofjFMBEy*3w^aj2gb za6q%opV0n%bx>Rt1F5PO*zI7x#yGuEg3B3%|NE4JntH8AV>r+u=xZ*;Cis+-oNtBD zjIb++lJ7}ZH^C$bQsacc@Q7kTiATy~8ja?6{dlHxaZsvIV2XjCRFCY={yVU2)Lz2X z1gRH>jhof$U2HXj3^W~aPY*rVzj8V1pirf!q`J%0uNyE*rMTf#4i|u$ zC7fbQSv*!P_Hku97p(8#X*(4?d>9WtY|DJ(#hk*BxxOJ=?8U6X4hM zXHpa>YI@^Rkq+Bfm|DZOwsiE z2ck3w;Vc#HI5c5^6=P)|l0B%n#(AXvId3bvsfr7(hlbrVoW&QyRAQ^dE2flzIV*U` zy$TY<6w}T53mgJLNSb_?X~kD5^H|XB9yhTd9Sw_4yHh4-zG4-b zKEWeb*KklYLJE?`1xAqId8P*oyejTS`)@z%ro!(yS=zrJhN^4zMKUV=Zg=T<9YlDA zrOP#OI>9>}b`yupY>HhzXO7o5FB(H7z_XdMezd3m6SqZvUSCh3(tSngT8FhgF?_uO z#nah7DJ@2v)fovs`pK-c^3k0Vb96 zVQ=-@|0`fjuG=$y?Zh;+u-$=3jEuqtxRW4*Ct%XLP%V4gL`}k^VELy+%zkVkWH-G- z6;|J&eooaI^k`m4R@+FNr+BwQ*7$!v4}%et5!FP178{geh|K#ll`!Ib8m&Lm0eC7@ z`5-L0l`_V#AW!|+fF{!2EH`S&u)})6b}i(?IxJlEIy6-0 zV3x{QCKM4-56dm2-oR<_{OvL}cMzW8skxoZHF2gGR%N2WK#LmK@jo$2C>v-5o_V!db_v!c7gyJW_} z$D&(NZD$&gfLnvy?~$s4VQfl~bYG%W3k4Lo>2oaeIV^prB84G}Xl6;oE6&FZBA6%u znTNDRj|3IRdFnDGX*a}I-6jo^H+3{OnW08;%DY~iB1{_~YA(eh*y8QogH_Tkdidgf z1dsu@fm4MBbFEu>wJITi<2yH^ zS6-E$!)Fklx&d)Qoi}1!D_#m3#(niO6k)V$S!5v7wX0w%uPp&OYo)3|NS$K?(|%GO zAh7sw)Cf}R?5go6su;~7Z)hz3-m+#W8f6O83E&~!YW50JEK;$4mpOpo4YNG5wLa}m zi|RObe`4TQ26rTPuBC`{Z!^!W2*_Ipc4Qu~g8p>v-VNZ~K__6%9=q;$PluxHwqrQb z0|@S1PGpZrkQSi(=EQgcucpQ`b~Q=?G8L|bH0kU4HwNC=nQ%pP?Pi;iXO&F?aRA~p zLTxc-drI|?oQb*pK{BBTG|DS#p-oFFk+|aWQyol%66$NNTbbI9%O3o?rI>7JiUDm~ zZ1%h3qaXSx9A{LyK!z~W)~@0v>V0i1W2EwDBTgr}Q!!EQoC`-LAgj)F-Xv5fMpI6IZqck~eJ4f%sy3*1rrY+M%xErZG!`8y;IEvB5 zBkjg8G)}}BW;tG=0ZIa+fYjO=$-o&>B^?8H8XGD08$W9~hD+wP=ud`Yq43UANwNy5 zvBAU1_V3Rz=d%$L>{xcu<~Y(96=7Dm)3&3tVJv6?qW=2I{Afleb^-}w^Ys3mo5s&{ z+5`DL-^m7aYx9DSMWp&oViO?|Uyx`&;=+Xc^E!KCXJl^JF%&EP7+r&#$VCcw4958G zIkl{tpE(4mQb3gjmL@xPS(UHaXxVRV~@6g$(xLb)rZ#_hib7V*H)d2Csvn%hB)+in0zTj0Qe1XQS8x0xR z)h1o&?x`)WeVww_$h=a}J94=ziuCI>Xo^39)vqwgT~xcR!k0RB&fMOh;3wddu z6{PcQ+0!nc=1R60^~-;>;eYENu;_D2_iwn;$(KbMZGdV5OO=rOW#vuO#AW2l+~FGU zrHr;^I`IIcq~(yHArmCEsl*?#ADq_qs(WZ078hw7A8z7>2@w82Z3FqmN1q4f`I(L= zA8t9c2p_KApB(1DwvOdOcPL0WiRO@l;t&6Cs3>05Q0t>+DQQ8~ihq!E_r(j{nTzYj zKklF(??2*Ml2#UH3B8WU`|6Dd4w>l3K~|bwXZD{W^@?Oa+~r2f?Vx3_HkRh2=?LL> zfzKNfVOhy<-&+K&t16mXJI5o(!c0wILE8sWufyDYfFK5u`%qKHbt};1ayAn0$Ka^#9jy8|ZZD)31$mqnQxWhX>#u${Gx0ki7%mlU#>8~Ls~4o@ z$1+@yN(Dz}I6=;zyLIiQ18E6Uqe|nEK!C?Dmy6Zjm!f=mPX$TMddNZN4zJC<|8?MGuK5EFVdHnZpgh=us_&H~2q)?qr7<5@$~R3C+3O2FKrNaSAvT(@?U z3h|nH;B!%%y~wClmtUb4Tj`42__x)ioX!ON97q!r?(mdESii8PLehzAJ!<*vCo_&- z(ag7XDNqUA-g(XS?4v7&p@wN&iJ_q&qbT7mObA7V=dN_)UM`kv2&S-jq~jCw_eegr_TgfOQVk zbimZlVfB~+BF4Zn{z%ro^cUo#2g4=*4rdGUUW>TjbEpg5G%)kyG~n=PBqbWVxpvJ; zTQ|jDu$D6Z(**{IS}bYTuQjQV(@~Y&`D@)74*B_n1Jv>mJr8afvY@4fh=6?2vGAWa&>m>#9mq3SdOu2#70+9P=Avjw1JFRG|wqxTCq}Nia zsq93D*5-V!%_nw$o&d4MXc=#N-AcZ~vh6rnQ?9-c5I|}=U}t? zY*&Po#vld>y9NxSXyc$OPdU9bk8+!Qj=a`knmo^Hdg8UILnD66$5-FE zg2PKbSQf>qyn(_wk8sv9Z)OZv)Yb#3jW*FPJyYS!S#=t^U6a{pcDA8aHhU@4&`rR! z?+q;gGd0=BwmGS6UF$`l!vlp46``Dr{Ik19+c)E-tb;iCE%+kyG&C?%;Kj^ZYbN4N z^rTb6AX@H5#v;^QHUpjo_z}|#un<7_mHR1;{a6OZZ&y-Ev<4V(`;^=?<{XpJe7ne0}0dPwjcCIeoof%BU5!8^DZh z!)=7{PJt!@P+ETdUVFXmya=6^J3{N1tfpIdUdR3ct<7Yxy*&l!Xtv+YU5NK`ITh}= zv+F2mCEYlbu!g7#oBDK@26;@$V|iaDL3f(XeB$&uME+s_U&45yqw1lGMICo<2}wNF zOdQDR$E(3|_fDNGR_2?{;+=67LnK_^cxh*Nr$3@F5gNxv@$hZ0A)6ce75YrS8vbew zg0aUH5bymf(?%i|02~w*DSGqQr zQ2KYY-FYyEU{iYq!HilhosE!dv5NDH<_WF;7{FB?@)2AWnwM+5>)q4DMyNJ!8os*J?rM53! z9-GSceG$cL7H*wv$88l$NjbpQi!8dI@>FFh>ki(j;rdtFx*1I&SuadCN~$4^`%^Uy z3oiFa5filk#TWXpH(Fq3WIcCEUc1XQR60mwNwXSQ9b#ko_#_0NXND7Rn7$Bh1t*ZO zBtKFbwY4rLovAt5exewf!RRdI-5t*)9GIVf>8bEf2EDw@y-)&pLyQMlB?VGkk_rbh zWZ!G95M%)Fyh|cdhqD-jMHHE&o51QT9%xr7gAK!q$oRnA%ZjVob4PFhMW>AHRz&|4 z&T`ojo0RIJD!Li@;|Otln|Wqm;b%XtKpvPesquYU>&$)Q2_*kK(DGOlSFtsea9V%7 zMh4-kJ!r7%NbQvEQT!gOwJ|}6^VbpJ75I}3iH;_SBBIAF%C-g@$m%;NdL=5NK3FcRn4W)+rA0+queW ztq_r`;Yd2x8ZnvNVg#bv9_;fM47+%+0}jY|+0Mmx@5Au2IyN!dY%8+QYcdHFkoeUz1qL$VdG$DA zEU)@&Q0K_MaW_qS-CJV=YO1`~bL0ZxU?fvFV4f~lc!ip-7E4~|L9QXhe}67fKD%mM ztAu+ng*6OLx#X#C6a5_BnA5~ge(|4aeiWt75M#Ags?Ge3F6$L{;C%7VJp=$dK*YaN z(~${kmaFBOVOEV9u)&-P~cM5 z>xJDSOC9~Tv%!NeB|Sg3GpvafJ5SpNV5L-LBZh-TW(O|WEa<1zl@lA*z)#)4#SOfv z8yzWn1xU&}pUsKkmi6zg<$!s8wWuKl5`>%a9{PbD(8y|mPVc0Rzdasy_4JSv;i$=S zQLd}R;-r8aC@9Tj`{ZE0ous5-KH60d@DRs@wJ4uh$_?&7wJ_Ncqu9 zWpZAWnzyTl6fqp~Ks~pY+AQUnJsU7ymTO&=EQYQ}EOeLu6%}8c#y^}DuK1?u6_*Qy zt^Lo2)28t?`?dVwA&Y`A$V~5Q2*h7X`xfAMbr{EQZGKp>nAarQ86> zTZ!d~S0v&m^0`9 znE^4?kOk+%pVg?9%--kx+g6U+x(35%Cs6NggTDZYq70~Vjt4h(^#;4xprAX%RU)TC zE)#6VMi@1%Nt1C~lB(*6DZ@c)6I}mZKEQ^GWqXY#b$brp4Vmg6huqPnTy*v)^ zH_*#Pl>xH+cSn=o-^RG@K=$%;d#Ji+%TIx(ub#zL4VS(z-D8#6)N|$Z83lw*uH4Z^ zIlZoGO92Inx{|hNTg^PSR0dl)x0de=OWU6rniA~3uuKdiSRW*_KY04i^ZOrSS3G_w z$jJ<#!)L)-=od2Mz_z|yb}w3tbsPBXF?tLtZ7G%+{%A#2hESz>`klVa{orHakRrSg z$0?1O^!^d8<*Xl5Eg0B?1lS28H%IStE6m9RK!yud1vB!IXuM`T})el_m= z_L+Q$ZB+@U&0_ss#@Yn~Kr_ENN6Ml7=SQrWAbeGuUN{ftmw*l0MwQry?+L9q6~Lh1r25&B)hVlF zVt{<0)RJc`W4L^TPZOvO-Bbq^g7FN2clf;I_yZXdj%0XYHOcwqQcPItVdNfoA)dyT zOKbQEr0-DW%AWmgrGr)yYrAak(`7tZ2-HNkSk~gfxe;AV2@RFjsz3pS90@#r@6g0S z3CoIVFK&Yq)GP2eiw|Dv7*nmdEWCLwEJv~t`ibgMLm@(NRp~ldmZgrthyhVRwcU|o z3sDzMDkYq@O6;Q#k=3a%X4xXlgr!Zm%g;A$_zL%l5!9`&K(dx%(4kb6#qzv^8#FOLH& zlMGo&BAY4)#oOWU=if9?U{sKsTI&>EID{3>e6_@qpzU>!pX5AA4;N;M?dti0li2E) zFGbmwbaFq{@~?k5+cwXiew}p}<{>OVxnmsUZZVOLf#RlK#bhq*k#0}BAsz-5+GnWQ zJXRXDu~Xsku3%+ZGiqi(I$kI5>gxAUC8VYItkG25s@W>W7ElEW{u zD9Tz8A5~BDmVYH6dTynp z;U;Z6O1S+Nd2dIgRo|ht?u!rUJ4(l*K}c;rhPE}GUBjYa{2>ZwC=r|8yg-(B*nbjei){@Wh#Hg6;s7>Lj;6L*KsEr3ZD8Zp;2$TtFC&T)tx-eqPkuo8 zNxh=pmYh4sOjDQ~fRmiUU4oKzrS^$FX^oGuth@H$g{oD)9Zo`x1c}7C!xRmBwL9s{+XH4$7~kD2j9gG>~h5T zlc>mT6b?e2m<}qqy->-nW7W<~^H=-OZjSFd^imNQ?Lr1lIYg1HJcxB%FN`n-irL_P zC;wB3<1C~YzCYP%FD>0bO)LT;HTbaE$yBR=T-kXH%Z~i!UfOG<1JcxJzkhB^q$lE7awQ2-XDNm5$zn#wvH!3x5UM8 zcIop-Z9>D5Mgg4Vg)>5*a&HVRI>|@G%*?P3Qz2U9dFNC?-HqKNFByA%E5qqL4`VXwjraCH=dPDuv_pnBx{7-7NT zY0CZNxvkGKfyb%b&H9_Yn~$CyOM+Sn4zyKJzo(`md3s9&TE)^DI51+k_@+LFkfO)I z%g6$U%I;|{4J%YQR@Y>l1y5RJ>9TCW8k=R(xG~a?BfL1$2`I*_N|c9H{A`0oxxZRw zuiOM3^l_}o#iwPNrh2=x0-%!+SE>>Dxd6S|nP2hEl}nJ_8|U-lsC|LM4K`C%vZV;0 z9yTAPSPXYm?G~5-`H(e;u;zx6rTIM{Ej)ZVq^thBcx7T+FRbgEF=OWGTnop&`hbtU zv{-82O4+pzXv%w2eBo>liwyvY5UK>yD&jJ(Aoa|0j5$n*q5b~*z@Yl7xWO0}H>KJG z^~U8n4QR(FFp2n_{v{d#)`58Bz+#ap{6;P=bq+nem!qu(qX|J7n(x32f2+*o=IGsE zD-F+7uehH2piLd{1&26FOP;iS(>YGH=C+!Jn-IsbC_f48>E|v)xab|k8bUmm zG&OP2|G;;wcs;xk#Y6OrHY5Xyg{mvgKq1t5sG=M(649$bpb~5OcyZuqm_7j7y z!wA9utrjz?n~@n19nRg}Pykj5>aw+sk85_X3f}-1bzemwt*IZS_gyBL%phmecB_HA z3M8>qVW>Tj3|aC(GiwAZeqS40=mN8UwGGZDrtX!EyI~-nagL*YM zrPraQb;ZO?eT1&Tr$S8CJ z-SpA3zJ`=A;5b_zxTpHbz1!1E*da>d`YTH;=So{c_ut@S@1pX7abcJztvAT^fq^** zy_{88Cr51OLjCl1n%q}mKkF85@jWnlnQvU(%nAt*@Pd1-r{X}Iyb`$6QP z+47VUtZ&prTN?o-pl$OBy9Y@#71tDB>YU*39vtCfRaF=FijKB#5_*!Pr^A%Pk>&4z zNHw=%4{J>G7!C4Wy+y3r>b zuEA>49C4_RU~0Ev#r%nH$%BzxF*@{Jb%2DI>=3>TGI>tDrqwo7`PhHodV{ROTB&p_ z;_Q$cor`Kiz4wUq&>u1hIc{3!0ljn{fH*4!f_)qYc7AEIPA%yN75xN}ssiW4)^z=d zi=u9=-uV1`Na^n?INGpnyTC(&Zz*E3kO$V~GyFR)MLio2qf@_9){?EO9%jvw!p8A; zmDEG;sK-JMKX||@+Zn^5ae{408=O6zWa>;e;DD+}tI2IBICMBww-6j;Mq8SXkuC|F zW$~_Z@yFM^+|+~J1*IXc7mYH2F~kHsgZe6g4VZc`Bvo<;vnQhZ6Dn z{^wA{m9n0#Ec+$@wr?>bIB#`KVez0Q!tNb^^_izG-jhr?@90&34a_H7eK|&x0mM;0 z%syfnReh#M?KON;Pl1_GJO3g}ixT^(^U5$i-9nOeU$7GKwRx+Ka+oe&SP|x+l@P`t zS^LQ2_j2bxmKUvq<_d|`3^D!6Tf7njZzrz1*nbU^0C!I(qA%W}syS2IXM^!V zJtMJyY-Ej(A+f3eW)1byNu0-M@4~!Dc0kEvRIISAEi!)ZG1K0v$h@;O4a$lrJgg(= z)_|RnXlHR!*8wf0dCDdnT%%@Xm(jutBiiNu<9#V+bjOy>9d^=?icCE@|E{ZgRPC4$ zS=hPPjIccqFx*Pusluua4RJ3ri&z(0=Bbn_)UFp->iFaJrTMGCZf2X!_sS zH-rYatDYnO-HTFl(Ad7B-^2VXqMsRF8th-yJ zm~3qiqrch+ho`%b^%8RU;*0LzBo3s-9liY`llPu9ZatUyg&4}2*9i3$ICSe@)*1IL(6sH1V6 z&^7{ULRjP75q5v8*Thr!vW=n&s$ze*C}jjPLr*pg-|4XIkAhZSPeOF_N=MUT+efa#>p~=SF;Z18uX(^39iHrW zeNe3bpvN~@n3*J;(#f|IZ(JIB+aT_?7V`DleSg<({WPv)poVpXQ9dRN$tfDHaojqS zjC`#(n1|^Q;<3$7`#5gb>eaiO`wzMoXNkZ8Afa-Gm&RK>8M_bQPM?r>pzFX^cnX#` zI_q$Hvf=TWq17;(P)4(*i~P>#AIM~&5xF_kCbkP7TGqL+EIYYo$;dt$;hlc*yQ?Ps z#B=QSjLg_<%F-b`!?qcdhjo~8!vpU(cwexS8pvO^vZ>Njxgpd*P==&^=>HZ!=emw5 zF}iVzTR<;q;w?`Y+L+OXZjIM4--mAMAeLWP2Hh;$`aeh5PBOvU>F;O$GKd#LnBpEx zJ>x#`%POz@u^TKdO*wIMX0}|Rs~5cw?@J0#_gc$wtF+MvP2wm)z&yP&cwvzKKy-Dz zM_TheQ7*gqC!8B0afpW7WJm6f&K1|lFjN{umqkzzd?nPH>f|9Jg^1DTxN3khpBVp;y_H%nWh@vG-o{v8jv+6+Azn zAtej2;1t^~RH49hH;9?w-NZD(-hru+IZtYxr{1%w^itEJF8j2HxVVs7pKO=ai0b?W z(=koy`5Hxv>TG+{g%<8ymc*AJr->9J`%^?;2*sDTw=%U(7e{8TM=(LLtqw3%3|rev zcYNxnC68M7?rVtgN&SDJ5Q(}}o)hxVe(cpTVR594mzu8Cs$H5(3)V^Nh8q%G<+tdL zf6-%z3tUxOLtd%SYeMJ3AQI7);%r3KK;Gma!fmsv-DwYGj{5}DJFlq8G$>h! z@nb3HnjX6dr<4-lE3-GlfP-NvJ*#V&t(?blMRBAWqYqRM_Y1f}G8Jvzw8i$N4$_$;I(n*soA zi_kaP>ZX@#3O?3A3ZkI~0Q+d`(3T5((ovr09wc?yvofQo5%j#$d2xKeUy7lXbS>V` z*pzR4knr)$$teT6sRq;ZZBHJ~fJ#2#YOM!*k>A5P?Qp!nQe#?fgy0M}nh39!jn;{d z(!@yX(u`(k8lOa@Q(F8BfZB%l$deQl-=zzjFt%>|iIMEXPV z61JNLuDv+8?G&TctgnJuN9A%7U6EtjqP0NoAE`swrGJU%X}qD4aDqfa?WkNANRkCb zBEUt#?XA48LoNaWq#ZYeCzuYq4s;~ux{u-}8Z5IkXCe=juZbtUo*n`q3A4-Y+sU@& zj7s@yCF;qxQetrKZN#5%Smr%G4hnM3;+SKxA>IvOocH#{te+J3u$|3z`V@xe#=3dDCnAG z3i@ct^pFfd&z>?xqJ{-vgt9V~r#ot>*>I7>cMMfL-lG4V)j8%7WA1d-JX<@AUlU|Z zU(EU(*@H5+WC-$Ugoy6GB8kK*(f10khZQ9r)o$&&gA#5cazTidHC~S9^hi< ztwkODHpnR`G%Nm@lyclx+iP5SA;dafi=v8WK8;oEjKFh4v`u|APe{_5iXVRw?Yy~ z-mn3Vhb8{z$NXFj15r(oQEIx%jRw=BU_Q+=xqX}fz}Flxf8PUT=2G14@~TZ5d*M_@ z2UCsRv+t!30Enu>tGQDA9?~1i-7rZ4yG(f>yBN5;ZXu1mF`vayxNd%@AE{KqS$+|L zd?ep_lm!2#(lVRjGf=itjOZFig<0FLxo-6ce9M7PH3!skf}4Rv5a3>?&Oy0J&|nsR z0Vnm2L&g2Dgw@zUk7?NNeYTy|pa~!LO-!XhUw1~vPa0_t+wr5RzKNl_K%C{8Z6F7^ zFTmtJV+}!+r%f_jKTgUw=fNN;yyRfgd)lNY_fX-Zs?61W+}1$&-+z#!6@J&R4f|I6 z?L~Hiz)|}z}mI7@<3dSO;6xp7M&4a%fdfOkR zp}e$xBvx-s!GwCl)}vs?X6k=&_m5N7w};AC-$r289<@&Mieg7Bo{X!7YF+V6#zSTD zz)UfUO3|o;Kr{y74d=}&pNaNb_;>Ef^q3QQuLbGwfh$u{6VozA@kBKd&38=Pm7M0Q z>IBI1ty~@e1D=hZU|2WnS$5{ZfmHP{3^U!}28x%wuVsd`3>s!dZa;FM!XJ|XLE~FM z2{G`y){F*YG{ibgakZfhO&Z-3QPn_nd_7+=)_k2I);VqMATibp-qZTN)|VZd&8bOk zl=mtgJrAcD3Lhcy?xT9g*;u6xEn|3e0_z-^`3ieQ87!#smk)?KsT8AgMxyRQKC!|o zsAVKU%$1)%mQiRtm1zmfX!DUdKu3C>G7&0+J=nF*h4C<;YjC!pHv`cCgJQplk9AU<%R7O{zkL>zW! zqlt+TiZ@~qFt}BTAq=d2QH}`Tj$w1YDT|&hV+>bh`49>O`}1jn2S5b)UD9NbmEJkH zv>+0_D#f*iM;@en3Ho+ap}e_PoTFA`U?3V6Iud1I5a07dRNbv8s{Dw~j{@nR_8vpx z($GWO3Vr=7uS7ahjarP$w&R@NPMgqy=Z<~zn2xEo@Y1~C}X`N_TND6}v8=!Idle0?5^v4ciH z0?9oWvxAEqi;y8vYXn8IWcf>;9yW&s{i;OjbF3pp|MW~*Hg&OCHUi;1s0#s|Nu z1Y*l-YQ0C1lzGP3{ceyjK^pUvhtWts%FDkPNsi+brH?AWX$vS(;*7kGUeI#49!T^R`cX6UHoNEBFN^6A(%ZY^Ss!rRytOujMsYu zMbALiSm=w|sG|q=EfeInOQOwKtAdCObm^L#r|H$LhH_j1__B%7>u7bwb2?(<&Qjds z|NJTHH;TR$c!T|XFpS#!cJ+gM>lUg~%`5O-ztAAGVBtDM5b4~_w$&rVE+eWT*Qae&p&NjMqY*NZ1~=b5@}ga$ zsCb76fiwsYL@K0A$1%e##{kpe7V9D! zkLTadk)79j-OkSHs{ashGv@#~LFatC8@Gkho&_XXlTo*RaUVb><4%zm6X!jWJa^?8 z7o9&hsE2!#As}8>k$LEBkKdt8EtOz0^%UNul)Og^3FoMA;4eLf#{8TF`CfA&MGz7QtT~FqqIE15>>6^1>0q3EXP#*hr_(Dsm@=9Tv8Rk z040nb^+1BaB{O-GJ0X@b9~MSY{xh zxTtvR#vVKS$9X=nqg|)TSh|i$>sTroB=ecKP*-%7m!|13n!SDmXz+1X?X-`_W@Zr{ zX4EIQxhqY|Pu~R-KG-4+b9dDoP`_d-CcJ%0sQ}8ORmyWzLQYU>Eh_0xS2-uQstHX3 z8(9T~GpI>KBsQ&&qpROB)XA=c zi`zKdy%xp68u6S$!K-&y`;D2~rg79^=Oru;!L~^b${r05@LMeU2Vu(%LeyD0fc)Zp zQI0zgmg7{e=O-++`ex7|ANp2SHaUi`%nDXz<&aY%s?eWPUFDt_M-!MkZ8Y% z?L5;<+++!lY32Hl#ZK~zcrA;d1@H^2Ha6t?b483_g?FdgGIukaos$rKlX2f;p4ll{ zn^|z3HrkK1_uOV;VxEY(N*LTkDu&&>SBan?nov=qZhIB+>`A`Cp|bPalm0@Gwca9= z{=!QYW}hI7=)2fr%|-nWp^>x=OSQfpK5(eaM^J*xawE;iG|VD9*mA)Z>!&`c-Vc~hXx0KS}h0l+*e%&6h`c`hg-^CS$tDO z_PSqDgacadzAN-LLj9VSw0I5pm~Zi{ti@7qQXsREIb;Z>5@=6v6hZ)0IHE+kH!`1+ z6d!qV3}QfS<3B z_#Dpf=!}lf;MTwzZ9FA0WIq;&%5k2zry>KVqJB5`F4maX7%dLt;{3%gc?~+KH`2h> zVk-VULD#7;yv2Q%VKxI0sB(yYg z?gYe^XppK-ZD-a~;om_cm7RQ2EVSdCnUV1eQr6oxTLLqdKtS%T4<|O(08-AKpDLyz zRb+EA&i6I>t_%2qEPhtMI&=?4^mDtiwKgSId{Ph_W242KC}$+?vb?z}!6}Gt&qLDm zVn5YSE8R0={zrb|ymv-p+>Y{b>HKpkR&^tefm~KW8uIlO8xXVIGn9kD{W+|2;KWyW zyG@xMH-&tqy>pBAL}w@=;IzUg1O7LsP=&6Lo!RCb$xCrXJ<$e3h^2y zT*V78-!U%>qD_CG3=Q9O(Qu-S-PJt~tMU7Lv~sjo;2%ybtCm*s?^GO&yUDyc}k!3&v8Oj97SOir)L2;doU_1&QT{NkO?9fT{-ziWKAWhSTCZ;qCcXP}2S4%(NOFblh zH%}}Lw#O;mVv+4p)$)V;`rRk7_EJm}1@NM5k-o80&TN5ghYKwKHs5{3GFVn5cJ7r{ zV)YOrV=h}SXLli|7>C9V_PA@MNS<}_fpwPCIRYsqG} zJ%%GieLqAmR8U9rNQ)yyaMCO?pctXr`$O5ZCwBEJ_k8x%@$MtasS{S(7eZ83%yb%8 zV97)&QF=$0>gM{u;U)rsUyC-)qFn&)gAIC-WFSedZaU*9L>IfDlD>;w>aUdas#F)o zM=#GhSVQf8Qj>`)(xR#@6|$a^3r3#kaI48-%9TI;iac4_xx1xCZmowg^@DA$k+DX~ zePoP0c`gB-|9Be-Tm*^@QGNnw3qxi@cXnAj);~Nb!i@m7&V?$0W(8)fJw6>>u5bc< zi!yxe`Z9MT?vBqzml)Di^#AI|mHhomJ#qlu18r4H+=QBxW;y9m#rthR`7`V*scW+k zWqB{bn7yC=Bui->qqPE!NWNf)pLe<>5HJZYG{hRXju+IBW9xt|yWL_0$;V18ri?Rq zH3$x~FJuz@vW8^)zmA@m^`C7$8JhUP5!jwi=xC8ro>+XiY1EgqrNLjVR-#pUVF^5j zy_Z=RP{y6nH7`@tHVK2OYh1jx7Gn%)odV`$G{7~AknO3bsB}a!k!x-gsEB9aNQR zNe9JiPT56kVhR=f?&Y948mr?0dHP8_4!5~h(t$U410M4Q6Pb49^9CaNlTAonGPMNw z5e#_<-^>!3NXU|2SK;>*@_}Jr2M2 z_QQ~j!lqAoOUexUS5kn4OG;^3Qvh3p{6b4c4OFuw7G^B!XrV5CALl?(bc^h`4v}nX zln_>#&Jsis{2_UOqYh@CXKKzVb}#E2LKCu<>?_HW;|!%*ZETqN(!GUTi60yn;toFj z9nHUCPMnH30BvC4c$_wK(P@hcpUfm?XCJLn1x~J|qBX||CyB4K%&pA_M_RuER_vH?J-_5KHKieqdJE#@E!;IMj0ItoN{wa9XU3HI_B@`kJ85FLEz>~k zp5w_c8RqIAln2CfctfEIjjrR(s}zDkOh>rT{(3%p(QhhX(b=Vy^#7|Uvy%i-Q48yx zqYo?f5ZS=VyHov;PY2dVct0&C$w6~l3p+L2O<2K=(wk ztej}~t|i5dQUQ|wFt%=;KyIH|@}cEaIQkU{Ar*GfSj{k;Vy zjBZp|CD@(I+3~8^m|YhgI<-0U>=4eb%1haX@hxYd2vqD}D z;F~7f!A#;&E>aCsK}_@7qT-Z>m=6k6IoP7T;?a3qym51C;^^|qUGLc7l<%TDN)i+I zKVE}U(m`oT%bAuR?M0Q!_)Qa$qy(;1f<(j$n!L+M{D3IVEOz+xeo&y-)!scL`~FkD z&=H|G2`QunrY0CNh=NSNF?o>ZtuS<0XfuQL)jh<>J*%~1={Ng!(kR~;X(KSi7z39{ zQb&m9j~nvm{{z#xmEDFE)G+hWm)I$L7so|i=-(}Yr>6FQZZBoCTm6y-Awc+4Um}mI zeK%mFy$ofE9MIrNhGn=>2>r&CNG!O{>gIFgpUcz>e-4U^EjLvE-I)X-=Gwos{nkc1 zZpX3=&{g+B9OH`#opauAlzXq$$TuM4?nDfc>)mP7ZblBiTki$^VJD&cO{cHpW{;jW zRRiIP(w zTRem|SD#Tu;X*b*99k@7Yv#J@KwB!sjr)*-s)-WwI8LYpL@F>XUmWz8ofgK`@8YtKOhED0PaP|&L-O243bQsqgp8}o1@xF{cte{DM~lsYRx z2}q*aAljlUU=)~vYOJ_lGH(PUfxOd+yVg7Xo(I6paS8817FLwv()(&W)vhGsXST58 zQpFCz{hXenf`3mr&+@zpC+yWyTSL>)YpEJ+ZwNGxb@S;ErWwmHhMOe&Wptc_vS4-l zbBswTRhB{5LHl8ZlEH98-K{xUyBQ5aS%|@^rc+A&y&`C}gtmJ?D0VrF($ZJlRnDMt zarXIDyqiCk<|qwl_kvRpM6^xw4r&s^j5$@{BHSLqD?nvSknBb}!BROoa=-T%F=X&x z#P8dV?hm18se!2Q=6a+Za$~fr$8|XN=!^5J_jzyy#(gQ0t}dxaf($v~*g=eHIkHUJ zW)-?0J_B+p>|O9RGbQ2TVxgn4-yI>WRez5uKFA7T1gF&hWI{KW0I5GzemNzY94Aoz zzj*85Ud>+j$OZq+NYyNuKL1TP&@vP@`U+M7O3n^>15L`okt z7Qo=komIA4(#05Os6J^*prsVn(7>t3>kVk-*a*O*7`~s~gK+L9e?sBg6@B%XhIaE& z+3|Kly8N$M5_&Nwlf%7m4|MYAXI(tj&VrKCmBRsT%sImI02!jt)aa<=wmIHEscZu( zYbcoFGNLUFmDZI(O}U@%n@dUa>mFX}@;$?x%L5ldFj{I*izQkB_hUeUPF;cVXzL=Q z^rYmc*zcewqie|73&JLf`RveEzaO0I z1ehp7(k(*B^xO%}s2u-;yCmGWV_uL_IVv1^-6GfZwmh4`dT3;y5e*CRUY(pZ9?XYT zmYH)Pn&EeWL#AjOk%Eez$fg`Jz%R+=c+j*;eu@t~C|B_b_4XS&NFFV|o|;EzAOD#4 zyGts`!abtl2o=OsS?*aUR~ z5wlluQD~|ch(*b`-IK#XPefU2d^cy|Q>saC_&HqFC|U87NIAg|vk&pg2>w1eyssCK zqha=8TVS)1SlWdV5@>tTHCHMcE?BA!GH!ozdg*aa!1G1bh+e1=_w^ojPZ2ly+EDPI zPvw>5nWz7)?!OZa9`D6Z=6hg}q}NtZny~u>~OpoY(1Wj^ev`Y~1~Jz=nlr6B;Tr zfdcyJ7Yu(G72j-S5txXlT$_PrT;^z-5SimXw8~1PezJn&vb7G0F*9{C^i>N)986xu za$*^pE`8Yb!BN@hdTC`oMt1A)eR@%caOp`3OC7**hO5s@n4M+}>x=B%2Ra)gXmygh z2dZV~H2RH8S;M+(w(X4q&*gyZRyOp}<^#*f3)&xHSI{Wru=R>he9WXEM=`Y&OFPfl zA=4G=MD1rFw9N(??v66g91x3Fcl}+R=9HMmpAhCf_frk{axo|FQ^P{vf0s+hN{>-| zTMAW6yNf&AL975>_!>@_5UsJsI@HA{Yr%>RbuRDv66_1C00D7gAq^ODDmhhm%2uO? z=%RE3zUHBX$7M9}jCh7PIv~EvZJM^}G*>`}+FIg^ys&WkBkR03f(bZqNTuH@6h%JF zI&D)JFo<#E^T>+7gzuUC(-1P1(A#2B zp5{4kJ(j|KNyTD+<|p-sij=O@l0BXC6cfEPxbn2)@+Ex?n;+TMnbb>Nj5l|qE7+;_ z_`(_4-|?ud^K3QYGGk3n{KPuXh$Fj}ECbGUHe`aLhOYWUCNnz_A`!T>*bsh36KEpdsLNp}Ithg&z^cTh-K zc6Z7W3`{`&KZI*9Z^u-_yF>5|3a7B$jpbCx!+vi zGb;44Z=kE5R+s2F@k!Ygyv%`;a%H+C?|cxZOOj8fg^3P(&``-Hyy`OCAf(ar%JVx!nZD9acP(x@xndu|Mf-og=D=Lo>lA9P#TgoN z>ZsQdx*^j9;+n&FGc-nwB}XXn(B6|9*#f)wts|u6&KUVVd5UG$OUVRntDlh9qulU{ zA{{OGVraEDQyTkD#BB$v+@*2;3abxl6{jfd(2eJ=cDS7e4Y2OFZu_q5T12r7$g;o< zJcOC@m=+27QV!~x%vvr;8Z^&Az(kA&jmt%c8A+F#4uib+$w#Y@pj-y&0{rx*4t|z6 zoOma7$re^$XA1#Yo{}(?5l4s8jMBzI5xf%0^2^(5AMRFvg3F_)q)bzvf^J0iF)Jp4FL^6d1=2 zPjytRUk%t-jYP|{CW`x~1V(ycwM&9OH}r;FKB^l^UH>hU){V*b~#WTp;xR>cDe!z;1?K9>G)Eo!8hj z82oBab@vH^M*A67w350LgT;hA-2Xq7S zn#6WgF3kV{KNy(QFjxBNyLKdhik97^6h9mm_3M^EU8>b?Le{N_?oHZhkJ)F%Vh#jd3`8;i1>#y#EYIgi*{ zgpCr~{4;N>Yiy=fiRWpEj2V$3yNww;Y%Db*+=(#W2EzUNCbr`tsG9kfSjI-x|h3}&NQflINmLO$}G3# zwBK10y-V4Q^<_)pI#bAlP;E1tG4Hnc4h*R@O{rr{{Mg)JD(}I3G03HN`vH818|8*J zc>V^HhL_t~_)vqHw)H^!_m>|<&`kM?Nu>kiWOz#uA5UEY>P^*m9{8=Csz!<@_t09; z=XE108FUuL{vGnXkXej}%;8fo4Y;n#xF~TA!7!yzYU^Gf+JoJ>jlC7z9uXQOWWB<# zJpRoNQ|ng8B&%k~V^I5)saRg(kyv#(ul=zgiH(R7N`=?b()*2GME;oQz@bG{H}PV% z=jwkBE4;oY+n$F#aXfr`Y{5c~J{QtS2<@cdkNFABDVU(bR~hZA z>dnDQMvvk2N#diTfCxcZ zuLGziM9%VlTryT|qBST=Z)fm64y#NPc(atJ9%p$z$Xfi*IDkZe8lLGCKcj_0R#D&N zl;cpz$$9&~xwpWf5}xQPD9J0;Qb38qlRN??>_V?>rETddQSyxqa3UFkHB=Aaqx)&6 zBC>fbF)4P0oUKojpyWj#uD%%yj8jW`zmfwU4b%-Y+g;c{d#A$}z%jk`E+O_ua*hLC za`Fyxrf|w)Gml(iQbIuOmJ*MVQQUSi`&?8K_`;?U< zil9J0n)jQ+iayd*E^@$2ku2l3zG4#wSPECJ@Pu|egpl3nMOxsQu3n{At(vwSNcBzy zf?5XeecPXq4NHDn95v*F#*)b~;;>PCYR1JU0fdz;W4;Ne5A#QL7f<{5WAU);O+F@m zZiK{6gv)a}Ot^<1#$NI5oYh3tvp=4MkZhyt?d*}ouK=I$)YTUgcVCIS^MIdD42V_w3*$3Mbo`-%igMjvds2~Ky_qAc87_mm%-?D{ zAR6pUhJ@)Klirh6S0>kdSVb6tic0gSQ6IMum;t;_`<`{%?_Mt`UUFk8Q~lJUQ+(I1 zlW$wpHl&Ldand~3-T^4cfuT@};|*~S@AE!iZEbp+At@uiag+n+ZO@9mPN{j>i3@`r zr(Hxbfyq;CU4$NX>(-KFg`#NO?38?^Kz2a10y5f)p)9+dssId+1IHj*18mFt2s7xM zPEm@0%D&jBo+f?vMi%GIovv=646!KkSA|@B)qASVN~gfs87~Li@k{YvTP$L;wW=Hb zTaj|QUMe}Cg4ISJGO&Dj)>k4SA0!Ifq#{tAyX+eQuUCoLkard)a3>=u_%Bs zDNn~E<)QD%R-N?36*B;kY{opm;|MFc!?E!%*W6LBj1i$BfWjv3Aa4;;2{^u$FaeqM z(EJVS^;Os^GlP=JF~xDS25BecP4U1ugn|7(qF9`pTmEW3tkTT+mFx0~-o>kX;G$K< z;X!w>xcK2O)4wJ<-H|Lr7@eVWOSpoP3u80AWU$B97=%YG9M<8O6Ru)vEO&2K{7+|o z3TTIsx=!*Sa1HaZH8u60G|ov4Twy2xKJb_EdvGh#46Ler_df3}-tH46e3TkAE!VcO zh$C=TqcNWt*;D76?MQsje39}XRJ$P8|{D1gN1griR`!(!SLVyw(bZPe6=DPcL zQ$A=eQK7==@&_pk?Q@8qPt*@54{F8cVXUh*4C0YIoUL(U6c8Ok^LLtPW|T)26+qUF z>N%8`k(v58>+RLeimU1Emof6-ZluII%xYkKd+Nk%`nI)14SR=evP5Ck5%75f%Q#I2 zRj4wut~&QdIp_Pthi4Afo`SuX*k%RHs?DooMs)D#2H%D^R^0Nja{jr%!e%=y&;zhn z+a3z}#IB$_*fUJp1L9}+JS6^r1=wbl#mCy2nLG#7SY z@NZrVXH(qZ-QF(;OlmU=E`h*&sJEEBN^iXz2u3ATHHQzD9BRWtJ*I3i`S$gVhn#0- z#3ld>M1g?x#6RG*IP0FXa|Ajj%pEFwE$hStm^`^tghpHIyU05wVMTsi` z+tB%$B`pn@UKzE(Nya$lkWXGHNIsY_dGkV{5M7rMSa?)kW&Y)4ri1|+vg2+mG{ z?79=enI%UKXHFoGjbSsmhdoRrgmNSP({QB-^I|hmMCXIb!2ht9yjH_EAdVRIy0pvaV~~RPT(g#uA~`j@w0NK@^w6hX;mF7h$WjR zYF;#FY|(@3VBW6-yWfzQahX=Nwjc;c0#7Haus?(F5$dxQ_!(YR#ig7qoUq{<7I|jR zD|DK1s6IB|!1(|(K+M0C$bX2LDbbKSapZ}_5X-KXnxsqn?}HoiRQ*=RmF;QMAE*~- zi?j4)i{&fFX5_h4W4p~8z5(SxIG6!{3n}kW8FP9k^w9jezN1bJ6G<8YxeqjEF5Z(0 zCh8d^KOfM>*~;lcGJU>}fNHqPZb@74Q5n6@#RJi1Zx!i}@J@mQKae&gG*!X#Wvn4uAWq?Y=736*PHP#+B}`ULA+gE0_6KuVZjoCO=A6$V}2ZY!lkPj_rZ9 z{xqRJ1%(wjHDe54p~DQ5_uYii+NjDc@BS6ev|Nwu&jyXDBIPM+D$@xq5FM)E z#O0gEZCpDumS^yRe_QIA*K{(1g0duT0_8AIS>DS!Ub08t(+%qMt7+lb8-tI3{|0VF zf1TX@-jb;Z{+l&w9xgMe1mQe<4hkze2vnxpcps9T>uZ~ATY@z`yBUf`n)*V0K)o|Z z3P{hSpDbsM3ZorZ?Z;TC#2(`;YIR_++F3xxG#wR{(FqDpYdab1Mbe#gsZK-G*N_{$ zC5YdX1D!ZL2T2$b8%qy9&q&2)bP0`gYNm1E0Zs0_S3V;#dB5D48O z76r$YbZ{_qDSH?(3MN~W(js$T+E~~-M#)wEEi~=y``s125`%z6h4Jo6Z-~OU_qWy$)ZYn=TnziuG6=OWi=v{z)|Ouq&bOE_XKY#jG*vdx9$Y+ z*tn%D^twjx$M5Q~+5W{=A>T=r#J=4g}crSHP^IdGQEID1xKkqiJ$Hfu>yW3 zQ`=jcF@a>gP<_kk(ptWM8jq~JutO5z+QVvAnDqh#@WOlAnA2;i&}kJ*Ty6~C!qLgZ zbTZVG1&vL3#lqs!kRD?_-PWRVwtKF3ww<0J$8CD*4WTgeb-iRMfgs0MN6CWh!8*S4 zLXIF~rKJCb>NMmb!V!tWs+R7*@OD+NTJ5r#j{19VU0b=d!=(6~1n5@>(?0R9Ew4B9+m2#cy!V}X!Sp$t4s2RfL zRtPQULXipQpRg*m0ts~Qv}lOsLfDgpC}7N<3Gvz2atQs_+$5*u`)-Cv?_65Mm8sY7 zM1H5Vt4*e~`RE~qzmKi|_<0dG>@^!s(x}ZsTk!OP0|qU`;6Y!0b1p0vvy<7!tt8cT zv4Vhi9wTW6(8b^F_#DZxP2bxOqbvvg4dkiL^Zb!H(Q4 zd)z})%4a;t2k>oJ2kaPp#Q$C}r4cd!C zpH-@ShOhWxQ!h8pOPDi8JQ#p-xwYUiX*HS>zR+gw3NElP&WCP8S)6h7=8@I(d81JW zuI@p{jF;H=Z1f(O<&>51L@Dw3!TM!Oz-j|qNLcHbMRyoMD=-d4$>tlGjrJV-DTLFQe#k#8T*QX2d&E+MxkV6F)njFC{ ztsf|kLyg(zN!+$tn=xOo``o?Hd5p8{A8s<>vIq^u@UbR zVdsxT5B8Z~QTZzr0;o|bHJ#F^+&7a(oTap^5Z2dII-{fQ7sSqjAXnc$RVbLUd3h=? zpxUARDiuvD{w;Zgsd(KGU>ueji|TYVZbl&-+YZL(ibp}$3$9Aft{t7+P*L^TVa8=a zVe1Pey0+tsMU!U1cbz{QEh$&_tK+@^=sZH*t44o>dpW@8lG^Rxq^%ioQFkfKr9hV@ zi{pBTIIIl5CgFqsDeonOo`u<%l91bG!(gOp&vGx#@N_y;=sQX>vR{H|#^|bo>nb;E zK=h8b0bRc1!LuR3|4sk8!|7Cpi(xAox5$R;uGufW^MhWpvh*R)z!~^+Bno0WpfW#t z1LI#DYJHq&}h7d07eP+EE=b;-Ctq1~AR2Mpd^3M|9J=nCnL>5_T?jy6nHJ3rZ zv`&q&Xtst+UR-i;+t|}6<^2ec^`)TfDWS2I#5{q@GReT&;`T`Wis0a68E=ku0uk6U zKNN!;;qPhyLn)A$cT56Bloyojgklzi=vm79vk#tTwZ&Lng>r=)5CMA>ZA9{G6^sq2 zYuYX6$JkVEy!%STr9p7>srN>sL?WZ3`eb|ipP;$-V=&h+nG07cM*|-Xw-`AAFTvo! z23hJA&CXlHYW?!c@OKAJiUp!aT`Qg^y3%upCSe#^0Pi9iy{1t~t~93{{@yAFP)UT? z?@T6bASX=Zbt3KsdrOL;%XxdH?WT{Mo0>j=8W zAB~d4PvRTrN(BHnqI17xPLoxoU*F@XY{El(XgX+Vm@0bK78*Z=Rr7@-$|<5TtUlyI zd%B2=uQM$)nqjq2G%G{sR2q>=SlU1Jf0}j{xrrmW!pb zrKikuPuH_u&z65A&@XrL^?(2UQgfrV*l$FHspR7)UdPm=PW&u!-sz330(H~M8x^Fs*a zHIRi?fQi|2e%28?NgS(5%KO=KVKG+ww|-2?1LBs&8tQH%or)m7Z}#1)c9yqAfZELB z08QGt)?eH)pp0Y}u(bUMdYO~bl-jMrHfcRl&n%iDOT08`)kZ%Wo{KKyy9sP&_gk$k z!@U?-z7w>UdcJv`b&M_S!Gi5S$8%-a_)2HQ$-LiI-LSA_9g=DA^;OHCh644th4{{U zHsq5pnUW4PK)V#7LtY^w;6ssW0Kp93mExT`gGnx_B=}2Bh z!Sa9baF1?tVKOc1h-BUC37tAg#FaY$n|TWoes{^@p{I^RmPV$a^&sZM(bH2qjIf zNGoPuOam;&t>WFVsa+F<_?oA_NlsuqeBGwlL%j%o{C*KM-#+E@i;+TT`oeZ5Xh^-x zN;D)2jasv!?jFnGnG0yMozl~Mc55(!J#pmoD}PXUI7Alg!A%-9w~LCZy2K_2q zi_z`(XUx*u)CMl;{N~UcLcMSXck82xr**hrBaMRC!thG#A@K+?2ySRixOLXEN!fn= zd%Dtjz_ZI3Ii{%LF=Z@#x3TAoR-hKHJFOdn7r2M!gI#3bu-2aHpT&U<%3r)pske&3 zxGMY*`jn$IrdCA076`k-g%IcbR9%_wyBEYf08*P;zm3As*O)s`BLRJV6|)=$%rA`p z$k!_G7%`Hana~Oe$`Hf(<}WZi*s)8qrU20>HQ5W`azxuYJBWWUquF4y&=kA&BJg%_A^14#Qo zs4TyJ5`d+Jq2Wu|UI~k&Aij$)c-!s;!%$)<%b>ErGWB$L$xmlJP8;K%t!NO5Y`$hA(BOltM6F@V8x)UCnw z|IhB!GDPO}M2FE*F%lo8p_QCqx3U{K#V|CP1L!HPOmYv9Lb=;750%rWXcDN5Vxf2* zVQv(oU%!-Vsz77wNhg{&`7Br|+~lsy3POZV&3}N3@lnv#WAgrbkC&O58{VGLK;C4a z5dY16H))2MtSY6Cmx#OnE^D(7IK&(qv3WG)xWhks!5UZrLS!j$SO#WxQ7Z_-C;3B{ z>kra~pJQKXBl=MXVvw`AfB76 z5DQBs+Wqya21?Iv^AL3>Sr}Ztb-UFd_|& zu#91()SVKy0U56V6~)~p6F(ebs@>VAuVxCg$f0uHob1M9LZf{N?_*gDy$ZKGZDRnm zq+qeQqFES$4u&oZxTAt;d{}aB(R?QB;HphgV*t(a1n!K4Fr*YU5D6nMVd;#uDbwR= zjUz{=#z3nZ_dQ0v^2F_wG8VBA&006_SHnxK%hU8V8%d*Vq!jqbUy^D zl<1nV5>-r>!9TZ*0bB>6?e!x^egS(zAJPUr>gV2)+2dyY$SzO;hP|ku?dB z1hZ1>%{UZMdS=6Z<=$Ierg8bH>MR`M<(#GhPP?yg`ow25>czfmAnKzQdv9s1UHZ+pyqwNTca>j94JWWsRt3$ERKC=5A+B#Yt2hK z?!k1FIzKy;IMonqwPJGZ-R99X)Ps84g}||9Dw*oP=+LttY}@RkPcN z!T{euov~kUx_nX1Wm57t^cE!bgX2F&hi`?Vn%g2$-VJ(X#C*= zheQHBGXL+B7N1a;CU&J(U0TU1DJ#^nlIbEup<(IxH9O1@QBb0{^K{8}#0j#6G%QeX zphKo)t5g6qD#S1WuNwbZOD1H2mS0dN5Qkhtt(AW{QAP4ll_vPCcFI_1!6zYrjsdSp z>{Y4dvS?@Tgzii^2?%;lDVi1ZgVj+>(W{5r@*~UQOpUPZ1!xK@YkPj?SNIHPcOyMl zlTolLOe=C+lG~Zqd#r4xW7?_>XBC<4jsJCsdxb*e${A#J8D=HvLxJ4;yM?1>D55Y0 z&mi1aY-(svSu{&6{AJ*eced4R7p$7@hM8aMUEBE`{|U@6M2AA7?Q#aTIoqd@W31ai z8Vr34$HQ|hhoHY6SrwI$dydKPh)?4kW6%EW6Q9@cuZ{zY#y*V(-X8LI$dGVqdTaIg zc}vMAIVpdw?3s3gWeJr^8-KYAvTB#aFk{PBq2K*=i6ROkZ~ki=|4c}ab!P3{2@TIs zdWQobjh2NV>(y0}%^QeVAZ$2t^>%aHz_QY8L)w`!A(fx>A3PAvt#KXR<1l5Gy$kgj z7+3Z0Z3)MX%$3c~0kLvcvyO}xXo%AtN39<+BfP@nd}Ty;Tzd>DrhW(0ZWa2_i>Z*Z z{Vyv=4><=oNh)J-L<8AXX*@t>_mm6oT<_g(w@Bkn|dg z71l*?3o~#KVBZdo7Ub}Q3Dx^ms_&Te?2=I*4Iz~!^TR~Ke>gV0tP@ISgET193*!jf zJCf$?Sv{%ZyZ(i{mYg^C9;nY*fDmNF6?;J-KILzbPSW$rZy_aG2E)r>1>^;0Ydn=@ z8_IxY!teh-$~6-6XYE@||3TixwG7C5G4&S7RG=P>`OPCczWRQ`&$}nknmXmAsFL*Y zBWq~^2B|1Y2ao;S&536gNU}K_+YQ>dO!(0CFG{Fbzr=JAUfU21We|o!csSadk%}Ww z;u0CBsK>N1Or)0lmIb~3!&SawA-lP~K`>Jml zDVeT{GB(cY>Ey-wvr@1Pek7tei6i?Sm%i~&T%QnX8;53GLYodNVeheJj9v~tu;@IS z<@nYhKyWClnrFz{PCz)Nf)fv+%SwBk1i4J*AvoN=1^`hXL7!&c!Pn66rp$3;col`Kb1CAxE;8=#(xe!g(&DPEdrwiEg}& zDjG)S)^e;HBr!^v)#{TD&Gh9k;%s(xAkx$><%HDlEMw_K2lwTXYzeCQS(|nQ`pp&W zso#>85aMs0q@M7N$EwD%j(u2aGd18aD`5j-F=dT!HJN0|BDEPW>I3l9`9_1I?PCo19vs8*D?pK4sE+Le9c<>X z`idlxzf%gcM0Y;6>Jr%`ir^h2iwfqpDT$(_>@?lRitH9_;ClCDW9i@gAjk$R#88@Y zhz@ZWT6mKA&TCX2B#)RbeB$hr7}~UYpg{Y0yq>`rHDu)PT69iBIg&TgEdaJI{>NUpmh5#NtBXN#w5S-0Uu4IAzUJj&q zAAOeSB&UxQJyeoewa!1C4$3rHb{0A_`^!BPCOfU$JY>UR0<3yT!SZT$#8GT&dS^Ur zlej+chX_$MKoiByV+mI%fBc~b;I-hP0FN{bU2Czrq(5AE2f$yR_=2`{E2`wX2v!0l^lj@LQ{1A1yw? zxmA$Bt;$fTi&2Rd(sEFzHnIe=ZUbg%6m;+sd&}vx&2aI$sqGNCd}Bh0@#0nh03}db z@1|W@5bb)rJ=|>6eY1EtUqEQap)^27R7H?Cv=S*!-KTO6ly*<%*M~GUY}Fx1==|Cy zg`F<1DvhXjXjW-CCjgVuGFR#N+${m!R8M$!oh+)kBYs@hq<|+5W0A8T>yMue^8t>k zG)+RfaB7I#2BFhDgEaR(eBDkauE4Si=y`Wy&icoa@^eHh3on>k#<=Xd zeDhv^5q7yKY4`KX7ymRBv0IqJ2$gvp%HIe!WX`s7!(D;4$eXqe&rV)Ra3Mn-F-u#5Jq_9wqU~0ZBz^s!Ez0c* zFsd`E-XJ7sKAC{6DdCR)8ONmT%4Sr)+6p2a(gA7OglQO_ori+E2(Z`FdMxtkaNa|bRgVJkGQ87094-+XJf%9<;8l}-0Qea}{-E8z3P&pq^- zlkrSRYWeJ086~U+!KeYLQNa;w^|H&858h0d6Q@8<$S__H+Yug*pU_<8%Y4^jlHpL* zc3QR~XGo*TfWEECUu)AyY}d?axUAkFpbw1LXieL%=N(b$WG>b14g$Ww76l3BUio97 z6i3JOZEC7;(N9Bh=VvUsqA_f(i@LLUvwLN^I$FWlJRB{=#vOq>JhT>*Rk1IWr!Few z4AIsO6OM+06nd0Al)}6XMo$^&eIk>L>uXj^x?r8113(&2q?aP#7ouK=0<=ALbcE^q zDeAkqu712RWyn*(Aro(;Z&U|9ixQhW^NnpmvITN|ntN0lgcKE^5vC&TLri?oGsW3x zP9`(H4WO-wm2=M7&G7q$%!F~$KXvgtwJvoA@mld=>N~i1swX9;a)XGb>D5b!jo@SN@*#5#ONN8I9n-y1k=0Xayhz7`chpS!}-q9kO>)*k47_oT#J(OQ;0p zT*%^nfLNDQ^bKd*Lv@s6Nzz~lG3=7A{yzY$wUt*}JLaW>i&>(@UbAv=vi2!EX2ieAS17ZMA~#Im+LiDp%{Q~jqnO7NDY2xP8yE? zi@%HIDnO=?`f8Xyq3xA1Rs&S!=>{)Il+L zk0%rL2eJTW`;4+2U)Ib)g}N7i)K3x@Sj#PcBcWoXYNnqqQ%cH&mAh=!4pf4Fg?Df;-CP0Y@^?G0D<6^1dHs>$lrWL$}7=`tY2Fx-_p(}a;gaS z;7Sy!*r{pNC9dhBr7#@qGTsBG-D9WKXcLWU+n=*FwX_jtgsNsxvwq6uojQza*-^M5^(9wHy;YG{wvV)z@ z|MxDF8iR4*GEi#EJzGX|v)wWXRsM-pt5P%96I^z@>h5U|^k3u>e^XN@a8)EE3lumY z6Y4g4b8ayOj@_2R1s!&+^D+Vsc&T&@XUZ=dK`=DR7hHW{m0ixDR_|7?YHsDAmH-DQPS^I{7 zFa#o@xc##16i|iDfaJ{XYAi=pd59>Gsrldv8OLxiqd7-GQ{v!rBjqG4|jjW)*-e2a2fFplRvS}LW`tsIeR`Bs;7?d{`w{v$2$G^TwGfWen zCxBrTDi)H`@!v12cAp@H3GQw#D&x{gmD-uu(#+3L&y+DACdP}*AImN~#RON-9sewc8K_#J z>>C!$`?dFyPE?-?tgM_CQ+yBatCymJ&+#IK)~rI0(f zp^#AI%2II{*A*t-1aqvu^HBj|5D8kP6Pr~)VQ z!H##L)Y`;T06oN*D1U9BQj+fb`!7XNU%jByV~(^MQ5(gxYv~Ul=nNh}ZzMt^d?RU^ zV?UD2u0SyNo9EAK1lKynD+}(>p+4AyC`)BXb@BKr`HgR0!0g|sge8=1jY1S;LP{et z&6(of+paID{l8EQqn9htTgI5>hHhd@|BZ}Rh8-}H=4w;i9huW7S&Blsm8Rk*^tWt=ubaW`vxFu#tjDm&tJRVFSdTuoI zqPeONYK*kUM-j~C4D|iZ5CXycl%s3w&E3#T&)~-$ zquD5Y!CgjHB>Pty+(djG&`ail`nf>N=yoVY>9Usx2y3oAO{~S|&^6r$!QxDc1``W# zJu9P(gE}Z?8tzw?)D@zlcuC}+R7xYg1xuLezwIFt^@*m-66*saG;T-hskx}B%k3jc zYT9q|009%)S%PM{jexc6IsXx9Gy~(;*AyfXJCh&HM`QSwR_$Zv^yHwVf%%eIQ*Nj6 z=nd+-w2^BzboVyQ&T5a~bDjZy3U&_*dszC8It`2Q7#2P)e?nah=hT#R#lYfBudpLH zA`5#ps^oM>a>vBWUggDa?$;$wL^0I?n~`{EaNzcIK^Ns{CUqB|*C8$dEA_^%)Hi(V z{~6qCer3rsQYG}K&r3U_~lmNGx_;YCfej1R99%|%e$1m=4{FGr8>0#r#w6C zZ#`gRGzB{x4o2CG_zZ2E>LdsseffiwaK#5E?ivi9@dl)4^fF^#kdl4%v-|^BbuhXl zp*et3cv=nKESpYSfNTS6J6l{GE$(rfOuT3b2Pf%Q@UR4I9vF(QgJDF8(nAV&r@!$> ztFR;T+14K)Hq3ztm&0nb&AI8&Ps$BGjZxt4!qVE*vCc))s(-TH75jLs6AGGWV95n) zl$K6YaYIaP`lPEw4W7zodQL04wu<>Z^9X|eJbS4xNRC8irpNuErGB1G)p257DG;$4xq8XYxVvh`tLR&mC3wI-g7 z(o@JOE43u{X$?}^-roC^)_<5I&8FGXy)IiN!Jxe3IYBxj3F`Q;u8rl-3Fj4|XOWmy z=gW<$WSoKxPaQ)zQ~2e_&WfUDI$b*0`#x&8J{@zt`&6rGL%^1i<*l1BhH5D@^GpjQ zCV^DakTfiMEK&UEYiE1*{vmOWpdhb$bSy^l_Gybl zTanD_Ui|zp032m~0WRRwXLN4MVmAhK?NR%IVAC*U&%kPi%?N>Me;v0X=f2rf`G+(= zN%8Tg72A0sTjNCK(o=v(V=hwn>kv$!vlxMpDEN{J+p!(}10RTe$l(x57GC3Yj>G9w zG}Lde7hL!ICi{PC;kaDr?&1DuorjN{Bcs&em#U7OM~~Kou1Uzn(8wvJp0T;4vI2nC za{*_f%!`}1y)m{ZpD!yR>L1bs!FEA{W5>4Rk*uZFnVoLJ>4C^AWG{jRSj|yZoq;sA z9r}DWBU4a4<5`pALMdH#Mhoju%;z^zIz@_*L`bJ}KN5sWi9%I+hk~3;0QE2Xaa4Jy zm&0wH@CA3Q-F&xK6H^G?4EIDfx#9G}QC%gn9#XK+E$>>!P;O{RI4gVp*&)&mwx-wt zpWN7tXwL%lWoz#74L^fnCYwH$zPzbClPdp0KUMA1cm7s=kRhADsms=&a}sus;~ujg zJ*_fGVfD!N;?RVxbHdI2_K;Xkpc)37e@oKz*?M=YQjyk*tcVX&n|WmMOT0RmO=(;; z_0eZ%hd>^eJBav-oa+cJ28MwNEte-PIalB^S`&y{HiWiE*32pxNfi_w!K6duUUoxf zdN@Fr^hYfB-CZ#4#Aw5Eu!)2V;bAOjDR&bPnOmBQ{B4(_A3PcQWg!hQy&f1yM{bCX zv3o72ThaGo)|eomem{4}Kiq{o0Tj zRx!t4Jmytm=lKV|hXMoseQ%u1knTlOdDwCRR!-&jTfay3U_fPcuUv5Xw5FZVmP8*m zi(irWh{>sLJ0gg3gRT-9)m4?#I3l>>{dPH z92-gt{L)M{J6aQ^4{m5xsN&aMg8=8-d3}^(6PFnd+UUulldmj63#(G1NgfC6xWUDE zzuK7v1Yah+yhFQ^r~Zw=`ZL8_0EDVz^xd-|$LS-H-UN9zX70}F|0&O29E_XZRNRfL z%4nxW$cmdUuhPtx-$zX`8A0e&opAd9Zb|(v}OCNpf|{+m-Ky zNsVtVsZw*QDn)Dxd1oTu1bANfd56sUuFCD!?0ce9uzHjtr!&I#KD!Sx`DZZV_JcD8 zx5-le9HZ`U)IRHs*^dwW$9cvWV}&cQ6ApQRvk|;!y!O6Oal@=zQp9Rx$wjP=>+lvn_8=pBVmEnOr$_`>qNIscT! z{&k_jg+MrMfE$1YXkgngNfcX>&{V!eYSm}VNIUa)XEWz;S5N)7M7qA%VMF~8J>?4f zZo?uHDUIZpX2|6UYBS;IsmPz14W&j}cQeLj(naL~_5E}D(-XQAbZ2Y~GkEmPQ$Ry+ zf#l2F)nl>fCJ&T)bMA;ZR)q-u9Rv!Z0z3x%l13J95o{6 zrJ`{GEgD2LaGs^`>D@%$#h%=L2}*!}K&pL`s>Jf4+o^zVFTl-D*xN)c=Z4I1AV)peRDWzLn+gP8&-uFXfLK!`QAB-Ww?on!#ZzW zmqF~0-vo+TFNcOWPMAwJKG-Kt?H1EkK+0qBX-e-qs-Vi1PX;3TicDcE zbswV}A_R5S$phi3l6U9wBt_OGOf=zlez<+V?QC#aAixHf(0R*Kq)zonTYgei$bQvD z+!8#Y#`X~cMt978hnvncvG{nhp+Bc7|R17Nd2T zA6^PxMe%c+OONKsJ$a~sZ-&UKVwa5CH|S#5T_5&^cw#y55Ac2`=N1*X8b6vo=uzv! zJ;6go5zwCvk0sR2b;|8fx-GT_W%99!V;gllPy1T%=Osec_!2oxr4L<5e#HAsJ0RR2q=I? zF`=jz(tL0Bw!=fgYq4BEN5!-4kf;6A#(*PEW?=0gHkNk}PeoQeU_w0s(x6D>psEc_ z8PB%UR(*fy>jQC~>wH#+`cP$RN z?-=LS4g3JWw}^!%g^JOIG#-?P#s(9mCRSofFEG;yNyHL@%vR=pB~9R=H~jYZy`yyR zSQP?LODy*?Id0u<48pP)XKxG@?zlNzCQ;-;m zk&Bxt^N-;5nUA2Fir4y>VAj8{Yc~SRv}vf&-b&9$-o=IduOY_coyUhy`Zj&V-tqw= z2rD7!PO#CUcTy1LrjS6BsB_!E85cs9 z%rM6(8&T=35|X>`O{;FMe(!kQ}L>WK9l(hIKGp=rb{j(1N+YNUce?EtcLeft} zs_pzom7Ln|?7zM6`HiJ&#s^Lza)}=6xx92uj9#JzC+AWJRit zMkhUI3ul^6FnP=h$JdnUdGD-j2j~!BoaW7)V=51?I+ZLyLh{Qow+`fH?L0V$J;H|+ z)@AJ`gAWtF5-3is#L{B@dYcRwX<|bms2sHj ztD|V<&?;w@BM#%jIbBCA?lBbW>%@auVNW_4yDMcfJwz~XJ!9Gn<4zJz{bxd)K{pO` zgEBkPiG?X-bX05=r3Dy~@tXH84LuWos0~o2$0i8sXou_#N)x3p9cOdS$^NSYzy78! z!^)xMO?&};$?4eP-|E%SE-(&gZA)Vi>(dD<=d8F`Qu7r{@MA)A5C=t*B{xY765J~y z8~dTIf%89`98P4T)Y&MC&rNT?&pPM8`uZjC;6ozN=?nq9Ge^u~MBKDWh6iDmY@~4v zFdzAOY(kqM$0s}cueq9H%NB`hGB%sd7(sXevO(o6Z&P$@SY-1x#O0yX7mU7OdR-2v#PcXESAtrB;(7r{`3N8$^lw!JCweAIP%az3juEr$Gsa^(3k%MMP2rxTWk+Et)Q58gb_-zP zGLUP*jN11Gl}xNHQB?#s<#y(Hb#!(N_@U?|4qZtEp_5uZ-K!lDb^k91F@nLjdg6ih z!An3MbCHfH@G}IX;l=gjzq)%uyI>waFOw>Oq~kK1RICzYVSe&wjqRTnzZ@G!B)t-= zU-AHuxkN zO&Tdi7#<_Asm{PSM&Q`LU9oEQMb@UkUwEPTSyZXJW|poo@$UMxx7!z?Wh)>g)voUt zg|UaUWV%cG3qP@kRMO@RK~zhH!!1gp95E0EgU-W=x;2!jzapU|CvI>Z(M1G5w7rsr zTZM~f?K2J#fEX-r4Pj>|gN1Vc2(7lPpav>`*_YbG?LsVUwwjp62QFadMFx;Xrz?}x5E9L3i4fF;sL1{Jkk%efaQeK%JV_JCPyzsMgxU@qX{~zHv<);Ju z)2$JIdblLK;i=Lz;HKR-)R~#u@r1&6alvdn8zDqdTU*FIAgxS|;Ktl*A9NYWcq`x3 z3@boLdn!okNS+U@v<9M4bePa@4B!RfCfWf-;s%~<^#|)}*}Tj{NkI?MYYt=X@!BjI zJKDYJMXtpPlSyY-N)tVbN)IOPR(%SR-!JVpJIf_=&_MmH^ZWUa{@EUa?=HQqzH-ZB z>om?=`GmyjwVw#>r>Xs}ICnsTMoi$B&6sfC?N?_0?UcjNR8>I(Lwvf}SGoINuS-)X z0*u4Q9_^Us)npLu2M-?I&rw1OuroIe8Ek#cSJ9iN*inJ)uZNihy02ah_2ey=pXCz{ zoH~HMctq%O*Va)@Sb0}!!vre{EkXCc&*aMzK~sPsPKGX@!B|7!&&ZT@zLvR#%%5BG zTl&LnRTIzii!4 z(;u4jt4R7ssZQ_N(RlXSSBg1Bahobw77O|HI+%t(NA%t;^eMHsYlbE8dlE~!;JG>w z+&xxL)!_CWxHeV)1+WO@q0F8*$FC$w+UT0FtaYi|bTO4jl>IAkptRL$>@zkJH!|0a z2<-B`Ua_@g?O4c;$9-$f%yBlO&zztQV+K3vPIEgDos|)Q=t{VeY#E{JzJd86(=#_b zx9Ol^JjKwv$8hbxE^1jESGYnQGe<3UH<7jZZclCI%Xjs%RDiSA?xfNwiHeKcCwh)7pGkBkaVE3KA z>IXNBu_te7Z6gg~(vbqY21f_Kq-?m7MvS&JBnxth8k+iA&Q(&@l5ZIkcu(4;g-!z}xEWv|B;!eYhYHHW za)n{TYrB*PqS*zRT%lH0r^%S%H|0u@4O{j2erpsTTu&bdTa)ci{wZ#+Wt1=?xz|T( zDTN}Ko;FzO^R@G)smE-a_aiLQktsX&#iq5Mvi5&p{_IBc)YT9aTxY75Uxi}_0kRo3 zMu!-vhQV34fz*$J(S173V#p*f0U{FUBUR_zB>sFn$#Byt`RU2@JH8vA)Z8rbiWY3x zf*&;?y(BLdY^Vcyi+BHV+$>hgrd=Uu(^{hddmuefCA1OJHulAe;c!6=C25y5fQh5% zkYL>e&&C~M%YOnF`+=>&2!|siG3j!NH%c=#x3q=$3zBFp zSdnV<`m8gDtCY?aUqQF5tyQWZ7ruo_UzYwlBOVdf}x$rM{6k z5{sx=QT&?HQJ9h)V+9e!z7XIs?i*wrELJ#6(?5^wRkm?9D!Xpf3n1VKjA56Q zmLB6}pDV4-m?3yeC;CzH7eF8yM87zZi)23~xBZ}EIe{}8l)^z2t<76BuM@vtLaMC^ zrdkd%SxNqr|Io{X=)8v_9j*ALvxkK?|`9R=mHvxTD7m&i^bJ zgv@$*wA;4Dd};DPQ+HMDsxOM2Jfp2nve;E6yA(zv9K*n6KB-^N_@daxgD&xX!bM4E zW1)Bx--XeRfSw-pFKxCe7%;~3zvFy`i4{s%oZfX;jDLo1#=@mSq0(BUV{OVBwX|-^lDZoeLCxHy;gVE}m8=6j5yhAj5uTcmAhV?TprW z(FP=U%P1#TieV@4gPh&WF!9roaE0Mv>VkgC86MN zxY_aD(nj?1U7>T}k2fzaADrUvUp0bO$+&wPsF=>+flb{vwMT+fF%q^s|L=_E@73}m zDho?c2zxWMDD|`ySx2U1E6e6c^;$!`n=pD%OO;6LC$xn0uY6bbeSm+7n4it;i4$mWsvi%17OTWEWEzqH;b($3n-W<4b7GdN4I29OG6Rp{8f`qep?> zSe6HJ@G@9%_u5okh3JM|lTfm*fA58B#ss3XaS`I{7RCrwWWj{%qai48Ihy$?Fh z^-B`7o2slo=1x=(``_xgpFd|!us+Kg^c_`W%nQ;fe}|myHbT`2F^#AN*EcY#ttq+g zo!rh0G*K7T0EC)Y++~#fprjpQwoaQjH-m_Cq|GbPO$Z(c6LUM$#?lJs>5B!Waobpz zEF?oNV5~B|B0-5H1g$5Dkv>^P3;l*9K=A_9<(I`Ezd*M4H-pe+cYc{2ORBU$(Bg_! zDDM#M4=x}6BOL--Sd?^=(OO5Q0De`A2doXq1Qt@~8)f@lf1POjtJnB7`yDsaqce)% zw1OX+IWwdZJs|1%Ljy`rYSBApv;V_8`zx1Gr>v6ZzaB#}_NkbD-{9;IQs0NSf$t1eSm}P0&o!dIybeQOI2M#oIy(~hU3z>ex z=HRdX~^r;)=3Tej?>f;+8RWf)&DL=LAh223wDkrWY1@|uT# zm7c9_9WJQzRG3OMl)=&BlIf9S3=2I8oObJTPD181jF7|fD|ccs#K7-aa!G^B?=6Qy zx7q53?jd0$=aD`IMEkwbR`<2$`4+Z@8kQ_{hVwxy%VlBnnE z&=v+h*>Kd({$MTfBuJN}MUOQoyN?Yy6&1-fSTf;vILy4#dWX%N@O#p4|2=G&=Hk)4 zG<2~>$jvwbpavEpUMM11Pgf`|$C$FE z`76pc-_35$yn68j7^Z%2HI!xVp1!yJX#gEg@NTN=8{9Bk_aZ>K<8eAGF?~YR=uwGJ zvAF&r_2(UAEm@;#eWA8*&pO-Lj8II+f|j>3JEv=4_dT*jSCGDRJQ)&1;DwmBG@fD7 zfy$p9iqXUVW_gMc*X6T0dJYRtxV^`ei+AWgPq>mRZTTQ4Ql3`lnEr>}Rk_ zUEdLVib{qadTSTE@RF28vhl6V_JZA1Qvhp#V=IxcPRvZZ@n(z%vYa7oxs9-*Fw<3@ zx%ZR7#l@!sJFr&E!9J7+|C4iNaLIaMGuAgzQK7H`4w>(nK$qD550Y;d)K3}}IMe0l z0?)s%c5wN8N(Dzq#$7Gr`-JYme>R}LSsBam62o{n}bUSHuO z6uY!SGC2p@y}s@?@8dA76Bga!*;b|eP#TN+o)GLvHfluSUyC?d3pI<_+$7?5siPU! z{0UPbD1e!O1LvR9ak4>+orw`lu&fv5O=B(Y9i#z5CTe(1NR(^QuIQCvz3KAGYjN@4OYjFfwS_QVT8&de_O}%u|C@3^2@LTqgU&N zX`ZGOvgv0*Z~hT8`Kc*ffXV-06zUgsfTuB@`Sxg5)eNq(0|-Cxy6RaXn&#>tMNWmu zvrzChtq14KEfi@!k!LI4l0Hu!$VeR`JsMvBU#3by97JfF3&{4b-SF&=e_+N~BrY8-ZG>u`4p>y`6@Ao zU6ZO01}2m0G1y^6Gnoie0!%Jb4X`3O40I!)a#_kw&@mc~CDj*u-~Ri{*pD0kdv%P4 z53oGQ-59W)$CouQdh(EuNfE=p2sik=ae8aJ4-Pes_TJLWytvi4GhG7Sz8C1QM*}oQ0?R+BHb?UO-IQxOkxJwz&F$F;8S9y4wK8V?gkD@%+c<1`%k4Ehb0z%j!$fWYYFLfjt*d=J70Po!o!qK z=etx=uzPx9K3yQWu@L#AAJKh``f=*=-s7)Sj|%A`DeIJQfB~)XnYpvbs%84jc`5JZ;J8RqManqd7JRX*H+pEePw{m)odQ zNR{pQdna~6923PDe({Pvd-Zl%5g|w}s-D1nBO|KNHF2M?tgLrgxbx{Cwi7rj!K{g& z!m1@W$tOLo3~G|vdVkdbTrt+-$H^TeAyboAQT3&U3oyInY&EJ^6B zLYnQe_{%797-`N8FgjP$*<<-20>B@}o6Pg_WY#~@et+P1No=8C)n->$#=2wXCuhhh zK_akri($Ka&!^^G1#W>J7{P}@@Bf{>TI2+K&Xh==76NQKnS*t;aeHk6(p zmlM%bC&sYr`#nqI7tp@@`PV7-id%i7(JEE%4;~2px^~6apst7K2HA48vO(Gds)4KEz)Ej`6+{||CJP_70Lu7{*4YKaGIw*bd0`sC(($$spmhOM0%5JTE z_;XL(qyu#q_UIvKj?~2BfRu$@a5xZuei|Kf&npf(Ks1xysJCl=1fY)L)hq7&Ca-H@ zeocl7^st{sL_eM6?7v%uRu11jdZ|Urs*d%tr%eG@7v$P0P$VNWm}cSeeeXo|bK4OU zX|wxZ8v|bKjSaxmpbpbLW@tvVhV4DK6?ZFZk}^C}+w#ZpAFT*2q^_5`-B`FCrk|bn zO4!lPX9gJMD6@etuhe|C$c1ALyqEAqZE=0a-sAn?1gG`36s{BUSmcclHr(X}3?+R` zZ`H)g8F-^F`cyZ0Hl4s$MFM--oDnWH0`766fOgkO?M_GzMeEPI>Ms=8294vCd`V!I zP9`4x&c3`S?|0eDKtKaUUFZ!^VvZHT7i*djguuB)aLegRs22g_MUs>9<=#O%~u18b{WYqVk=Ps ze@lsz4)ar&UH-Q^@*~o+7B~ZJ^i$tcgV+<Q$5{37s=whYKqAbS@dxZjc%lz6qD;AxsVZU0FqvD971}@T z_7#x{q3uzG#KmZZShR#?+CQpp9W}FOcmL8Zu6lv(0gV2m?V~BaYEnrOr8JoY>l=L` zTjo6S{@rSXeTe3QKSDg$cx@CiUZ*M&q3X8qMW1y=Lt0LJ_Ao4_ zY7Rn2&qWqE;E(ifm-=-+pnmTgUr$miH8XLyED*OL6Y%nk8hQ0K5z3G6HTx&mJy>qp zIIj=CiGn(0I5$>-iFmo-3vl}#fsv+)l7P|(9DM4&oY*o6MYoq5>sb#>XSHx#!iU#6 zv3MnW`0m(rGU;|Ss`?x}7~K@`6zCswCDLhVrH$GWdTf;@o1JDF_V0AfNTP$^#}WQ~ z1J_`5UHG9ect4hs@Mhhz0^o)c1usNOZ`6lVJCFk(b#I1+V;;pk%6ew7mYY80o-V8y=fpD(bHN;H$PUfv#SMUXNMm@^F7$Gx>Huh2dbK^18mR1y$>)SKPAyqnztF^-uD4yFDjfrtx2!ySi;sg z<47NKHB6|cp5+`}!!2ac@n1tQjfT^yp*%9CZD1b^wzd$meTlXIHla$PWg=L*&fB(&rh=Ya*tf%b>xj@&^OfsRsJrIdto7QXea3SuVV3WeyVuGKA3>wN|k0 zM$w6g9@oo4wTQ<-T1|cn^wjM*jI-=f&z{~3d~E=@p}~L1KWIYOpICZ%$HR=n@Yi|? z!}q-qpPrB3>u&H4Xj@;P(9iHe4h4R^+)G*Gr-Yfk6#wvVveIGt9Z}Na#%4tbA|S5w zX4D;EYyvne)kuX!h=$VP;cd^?4R-L1-EWd|JA%lOhs~;|8^A=`E`@|+RV<6p_m94W ziW{m%Qd6g-uX}lHi)$sEOX)6SyyPwGa%*@lp9={6V zQfDRDq`kL21ngNa;ow^eG#JrYWcQ-tQdx;fF{{x-Z6q-q$f{x>pK8P`TH5zT2*8p4 zm@?kGxG1tlu4c#HFGgKI*s%6Q<#xjM(Nm5-ZqE4bW9}II^6`4|D$hfFYZ{c38zJ9G zQ5`aTTz*w0AoI~95*^)=_3vLcg7L325�`g?nIrVio3c^K4|e-Jn(WOFsaNIT$_= zW-qDO1~_?lKCp=}0qY8~nOPdbMK=Mrn`d2?HM zp56d1dQR0yL@>Jn&vIGC(eQ->%fd%bg2LoQPI$8Y#S9v)wOYj)3Y-%v8$YAmdtOL+ zeqD<9oJ7MhIQwp*u|CNr{ZxWA+RwQ9Z&ex)`}yr7cgi5U>iK#T!XYsnf_8T1A*@o* z$@Z*Gm{w;91;eg_lasJlD zRb`<51X4-}Us}TN3mfDkj;asf&Fji_x;XhJKg$qn{jUvFA!{{0{zIbqfhuOT5akR7 zVv=(*2**69mK>7j{Ivk|exb^-h{RvyW$GQa)!S6V^{l=9d^6>*Gc;(>_JxtjnnNp= zOX86=wj-HM8O1LC4v5!?C!?p*oUK z3;m7ox1l}xbC?3}K)x$gNjP|2X20;!TvQ%`=G}R&7Yi02JDJ=!A#t*Tj_rC4TF^}Ma+2PPXB`qkDDZ#@WhUZotwS1Do0lZH@mEMjCbR(!s5 zu$$vE9~3;C`A{o&x>cELOAf%uj}685HT$3Du&-IU&x^;r5<5z-k@w+jl~vfevMhLB zfp6~VhQm4nVoj2bOa_qqUueO0nP(vLoymW)fkvbdrqX#Pphu{b+u}sk5y;e9=aI-F zV7TkrhhBa$Vn`mVj;6jY$4cXgR;OEc-8~$pXq?qlmMMTsvt$0^6&4CUkk_6VK+$cd zD8P@7N)5#m_Es8C?EWVuOhTq}d5~g0lq@YX03~A?AUPFZ(F!{2=Tp%@euMoi5Yr)% z?;;OjV@xqG@W<1=i!%T4XqvTgf=Rz0pIHpD8t-jJ5c&re%GE zK^6+v3fXuJ8zMeVlqd6-eWz0TN#axv*F?w=lTL{N6tG(aUN`cSa(_!|$_u862<;t* z`422p_R`}W&_uyTbo9Td&fu9il2W0|C4K@nMHL}s*;WnXzc+17UubOuocmdlrz9{* z9F`7`t347GXQU`~RHcsv=SyOWHMmP)Qn_wn#s{!PIoCF;gROT>-ojOW5^^p5-uNbQ z#viLmQIz%z?Ka#-chxfF2wfI&qq>cql4O62c$LT(wMM`+dmPa!uTiG(aFaXgi_L@k zr>i$3ke-We0P#(I&!mD#APQ6~2#&LZ*^mo=6wy=NxbDUkjQ7AAYl8W}ae80-QPV>A zWLRTt#%S-l7*viIx9j-@o3RJ}JY!?F`^24GxhLDK2HREUjPlT#amQLyfAhmQ;~THT z75a%dGZYD4?lWrfVxAbo*XbSc1!4UF#a)X8ce2eGVOov03Pi@_(lh-NX`2cX_KcK5 zK0YmbVkd1{9cXQSn#l~kNxlwqJpQQ!Y5in@Cqutj_7b%eRqA}hQSSC(t=g_z!Yh3r zu2aJvO6aCN+d-R@djG^7QO4;)_RGb&O~E`SCNRpv!^xq;Ck5gz@~wWQj-w0jHA3S-lL$;)$drS>n{U2BM} zl$6(^h*MKN7$y1YU80*r&9nyRdeK29k$F33MwFx$o0V9L=^#Kh#JNSL>w2utJB8A2 z&vk2$jLt=L?N-028!{neDu(op)H{Qn#~w#Xti`9L;;%FO#=*?-Ilurc3Y)dp60tsv z|JLv#k|(@M@fjOwzZl3?B-d;kC7WpCua)2 z7O6bbueH=WCB6>aoN>W9XHIpg+w26ARY^#b=Q~U%QBcAt#D=)ZNOV*K%_49bA8V6l z_H2_LqjQ=C4oCl0K*pyO+5VOpX1Tt`$P0Em-KRlBt5w+wY(emBjXT0@k1|7l&E8Sg zig~+HEKZ3TNk|wSE`mEF9&G#1(37!S!!$BI!@-AV|MJhEv{@5J$Cv{ax>b|iO1)K2 zd9fL-waIu-Bm4K;44<}`aIKwiq|I?Jp@PIK5|T0stak1}B7OGj25#O{;aThB5D}Y- zCg7RB(afHlsCz|ukp-*MErWs!d8CuhnH7+yKZJVO);hc8^J8)vd0lTWi)+A^Kk zrTfdjyiyTgG{-2IVGGcd#($o8{1pbl;wsg%g3&{Ig>;zP=Ex8ve7+#_AWA#}-G##} z@SLja@IxOuj5BK_AxTNlt}+rUCG!NpUPO+6DBdJ0xWGZFg~ z!6z$#%Ll|p$}nQ7Mn7}f+?8xi!&cxmr2|=|>ytx3Ijiud-(0_hqApI205Xi3yvS`} z!cI~0$p}#F(ztbFxahWedyvC}Q6#BMmTprKL-~#_)_hK1LnsK!M(x9Kk_fEQr_2bM zq`Jl$?|mN6Jq}~Kyyhm+ELQ67RW5f30q^c;%hW`lm}ew$HzcqO^qogQgIIvFbzb*8 zo0Wp;OjVd_@Wev`N3(MF#Y%yy&J%9l-G5#$^{vE>-7?QfFAosei1!C)`mzI1Jy^I0 z?XWt&9VUuiq-bv&W?&C4ix^>CQC|tpOo2J|IQKK7p+Bzhxn_xlGQHcUIy1m`kZgxoT2a4XT$@YbF z&`2S&LiN@PlGRBOm2xlPi;I2m(B-7RljyV>l~(4%;P>bmW<3)-5n_^2fAGuT={bp= zl+%`Bg?rKBhzL3$jnJQXhsyDT%vePBF3a1_6nXl>Ynd^ZCWCzt+r-*bOU`rA?u#<4zD=^{BgD$w^~xr2qmd_W>uDp_vg{)pE* zg1*fop0sPZYwGd=yBbT=kc(>A@aSXW7&EImu=n1&Te8u!sLKu?9vk%CJ*OZov^f!C zKbTr~NqrhM)v(a!+LynT# z;HNXI#}C|ak(5gz+rQpE*HiXk1podZ)lDp_aascSAP}b1|1?vdALIE#4YMHjk@5N{ ziZSjDIbazbY$QgbKeJIRQC9f1vQO!y#^o1Zh#533=Dbo8g`Jt>G6c{oo3=Y05D3=a zB*M4TJQ{oD5wuU@HQW>UMz50K?4ZUev1W$FBABnB!-kAOLs)mHE*XkQo(F%-D6|by zYW{KL0=XNMay&ap{kOSYXQ^vSSQ4Ovdr=sJH4kx#mNJ~ITWBsRX2@>IHFz~?{rt@R zXqp6gCOUK5bijDYHqs7X$0)lNH7R2Cau3v)-7BEv%wH4g>jzwswel7xNJ)%#gi33w zVkWVyh~8^Z>x^swe30bf@S(nCgc|ZrLHO&$+IV10I!dz7E<7;Wl;O&Fz^q8 z%^?GWN3*;??5AGuB{{b9)xxbkH)br}w%EJ{)(!peqj)FkGW|-AV!QHXm;gIm!a(smIwC{9| zRxfji&w!mw@H&-{DrOJzD*oOm3pHxLtH|7Lp;%x+=kDgF%kKH$4`st3NCubxw)ZoI z{cwLhe|W}|jij*ar>|Yn`O{fdw#h0X&luCB&W$(*c+m^=szWfE2D70n=-nydQzF0G ziolz-+U4*r=~Iz!LSM zrpm?!=<<25w@@->*iF?Y$*+RJ+)O+e`$_PcF40sWXrn6nK6JrH0)VK7CWokfPWLa; zs*st!Vfv=c*!`4Ytx$0RBVH8Y6A zc2RfWCk!t)yp^Z(~YR*poo3N_&ykbsid=mz1x+3VcfM( zP@JqML>DmPBpEIyv|HZ|%sm*+{cA-{(Ei{VI3!pYt-t8E&hhy)O2>FM^oA+Ile7!~0K*hBrK)nlp zIhkQ&(7SuG(VsO}s^~oHcsUBM$*6903KQjxBVMyOU;o#SUG_{q=@DVVjRZm~^AUVN zkA5gx2j+3~Y5ZlselVM_#*>96=)@Pr&}I2(;Lr;;aDD!S-UULup>rRL{k`?xnO5cAA1 zOAPmE8CQP^MSM;Z5xnuax66cmv2zVYTU@qR`$s2XuEYhVB6)#%6(UkVO;iE?CRA!# zJ-SVK4DoJJ(LcFm-%~7|nso>WVT;Bw&*P>C5Q`Bb8n5j^0+;0*atY4xH>*P09CQ*f z;S#j!aJ>{NtQg0#XN%dHh8#99g^;V`c0A&|c@f%Eb)@*fFE*J^2n^~T4*3r;TJcVq zrQ#YkD@TIXj+Zz3tu-|oj-uyS)}k#Yw&?zcGYFUj{Ltjdy!NDy9Q*#8KyFH;KdSq0 zFYltYjs^;}6v)28Kr<-9LIYBk+GEYIV!#k??JtZqw)3TB;0pxWk!!W525Oa-*vx9b z4PH5HHNM?bd(g|_7f?|Ot*AW35XL6lzE?o934$`1R9|hQj%2%|hKc-|8`I5;X zN7qFP1A>OG3<=7w168G*=)2HUw^tjWPYx{cVzDg49L?6#`=9z^3>63v{8!OCo+tc&lU{*$HfPO zB|6y#OsEJsV$cGOZ+TXCPJ&q{2R=58w{a1$LP#821||&a-OsKQ!PCJQL5Wlr@*;Io z<<$R3hVW6N=7~!nJkbP&NkeZB)%3k0y~J(UANxy}P!6B2X5SaTqx2E3qW_wngstuh zT2WYL`M65d;fkAKyEg(b7a_4`>LYOPehf*Rdl~$5zL$ev6fCKs19y z#hgbei$E7NE~qo9*@szdzTuaDo{iU+Gc_4pHYj#9duSUVIBQGd7q95`Z5AcaA*FFI z8cT_9S~NZ1!==sA1S*U_T$Xbit`As2R}hV*dVmrW~ufrEyVaHgXd4- z$tvD4$(MX`k|jg6Ja8gqyhx7$WZ-+yH2r?Y=dx>SmbaFaM#+nnvjVfyCSC|NtL#u} zlk(`WnjCo4^M`_>pBLd$^J8q9y&tr7e|9`+b9Wvg2-(EUp-MV(F)mGggvf69gLZmVHU7E;7!^toouyMRB;H)9ZC6;(mZWOo0(;BrWs;`0pVq8;(>3BYx zT@^a=g!w@PEJBz5KY1#@?6z9L=YSGO0KPXXza_h$tI8j&cI}~5*n~aUx+ntvq3U3Y zM!1HKo>>F8Q7SlI?}DU672TolZ&0k^)c}6Op^WG{}de{nas3Wx(+a5 z#5xgP?BJguY_m6Z+X|4(Cwf^`imCldRg02lmfa77Ex~Xi@4(j^(b6+hX5k1nAfL2| zbU^RE<>>M;PLGr@OvxDLpl+K##JAWj<4L$~)CFMq&YuG^a&}YMzG%7arsQ39{PqZJT4r zyu!SYdUHhDzuLvY+meGVhX5%y!q&H(4RtJCN3e8FK`=Px<@ljU4H7q}jJNzQaS&)R zz=ked{yC(#t5Asb8xgZ&#MHQ+cFI7dd#hjT8~2Zldlw| zFkiWRy4$5ayz~6uKXnT=2G=7D^)(s~bpI*aX?JP?@gM7NKZX99!?)4{eoQ@0_B=LM z8dPx@GLd^ww-jF?7bn5fubO?+iCJn`BiXRLt7{oWu71pP5$Y>Y!Dc<*fCOrF0#5j2 z>P(}J3{c2xRtJ<0)OLI)VzL^-0SY3@Nb5OGuxE!mU|z;YuOg|3(hSdYqJUK8SvKg- z&MBu{q{YI31H|BZR|T@5 znI=t2&}JBtZBOvjr5eY^LKo?!xs>53vT;vj70UCdNw)zIgHXnMxpoNkks%tm>E3hG z`AJOonZv#mA4w=)_K??CtUS;bafk6pZ|NnQD1B>GOclY4geLurFrcOw+Y*|b)4NX! zQTa96+mc<$Ow$fjoYP%+W5~C<0%%`SMW%MpZ$qquKSBT^z{}q{)}ej6y@}B!&4*bJ zvl`zKp}-gEJdV_W0z7CBuq>aH+mPepO#9onm=er+=A+%cdvZ7dF*CdSZML2*MX|b| zax%saZPsp_QkBdxLsAX_+1qBiOchTEAIRovbT;Kpyfbhw_|nonBK#~Ku7y`xA=XI& z>MWn@Y|54_S6+DZ_VLyLLQmO~K50_M*VbUOmFaD!0`A|y?ZJMZ*x-1wPTq=j`{A$} zQOLtw@=T^o%!sF#a6o!$wJ$bgzjU7qTLWIDGr)Q)_H#4^S55ZabjHMD>!u>yAIi4G zBqIg6=EDfHYJ;KPp;sM$m{~Vpk-v9V<)_B<$*|tH_dZ#FiCeW+!w1kAzQJ#=7tS&Tn5JdY{=%Z+ppHx zpsC9qrF~3jI>vj+;LIH;Fx!6`I3ECMJ(l0bOuS+Okdzo80EO%7!E(zOrRUNXpb+m_ zjJ2&Xd{BRLG;|GNpYL>d(~?K)nbCk7EyDfz`#jU@SWW@ZW-*T+D$}_1T>}34`YG#*?3E-$t_q*ifX#rZQJsbs~jy-@^;k zG^I{2dScFfK?SM5x6phnc`2Gl&CcZOWGl`dkuP6X#0)~JbGPN~F&40#Xtw#ddVe2K z4nQ7dDOs-nN9xgRj}J)lvnit73x@*n_Nl7S&BTIR?-)01%lF6idTp zI)%cb#g%-fYOJbR@Yb7NnVahf7wHA~^-hTy__+Os$3QBxkOy!nRqLBQtv817QUQ3e zi8Y|z;)GrFx9e2-yH(g}iD2=6dDd~8GWRGCt2_=eENSF!cbp320Wfh! z?EiEni)grqoiXrJ9bi7<4D7aMXPb0)!u4mhNHQmXvJ4K>%#5gloFEx2m!`N$fTmJQ zy;1j_$kI-AFT&O>kp-A!7AI6MgIV|*m%PM$F})=EPGI<(DB87x<+$xytIWettEe@p zbb~}3#U((z;5VB$s@lEENV(cc_t?4}gF9wd1v>VYnPCo$f|fCtAE;>ieZWPh0%0Q{ z6!O_+)DfWVPOkM*ePzK3%_iQECra!b zVZ}E1`dGSVIxhjI;TNqmEi!cBLH4Wr8QJ9QNZhSKt#i4#&OovD*(INdcyovTI*R_R zC@GIF%>^jw#egO;noRcaND=&h?Nk;FX$`ahq4T;dTzdFE=yVrb#wTI^Ri)NXgtE6U z{yEV!29HExz|~JNAk--80lzn@g*;-H5C9cvwV&v+d1zV68i7G`gw0P{K?3fpydPjR zWI$?lw_D!8)Sqohb9A?4Y35y@-Ca= zs_@U0-o)`t|s^36om(C&@8GhiDUDPA=+Y*YkWg5z5=h<;y*e29Q9i9{Ren0 z5KHH$HzMAf{TGPtByubR`n7z_PrK!D6WlN9k-O59Jnoefkw(`6gEcfLW?+)pVq;ja zzWjc#5s#qpzW}g`XQqA$s&RKA8m{$Rr`$)-F_1Q&B$Q^#;+BxHDo87LPl&pm5(#M- zUSO#Z?b@!FXM6TIetjZA;JQ=vvxVMcU*1^m+sb*|tY4Jt=*r+1AUnNhk;bcSlrcENR=h~tvb zvSjPf*+3dlmV}t2%*^Pir#Fli@a{jX2eW5}pr%SLePf6Igxu9}lrXV@rmpG;a*)z? zlZn(e7oyr|RLLjMhu=mobZpr9PE*H;I#U0aiP)k>RJA)pI2|K!jVF_TjmhJCXC91i z2QXzaf5~uD5Ci!7+X`qQ19%E9q%o8Z`AqW#r|f*iP!Idi)ClUrtdB`KrPXVlmM;SE z5`p5lPX*-Ovti#do&|7GLYdD-y&|1*%Wc4TUPL}PdpKQ0tQ0l7gtjZy=Fe44tF!x4 z#eDBQ_5|3$8Mw6&6k(}?`eDFG z4DIfj4q(=z+qr459l6FGEfO(l(}V~xVw*qz$rc`r4uHmd z^hvLt@BXgYew_2bJb}V{jdz_Xr{TjMnw;}o*}ewT6QR9U*r}Tf!EQFq`(_fs-M~{Y z(q^UBp{FW^G*>y0Nn>|!f6MBHJ_S!~~AkMV&V1o5AR$^h_yq z7}d&k3*?Mfc~&a;@zB9nU$KI44mIFFRPYB-Olb=1fonSmBNzOb8`MoDd*(vJjin#Ii%QIvg6K?bdyXpy zdfjeovL+d2^<_4NS1F_0Q|B|l3;Fw1liMAH z?Nrpe3OI{Ea~K&tzagZxTsDk4qNrO9sXCqL-|{>?Z@r~4OlS3t0TC@@)j5sXZ2upX z>ttj@exgI*@@da3Zir;&*J%CM-Ia-hDCWiKTaL>o2s6?>sl*w$`Cii^I%#X(;W<>e zY}Rgori?yP(7td=gotoH6_5rLL7svmjUryeI0}r)K$j1?TozngE-8jmkT}`6`Bfye zNO2#P95Y8-&_5cw2`@k49TSVttqss2Yp9*;XR7BHqi-%^yWEUIpX+}qF~{2G1%xPU z`>}u>_S`IfG(}R-C4*OY#Vk;**75sKs%ZTZ54sJ3Ma+*x?g2R)7T4D)H?FgzUA7DE4?KFK3{hGdOGTk?Jy_mi3SE`0@aqL}zVR7*`X-BDcJ*agIZ8zE+;^VA-3dC_heF6W= z-6fx-X4L6`DiEzs{tZE{Ht5d32yfF1Muz4rO}8WOw~Mj(&hI%PO!0+z6bq$>BCU~f zq`ANx!<7WFJ1~iUIAx>Cyn=9eQDWR{xJNJ_Al5V%u+3gw&ZOgG)wq1&)g^ueC+V{q z_YK8ALnziCm33as?f57qlrTCFs)4AW7qc~X80Y3l1WMlFY6bEVz+$-Lfz`mAGQj;!m6eqibW;QmZkH?F*Qb-I3lCfBHM@RvvlQ<*_?+4+`U zREE!w;uM%5!}vrnZ{F;$4X$#IQJq1A!wU;96LA=|8-WqreW;*(EDn%qF(f?!EVJ4c zXckwK*2b;DU3ttiVnEXz_x?3CneV>l^0O#_Z{ZmgNYqf0x*A-?@E1I^>}NYcP~@>TYl(S07q2p! zGO7*|Jy!5=B2JN^E)~pRHk6m)ScrtjxNMVS7r3YH_4Klp4^2DZ|c zBPaVGYras*)Du&i1$vp!5|bxEMzi~sKdhi`YNF6&RE&5E@|Y|n4apw1pe59KlyY8? zdzV_J7=>-BrG)G)gjFKA3#$ZfskbLy^9CnNGko2Ks(t(Bo8lF=rQ9#}^w%z5y~mo- zwRRBk_KWN-*}y%tz^}$;F2=(x*IJ>`ESk>((sYK)k<= zBDGQafD zn*z}m(Bf@J)v$_`q{tPs89|U9;quV_+vS0Mk?nb>-C4@#_7n@g-pO8=>z6>SeA~=j z?f~bdFagM21u3{3qLv#@r3(-9r`^oXqd2xFveoq7H-R*TXAC^&n)P5+$Hw9d*qgm= zi^V2omWV!1o5S1!)Z2US>&%%}gJcGrm@=;t$Ku@Z}?2qlBP zG7Qu-Ok`L(35<0V%Md0w%~ifn)feK=`-->P%p%dxyzvP&2o-b}+MP;{%ESVGtbKv& z5+h(IuAruN#9GeY5sh^{QSmxpev?amGa~o>JwGMqAVrcK9&t`tPx;ac?zSV3IdwZ` zmLT!~Oa&;M8e5S7$y~>mcU6iQRGQJUPWEp`?BuHfnL6my_8R&n0_&AoAK*sXe9SI~ zM;x-of`A9guo=?i*)=YgR!o5`6nR&SEiEv)?_GkIkMaQe4~6d5FIDv$y0!Pqmp0-g@~>e z2}O_L!w|b5cvP&cU0kX<`Pw<1-XOahbt%U2qtq^lK^$3oWB)G!7bIn;r*gRxL zQiVU7p>db1e#yPd zhdk?b;%b8@TamGQqh@yrKG4h@gYPu%TVS$%faX)w!`@@yc;(yJuc=#!4mE|21Kpx8 zm-Aor8%y}o$ulxeDv9rKQAF0^ad*jyTd3&WVEr@p7uj$pU? zKau1)WDYHtKH+Ta=tCva&!6}WyH9h!|2J6j$|SOjV6wS|j5N1mf2;POo92!p;dW}| zmOTEZiqenj)e{4=WD@txolS;EZ(>@FdwaIJ>s|}&`^{r2u$j2z|c4xrT zJ#P5elK+nwp}zMR?s3)4AY+JI9XQ6?OIMFV)QTIQrijxR3dI8UN}Yf-pk9f!Q@Vz3&Qt}(bl zN^^qhg0s+6r<+mDv^6W-<#dIh*P@*{D^0KlDH4_?}v!ip<}t zb)IYP`z(DQZNX~*8FJJspmS6A!Tz?ie>jniQ^QwPG=e%SV6Z|c2-`f zG!_()rG@LrEC)3D#D@47lEzAVAG>^SMa$MDOOKKJ#Z(ukTNTRH30m=I;8lm9BtQvETK%Dy&}r>HZ8`iqYC`GgEdx zAu!rjuKRlE>~c`QNV!I*>Iw6@amZMR0X_tWmbds4wVhNb`@AXxq7HO~N(KS-A&{8= z%kC9QeA;E#HgVH1=iW&36^IYZJEk!y6Bq_JYi?u9cEduY8t4)B646_c0Oidlm4F=I zDWzMlmPe=y;Aqa|*q3sB+(Y0^U<)T!mb@ky^8iXh6vRSMy$Q6jCQ+myK7>a>wDoks z9?)TL#$sEcj%*E|5L&u0^-ECss$WmrCdOE=oAqtx5S+qnD}dAb4H)?jU8>qd`=#yH@z}C89C&j2+Ejb=^s_b+yfGp^i2FU z$Ow}Sy0s{wXkIw#=_j~|Oe`hM;!dK&Ljd_}1o-by@*RMSns`H{md#l0F-!Y^*tO=! zXM`C@@6miSrV?_e@3Zxi5p${Ac1xY|!vLe;JKv}=gO*>am{i>p)eXJ85`69Mem4;b ztG`k=pC+ilQD@a_5YJ$A_vEzVOpwqs@M$-05vku2@Ug~rBFt?M6VWp>FroBkPUUQb z+^O_yqoOSS!SWU1GkjBAgKsbOPV)JEtHD!CwSzXX&ldJGRA+kB$xxLqt zR^(9)X;_R~Btu2(RSCiH;POM_IN_a<`0@r$%p5|v*g%{y#VHyRDroDV8>UOaL{(=% zObnTu>MdV?MVzcpQzRg>x$1--QlrUhu{12Z!P@x)Ggi;PtvP3du{@H)ZcgifkJvnl`3hqzu z-N)JAr5`V-s4m&g&Ns{NnH8?X2NCtIdnk2g-5Ut7n0o#e{sx+~UyYqIC%acwl~wh!jjEu%di9e%A`aSV zDFa+@o|3Z@(Iq&x%F-YjBvC3Tw>tPU6G?Sr^>(8ocisIF_rGMI_AD7&3|0w6v=ln2 z6j`J=V=WG1!{8Et)@OV?4~s1EgTfxs)6AmgdWcE(CfU7W4ZE^uoz;;_b7Axm`<>@Lu%{|RvU#5_K_wKrdG1ra&U&oWSR zYnM4F+_j!mBRL={(|zb1n6;e>&CYs>nuMrkS~HK^`D9&*r(YKRm2~SBYP@gmu(H8S zqySY>l8;AXm)Gw-VE^e8Kr5=%%ZdRV(A+&76Z*t*Bf^$mXU&r;ph*mKyFMj#L+V*e z-l=2&X{bVuzM0_u5!`R%yXzBL>yMm@()_;_?`J640QL|dlJsugvz~gsOAbQZT(`cG z1Uu;`xKc@_sxeUc%DHzBcC251Vgk4@)&a^%g+mBEgHn3l&uJ{ZzF4tE`snd@@3L zi^|msOK(7Z86r!a?Amt|k6p>Yt~aKVAbt2Q8PkUvEx5Aa8TL=&*Jcd%L#rHOh-^x; zJ7W}~4jI7%DK9aH)_`%~0^vZBI;M)wE+1o?ksPb|#KZcOXS_0Sk^cHc3Ddqa5r7-Z znimYyIXOBV=f;4P#q^zYcKe&}w12m?Kr(%(EXvr#+nm3NW9xr-=q_T@<}uM$7-v$} zh}LbT`I8>`83s{T0(?up==Be@m z9|g&6$HGq1q#DRYL(go3Pxl}jqtggEpd?4=UGf<KGhX|`Tc-bqij0$NF8750$(_XFS{d5A`E9dT zhxibEcw(SwM+i8cMSkQ}y$AQ)E(4#DHQH}MP(a37(XTmxkJpKdY?d0`m%65IW1)I@ zi^LfO+ChAe6v|~G&@x^+Q8{gJ)Q9S9E3CuxpR`F6aE@-TL6kzauDM|Hczy*E;f_g; z@KJq{I6AYUOWz#ew5PtU*bOo#GFPm6%%iG2=jRO6XG0}@U0WK`U)$z2U&GgKCK{!L!s~z1c5CvS$f{$y#y{H^hKfcROCh3` zKBh8*qGb0*qrDPv!ihxy>&!%E>vYVU?C=laYt9DmXj7Hgm?pmf>g8q=WQfM(tphgX zrOGmmdO5D0>dMbakwQnE1opSL$dSC4=)c*|A`spS+mT)Jm}hU~^h__Fi8jC)Gjpds zCl6)rnw?F6A57d|eBDa@ce;vju%FfbdWkS<0P%3B&l&a9lq3nB5`bsRVmWC937Ej1 zH}0W^gdYFH_0=c+dHJAMSItWGgjx^kdkju=e?Ljr&SiQT7ZiT|5XBT|(ChPi@ern( zr6Et2wN2Bj{>aU!LBh(>qm{795D1M?JE2W3?(kNa%j;>im|A|L*6|SGk!z$u29psEr7sPq4fr=5$kmoWH3rxk@57f52188TX}rNd6Ck z7B9%JF%Yx53zxQn5e(FwrbdSO2VMz^wyN4<%_Yr#0EHM5(3&wcS0)Udi|QY`FQJ^f z=~@`kree{FCRx7qyhS;xeQU*NU2OsH6uN)Cmu=!Zj4n8?tkN>{gHyHRyCtji>N`2Q zI}+o8v5-l6k==eA-8v^ZYBZQOl_bpj_kT<4P??pKVOiZ3a=~bTM?S(9EfUNH2GKJ* zlpI-QbX9j(n38{$&^_0=0Rt&-JC*@|&<PmEBrNPi^j#ZKvx*I^s;35%bK&WvOCqan6sgL=L)f0jwZPU^9BY%to#aIDIevUc;j#S zt19Q`mR*~s=h^N2V3v-msc9MMLr{JFk(x|}J zfXQfC3)qjZ2XzNV%6uOA`QJAVHVT*jvHyQy z3gkRW#U>pp=WBE+(uMGfy3$CyMST2^eUzo3*px5} zf>_NzReSm}x#6tJF^E^!A~LxycZv1eaNO?^RRex^c%A>fS%MtIh73yW`}b+W?gLhL z5-42Tz)Bth2uPnlQRI%k8ecz8wNL7mB+7nyxTOx4$i2r zvi)%bVKqZkSLA^%Dv&A>ZVvO#ev@(~Q5VwbhQi%por0XJnVJ2*uhGl0p;_)9%SngK zrCAf!X`X7K7VMxJW_y4AgS>L%@*)D~v?`Gc0Hzh8eP7gi@<)J|^_ah(Ji{3s6YT{0 zNu3kC+G2?YlKHtT4H*D%98|?~(Twm8`^PlF8U|6_mz!f=vRu>h&|ccT z`*~>C>lsqo=^uv=D=o53{sHeRf}iDZavNogt+<4dI7xH=z}hq>GeB|RR| zS(J;bBv|%cke5=pi_tsDDMCoFGt0H5} z&j^t#gn2DrlFeP0s&exHKVTeg1A1--jOVXmb4F{F zXNGHIGgnhF3(6*2%qqijVaDsL$(efNkW?g$-k4aZH~d*wi5ZzH%CnB`21`4 ztn^e7egR5DnXI7@10(#Z2;N$W73y3r`2L%*Z@%)cx=*wJ%K+sjJw6?=J#WXRyZz^Z zZ@_+}y`Lfi6EGcq3RQ=X_&^0WziMCzHEGAd+qrzb@?;(5s5JC&H<`DKRnUTN)3bJQ z@Mom+%V*7A#ff39}BY ztM5|7a^Y)ud+3rn;Oe+&8L-THa$g_=aGPMEV!rZqAXA(UDVy2lg539o3wuN&AU+$X zIz3RUA}0ZcB@D{-5BlySRgTw1X;I9v9YO|xecq^j zxB67^s%oI!zFFygKuG2qWJ1f-=H7=-NUiG;npRH&sB^&I zfCI<)F?1NEmn0AXt^Fe^4HKciP8A#hQBd2SXs717TkCec2+tw58~A!LXyiqDfJ^;k z$xrSkz2KDa7ub`@NK2ZVJ5DPc!{j3N?cDN6ZMYqA;3 z$p^nTz`iq#<>69)R=Pio_Gh}M|b`_c?|axdk583VI04?^CZ)vSeh^cCOtZR64e7FB9FP2VREYCWIjj zk{dI9*p%f4@+Xjs!%=rz#4Az>O=kla5s|w4XWWN1k{mZRX$}nLU?0)=`4m2VUZwFE z>CW*u6*}&tejochcP?#m{)F1TFCzIqcj>C>;w$irK*%jeH}&-7sz=%7W4p+>Ao#-vl?;~^TFrP3c`V?v{hVAE zD|`;YuDqz#&kV`*GbBiR@k~?p(AnotVq1Z1l_CFP&PQ>9-WvCPi#&0&zW;uCp*I`P z&!OI+;P!bu;gm70L?pWLxukI`mTQl<dK|Y1_5~Mp-Y2bQtJ)fImF4QrB}4I|ZHdcw!Bxjnt=J=b zwN`JgGqGCepT26wJt*cZRBGtR&40SgaB^;!>FB*F*|>jWJ}hWDazPzVH(djN@Sukv z0+34F5zuU%T^t;prQ)wxeqdC*ANwY~Nf=FQ=>mKVW{Y0(FIzwbVF#NowglLY@bYw= zzTTn1@TC((PLESZD7yoHp%Mkm>#DEJL8X>rMVo?YaBMGTZKKHJ+KX6d{4WKcE z^D>~j`^eCiS%p5%kZ}z*INbM7ArXUBvJz1Nmcmo+QOJz=Oha6(Zv>i}Y6PV=l|0EbUY$t?v{Ce2q0{RZz_M+%_oE*F#$SF;467i{$XR zC@G7uXqKjws+a^O-DDu8zHEq7GSIf8n#fee7a}4O4zv1M;;o1J-J(0~{M{$#;0`qh zmRgD|iAtG2i;IsMlA|z3a=$TVz6brAEFwjOX8Qh`5E8OkUOz0On$4p}s&Mexf%YN! z9|53QYE(-h2L|Y(IoTUqCE30xt9XvmQ0(?GXm-LM5Dy#i7FlD2!oO{EA@0%Zq&Sd( zbJhb0e2Y(7WMQ_QT`nL&cYV2}5o1{A+tL;iH&s`>mb1(MqxVHKbiGapgWGb=Dee%xTL>fi%+wVE0ysD9 zV3gJx^G5wdn?Rl7)fOY;NRzdelxl3N8|oSEeZNi?0Y}HN0LQloZvV1GL|nk5DQoy6 zp-SH(Pkaft*_~dyqzURP+w0o?97!omw8#0i7LXu5``d@UJ%|V3?!!=Gmxcpc{JC(t zhE@x3IxaJuLNCE+gvy;^S{i);|O+JJM>C4VrV|q6QvsHk>gG)u>!!5WN&_3`i)UT?I@2mTb&t867tRIE0fL_427pek7mDG< zMv5Y7oAdP)2BH@a`N3r*gA^YV)x((UW;e}dO23H@(n;-M2+aq3F|$$FfFEqaKL-^7GXUPH334uR8vBy8?zgt8N_qo%jBmFtn78U)8 z84;z6+6MNo6}f$*c%V3m0dshZNVtK_1M#2ws-%Sqh^?nW=y0M!0Fnn)=CSqWln^E^ z!yeLRPc(E$7p*;}1MR`O`p2JQ`WA=~CXcDlPF^hRSX}>o9mjW*7A^j$cI$r=HHrKW zCAxI-U&F-1)mhrtsdO?k1+fs_Np3UY9{usm&e?**=U(f zG}j7%ZA7Gx-ZU7+^<#Pu_N#8-HAcM4t+tAWcWAv6uLK{Tva zmn#tY+SYssar%~&E{C)%yPYP-Dd4P#nscoaZ&s7T+sY zT~-IW%$_`gZf6$<_qLz9d`%R)0RQ)+wh!)HpykUKTTxL`p6SlCBzR&noWLgicK(s~ z{2{YY9(}IP`*`B&3)hbv2#AP~G!8#?NsWD=)l1-yqe|P9 z=gb_1sS_X*PB2<~8uvM{O-sFGk}m`#%9OM|rT3{~2=gIWQE?zF%PSeKW_X#c@UgP4 zV8q;z8WfNScm30%J(Y+->GKViZpuidRx8sB2NmWLvh};;C*zUx{9iGd81Racc^V*h zpL@f-bpgg>`^x6->8{^=PC^{+Bsh@ry|}3JhU9})e`zKPcmP23A|z!}zI==%hM}r$ zv2(MvI5L3v(s7x&Z4Z$sqw#6O_Sm$2XG{fC%P1jvwflsp9MMn+q8-^%;>`OIijHPE z>~cGPMZHxLRcRyz|MXh)ZTIQt9-$d5R=7(Y|0{*$hgxA&BII@M?D5#rEZA6Tcn2z2 ze;$?RF+Osyr2#KB6k`nuu)>wkppDD9U^xkn%A?}#NL>U^pz*tN>ZJEqHwqzQCu$Xv zZ=~BlchlQJMq6pHP|h>g{}fc7B48x$0`eD~UerIr{!_DAR)a+#W5o^&j+w$U@WWvw zrhqAK!^!48Q+R$O{OMCGwZISn%s`#*;xs*FgpWCK-}4^9I29pKL!Ef#aGyC~KdA+w zACG9dvmalO*uOK0^;Hb0XpGu&3X1FNPmpV5r5#D!N0f4&q>u}Hiq6E1y)d`;*(i#< z=B2r)z={GlPe3!!hJyDuttZH%=DHxH0x`TOQQ?-nt|!vnOg(-tLsJyy`6m-IT^YyKos`)ne z*gH}7kuYhBIQW+K!>GNFOj*wqbV%J)S1S{k{gC@!y^|!Ag1kp_%vXsZGQm6El=FW{ zo>gL_mJma;e3cDW02r!G1v33zP**JOZ?0m^X4$=|l1)zRtA=;-<;l3`4K3*s2ZXmN z4EC-iwaa(ww~b^lTR@8&#@9-ybf- zrfhbQg9XIE`MRe~&%9J)kPD>&r%<<(p6rAwqV5~LnGFry=3bo_^=sYLOad#}6Iw`o zJ8>hI0S6Nog=?6EECLy+n81-@(mF`syB5M{rdZ#! z3p9G-0uAQGL0QN04G1LmRC z*owQhyEBKX$DFt^NZef1=y(N{KrwOgF^xmlk~t69G~)H02WW576Z;)+t%vQ+9uYP; z?p%a?ocvv#MNGX}IN;xAoeu$zV){ifw?e`@>Iyl$n!5zbdb>`hAI=%gN{wd7o$jL` z!4UXSzr!U%OWSD=eQjaOT}eHB>L2TCG0n$#pfZWM`gESs)#y?$#84XP!nMG7iRaa` zqAE4jOcC|hBiR%0g~#fJuv`UfCTJ$|4sXqEik+J#H`GW*`6x5?O7_F+yH#5*Zk6mE zm3^~g$(bUa-~+^4@o1i^G%!sd!AmHtsIn0z6DRMk-M(T6YIEU%;PEXsCeJ!x($ia;&C{koZGux+Lt~+wc3Qh9rvT z<&nP{5uYWlC@%LfD?2y5Y^pZe9E#kz@`!y;i1w3{WkV#yRlBd94+(JK1xb6at0pMn z;dHD-$vQxen^WgKzsF44fbWqnfGl9ACvKdT>g3Voh}-~sb!f|?fAXGI)~7by``?q8 zjb{aUr|GN`e$qRu8?ooGoXe`ZG{M#_KpC6o0F2r25peDQJ8Z&xFrjQ1!-io`8UZgq zvkT(_+F?VG1OpfRD=~r+_?)mmc*cIM=CS}O?O%SK1GRm;5tW>g5uM-6=>Pc-XQP0X zOJHC^Qzov>Fkr^a>zLF?JEk3)1GZKDjDr0 zCGt0&Y`w*mL?p&0!VT62baijth5X_@rCj}=13N=+f8C-BdD3oiP-~yPyLxtE@ZyO; zi@rmhHP{PH47=rA7P&&x4z_`k-C-$P@ zKg8wPXQ7BrOQ6buQ)dhqN{`@0zfxv>BXY7rB}(>JQ&M(s?%~nB3y&D9D5CE+?Yxr+ zC0RK1+5(%hvWEP|5pudVg603vLDDHn)iP3*z5lp(0mR53!D&TwE%*0u9cL9bSPKOm zV|;HsQ+xl^!mq;z2wHttldve45Qhh5nd-d*breM38eb-{CQ48)k# z5d5Q$cQmsKBcfaV90EwcGjQPvI;)D&v{A}BnuNMuft?<^p9%ah$l$!UQ!7i-?GE4; zOM_(n7~s;uE~acrh>=iV|4w$9DKgIk3%2p26j(3J>d58IAbniIb4Kh<8UWeZiTnbM zkc}WI95kU*#*OL3WK^#z+Y+fI;g zQh`wHR!m$SFELLuj7R#P5-u+7Exk-W`ZO#f@~ja$P&i>NUg+AhpGAGF63ZGBYB_rQ zR;jC{*$69`Q`@g0U~m1JG@2oElnzT_@T_T;!2Z*R$d*13kE&U%Eqb+u6`%tRL9?&8 zIiV>LSZopW49n1cZSXvO@KPijy{a8W9rVX_eElJv$3ER(4Rsh%E*f(^jx4y|BdXq* zL75Ev4;?Q$8>pKdE-$(wijSA0{Z5g~e8|KhpVuKjPg+%9m9tc6AU~;V#M#>1I}4me+hl#Ow*FR>x(JSi&piH646{l3w^Eu& z)Dh;|*=auqBz1JxTTN2Z%2!P>Ap8yzatUKMOoH5|v2z6|Ya%Kg%d3ZPA3TS4etSiy zy0oMD)X3Hjo9$_Ci&J#T$wOI>>0np(bK)UNJ$Ufa{Q8FdQQ2qr{X}G>D`5TTsO64jt?HOB(tcmcl_E| zIDHD2kC*$$Y5rn}H74UCoN5S-V-ao~20c+c^}$GHlez_-y@FGb#i&IS#uewloEECc zYvS_QlOsGoY<12YK%T{feh*Tlfw>CJ#5rG-l*eyt(Vt#+KkL(=&69dd*xF=kLoIHU zEZ2u--a`{>NugU+K3*g{RQ3W#nBdb;vNRJ{kcaZ~o0;W6stXH-nR|czrxIg5P5^S( zK$T2&wvK0FNzs)Vk&%XV=7619bcM!D@3sL|pYd?L_p%^cuFztWXo#2R7Kz&N1P;~d zi^W8LaRV>NAvJsPOOH-KKu)ZkPfw4(FrD zemwNU;eT}O`y_Q&p>i(MtE96Zi24hq+%|D?ObW}Bae-l@j8`Kaen&1B=NCHOs8lbG zAxOOg*ASxdk+GHgJCRg>%12h6@j0nx7qwccW9`}X6$$HOKRU1uNuHQ?Wh_s5@EBZV z1}T=98}EN_N}P=EDCHKkJ^z`75p-V@W)ST-ZDD0`7yY)Vbc|3LS_cFHeCVIP#4r&X zutwjo6ueOOqhm?MR81qMd3CYo*sVQe{RFWxMZ>D0h>3JwkUHSHfy zQ~oNs3B5>&e@e9Loid@XR*x@uqbDG^<(d$jquXKj!!oui2yzC!7o-j_iRPjn6N-q?V7ly|3?|wnLE@^^JRv^`osUlYX9YUfyVx=OY=CH5v!6|vN&b0V(-}1eNXBst-Omsji~E( zv1xZa*&R@}(e%A6dBcr^_jh5I+^aO{WNq>=BGmE&dI2gu#w++g*06t%qxL|82z3W) ze`(=_^xt|+DF9ni1+sFo%+C+X%QIsmSFDovL?pT>nD*hlXhP zf^Jb9CI@eGMTA^Av&@7q5x)a0H;GNvf+~?k{M8Zwk?;a*I zGVEyba9#d52G2WOuBBr{mt?wq9@thYil_~}j>91jTN6-8M`hS=b`0MeWsG%Oo7Xs}K_1N@aZ+?pLt#kr+-jwLhIVO}K}UJDdI znMRE<^L66>1n6)i4X!-`-sW7`-L_b!J&P0~E$|n1>+R;N8DvA0Vt-PkL=>mMl`$Zt z6>i7IP4F!TE$B`CYj{=H1$#L-baXO1(e#*-d6*30|c4)#BYY+WUe0eM*w&aS_|Fx<`>T z7WZdDKm|9Lo0(+NuGX_|8Cr1E=XU^UV>y(ZdEB+axvCsPOs`Xdi*&HxyV z-BakU7LQTbua4np5CTJ`Ls&7|(X5$^(T2pFw2pLY0WNW*@00#XP?4mIx@UsKx+eDa zjMsAk;L1uoi|cv_o1NzKw)Azwn=0_^dNWA6d8Q(7ZU*_z7#^_|KZ)}*2+Du*c&THE zKdD5eDBPKK{Bx$XIti{PkM+LmN`#eIuwCa5l{>qSm3yKuRcr&y=3tgVS5I@lK{KS} z+=QYyJ6wRKyc73kFgUMNZ;r>dI0?{_D`~Hic*70PJ|8)?AT##%caFEXhhjHC+j0q? zIpEN6Y5_GuHCiHgWTEhc!dxZjo!2oc%_89lFFM_rSj=g-Uw68p`Lk){iMS4j3;aZk zu|#Mht#AH-N7V~snzLC-SO}%{M=5wra)7Kia1yh3DsZdM7RHsov07JJ0$q^wNN8+- zS|GNuAFa%eJz5~Ie{X$Yc1jW)kXOD@bnK)UUD`_?kHvIQ<7CocZn&CKCOqv%k(B}> zl3ju62u#`>QKaN{W!T|rg}nbHpC?V=Uz*d?A_Ch5m$ByUp)Yi~@F{~^exB3xFhq@# zXKn(NAg+0ytK!f!iY6RuC>wR^z89XZ#8;{Vu8)NOKBfivDnJE-aLmojJcId>_-LaB zn>N`9>Tdi%84X>i_+d0tG(**Y&t52vx67Y@Mc5+bRlz`Ew|e#u*swB(SpcaZL)F;emAl)F9RxzsoGf83s=Y7LO zokW|PEiskrx;PShQ3#yAmzKFk>%Bp1q1W$P4Y$Nc{xQlR++e+DP*Heg~Pn>yVxKa;gU92=dbLEaZT^gzixzfL2uNcp7@CEJ>*hg>+v!$Fe(b_5Q}gr zIAW+}L=2Zx>=kLOse;^!v0etL!pMa%VV6{K<`J;=Mb_#4^G_g6(n-c^N1$v$hqj7_r?wDRqCsu3-Ty~iy&-9BSF;8^pBEP~o5_|q zTbPEnTBxmKpW+RR4oYA<<#4|Sf-uxBwy;ZYdl};=Zhz( z9O15q1v-aO@N*)tq#<3&c*n1)p1};V4v00si%W`IOT<+x)o}oTsn|30Y&U^Rh(m5=jY&R+s=Lmn|Tp=W0j+V_c?q zN8150FR0D}b73(2^d z&(q`jad^S_6rtEJD#w>_zNuD z`aD-Rb1zb)b%3-qGY#2ID}R6Y;I!6}rNaQ%Yl+`tzAz&9KDy3IDE$%} z=GO81=5#@xix$t7PmiIV-9Ig(K)faNY61n!JO#BJC8iY(MVur7dzfi@&`|k5^(w+B zGzL{-*D+v8%nhnH$;>E|8&@zY1jb%;_#^d3WAft>8>YVnmNz`o9k91OFosm>6wku zR39E}koFnzQ`meBgR^P^F+3A|QcQIVe0I2%4|5V%gXZ$1495d&jqIw*nYmOrgveu2 z_e1yqq~tkCWRK1y&JS@(m=gny=XS$e&J7$+CK7p4PAvHDs}18%yv&&h#WiA_slwm6 z0wLg{qAg-X*k$P&=dieAch{W0RfowyW_xH(RGvWakjUo7kngTsxXi*nVEc#{_zSQL zu|@*?xIzkdWC@Z)Hl&|3Qi56Hp=rh}6EOnPR)Y3O&oI<=zM}jPfs^E`5})yTHz;)N z)a3lAUd^mx9rn0Eta~188~G;nFF4{DhOx}a#09SM6dwO@c{ee(Ew_6$xcS^7i&_<9 zfqZDlJpSCtbvJ>m&}#6@`hi6g=+r1A=FGf6FBOV6#_3q-@xYZ62ZYu6_1cze=lnvliH*0}u{`yZZy;|Yxcce@VBMpL{S!i|cU*9_skOaMnWv107HNp#R-a?I1bBKtRYG#$Jb2H)m| zK8vPU5oZPqk6sTN+_TX&<2}fh+~kA@h#0@ZUr9Do!9StSoqb@OE^oJ9J87T^b4SQk zM(g~~lt^tbEK?b)Ywos7QnHsvS)gF)AqPSpA1T$MlJ_3TZdY2SxilgPsMnu5A;LBz z;S-%22i*4wlHAEg(6dLgwfaooEOc~goA;NsQcN&~5uUc>Xj?|*Kg#9YPC7d=fPxgjFAYb)!`d>xJ~+&@Ox zS-GXF!GhgZd_OAghh6OY$@ISx&{k*O@>-NZzp81n&gdKr~l@(-~o>yFpHKR zUMaT52ePj_^-uQjBY@e+*G@thUeR~jSty&;wE6gV{FKCn7#wi*ZHq=M<#Gi0QcG;| zcsH{~RzV)%$|-g4jOl-t5s@*!8B*f4c@fGq`W%I*|2`AUf8Bcay_-~d{k3hU_LRoa zNm2H{81$5~wsiNT=0jpG*2^T$8~7NAhp^?eDh$Qyzbv1@C!F-;Sln=;I`fVfu;Kg- zRfCjw2P6POK)t`KgT$IH?=@@_fEL2}q6n=8QyHm{)BMWF`stw9;tC)Q&P`C5ubZrr z=Gyg6d4P6&FOGFPLpWokPVD>qK1r8m4$FtY6brt+IGc9$kp6>!$K_l`1dbt;6Oa^` z1ZT>aICJz0BPaBwlSU|Cu}w6?ja_7>A;;tGbyghJeJAdf)BTV(k&U4<`cCw^Ai$c(-Kh)076vm0i5re@!}9U zJCs25g+xhF7BWGO6wFq9Fw0R4B?>6=aooWPH91R01iVJoepqBDqBCiY_Z;|pnyWSf}67$O>T5V>tv>=!qXggcI2So=TH-Bl;bk0+zT$ zUSa$;UWnCQ4!qj~l(qt%A|{m%zg8$g0=>u}s~q$}i5DzWy53S6^Ngp-6DKDDiBVn| zgenz(S>|4ein<&{-a0BjrU82NOz!ta4HJz1ZgrCj=n)aB6`!m<#)8(gS-0$|#C7k{JiHxRySS z{M(h_ow`YV7M{AEM%*XdmjiQ=!-Uwjl83snK`7OlOcD-gZtx$Mv8UBW^b((5SBu&> z>nOur1R<$>dI~Is;8iZ&7_qH960#!-O5_b7QV~d_gU&~13`c~Tg4UzCmM+$4n33Ws zkp-a;gW)1*6-i`<1kjU7$#vGYHB_4i41}6yzA_nlO>{qnxmm0aPk*?#6|COMha!GZ zy_v0Esq(wQM?K#Ib7bL+B_5`ICEzUQy3z8ySKs`z359hb8FoUz5V$) z?|on>kr>Ei4v(;z{sGxY!Xrh-4a^pZg45RRyj-+&TaRDoO*|{7QaBA};*ne^8I&E} z4KI1>kTxRRq?l;GLGT zBe}1Cr}+~l)#HjSelUF!98$e#oa)@!N^rOM$q-~l8R_8_WpeC(`Tn^tI!f zb?#!YLKHnQJMa@)aKkKAAy;>&**|yB2G13WWmA!t+4C>0We5XXxUn1=K*8>$u*&J| zKULidsjLvLhdsixT}6Fa28l-68+Xgw2efCg8di>168D2c;YS{27tkY5?W*5spk#W= zbxk5MMuZYHi@edbM2&Q)$77$W8H%A=cApo&JK^w%86cOhhp z`OX+FS6~1L5nOY8kL{8fQL$0y5TSKS;KrK#yH_&-+!;Ih0$6TBGgwAQ_{It7AdjLv zb2sEom;fGjjA`pB5Bl=7GCg$?G@hrCF>|yUC*jXI>|w;bryr4uWHV=@J1jxvHkzlT*ORe$V%sUKcN6oO-IQ>aq=uvvTj_DUo~(NW z^H#Ml_Q~_BVkT#hfaI&c`sq3l?U~`W93ucBR+-g5El5^JY3rj#eHm+d7wbF!JgD6@0p+p^;=T(0B6A7tu7AC#&Jn@M zMj3jIrig1PCeI2__;~C%w55dhufs+?vsd(aYh{wPvHIUe*VOZ(*NcfG#1@<5eVZw8)aSr+?W zD`c>r1%o112?ogd1bs$-s=fiMb? zUWs=wuY|mg=xTe*4uNhjb1qK`f}*AerUPrJ^FVkfQ`&=9ga1;Ti0K5OXC3&j!^iRd z5jT^ZTg~OVB{P@8=~%l_W-}XYhx&M%U>u_ogs>%jv-QRiFg`y^MgSG8CurE(#(rQg2+! zJCydZlzFO)=>6uWR8kOO0!huhWEi|bbCMnRLzKudyFf;eKr76G_V;+E@omIgb#_XX z>MY8^@m)^vTv-J^ab)JT$L|U~0M6mKWwE!xJxawV z!m5L9deISV@0s@BqdT_c0REsu^V|I!mcSB!X~VDX+VQa^Qz#>zV3891EDl8H zUihOXKqvy)t|1uN8&5z%vaD-qsi0_xxf@WswxS*=14ZkE5#L7SbiNNnt_t6#S+SjNar)00p)JEt%`&ccYK%#TLY=UttZ@txr|j` zCnod{1-oWah3Z}>9a~?td75A$QQf&FOunbe6aZw6MNi@4jd(bNtP=GNYK|*f1k>&y z95K^MM&-;}GhECFrbZ?X#4;H`qXCQR`o1L_#!}!m!~&H;F)a@k_@`UZZGRn(9mQ&RFNmAx5@N3K=5*rR zJgmSeM7+)oCDkiKIRsm5#an3GUrQLpV%_5Iq@8>xc~~KeH%RKB@R$$i5z=(wNuB{U zXcUU%|9FN>>~l)=2?2%{Nv?XdaqWq@JV$D3)h=!E<88g1g^UF4z&LvURCVy>9=OU) z^05#A?SJWfydxZV>mL*mi4e{i-Jx(#IxdaLF=|(FcE9Ztk0Nnq78=8Th1)_g@0G81 z@&NOP#$lxlna9K|@$rhpgC7D!gBs(di02^{QSK@7Ag~$e8mv#145S%;_`%A3Wfq|z z=^^Rb8MK)xwGUFOYIx_a5Y6EgUY*p#*u|JB>N2S`zg#^BHr%r^|@TWsL`>$5mvBfrzOX0KF!_X?TXTD zw;(u~Hs9R}rvf7R_j`ySvVlxhv3Y|!?xY=HQ~E8Lgx`s)p{`iNiGis@^T`2Zx5L8Kz+Gcj0F zabxsHMPjX#WM%sD24g4`<1bL#dLQKkGks(P-^}lo**#-!USH(HvGSsRU{41sxL!?mIf=$9$DEazv|=SoKdrABA_AHl#4 z(fe)5douDKxi`_6C;(?@wg)zDxC<-?n4#;ii%gWW3o~vvTV0)zeI^|_PiQMxiU$1w zcdLy*jx!wj+63sNzxpI8EmP?=Fn?EsA_KcFw_V4rfqa=57sWEQg>34x_%m{}2ji5q zz3Sq6a7GH5&U|OWl;4SH`h^`Yxfu;NzwPHTD-N#HcDLG?GI0|RvR>Cx`Pw1skzl51$+NeCe z-r72de<52V3R&6{t5`sdt;u-I&W6@&b!)Oo?LqH7ar-w9^HM_F&Y(WZ8G{(Vtuma( zNvL)HE=+uisJNW>MIb0a?;~n^E^#wGD{NOBqW6PQ@D=VFp#YTP5$}<-+&*N>9{%~= zxhQ-?t!ub=6$`K=Wu%@%$c(0b*CaX6AQOnef|02XrmJZT^G50pJfO-~t7Y@A5Wyi3 z`Yx>K>K|c29nbo?=^%}gXfrck8w;Xik&;rZ>49b)H;k`3dlKNPJ-f?-V-ybOk{L$+ zn-%p_>4#jNav%WeN4f9D#c_rkRCYR_YMWWoe#gpbHLo!a^1O7H@i$3ZG4}c+*l%UM zKOKw_2uStR2is$m30u_@p2v>oS>BT#ATkoc=%=4_*gmNbd zb#}`0&}4)vkuc%cFp#Jrz6v1rdpJi0V$sj_(Bxp!=gR>JZ{sozIL~xEb3>mnFBETQ zr=~UcSNI^US_a>*v z2#0C0W;^9{u4q+s)_M0Gprgq)1+|9GQ5X4v!iRvz_(9CsPYcebASjjl)l&DQT6AZa zRtUa@sPM5)Ou`+IaL-{H(R31>%@vw5N z?zeY^MZf{H7~_a!chO|&K80@$L*~p&EYD+=_f!W$Ohh>M+UQZb*kN%nFv!fTQEcpV z0?d8`FnD@W;+YIkJW4|tWDNY#Ny+_5A8MM6rUYh9LyiL%FD>|=ndFs$RpSwCsfn1H z#F*Ai_qJ1F@lU8LTtH|CM2}$~lNxp6x43!snxdDmaA8Wu=&wjH?VVqh%SWPTI(Q1_ zPvMI)>h(Xlj0+w+GiAI17;qhTW!faK4Dr$kukUIzl*x#kx?fR1C!h~-rW8u@3xR*$xrD9ll|e(Uei!M3xLyAK zvCI*AAJo3(>k53R5?8VP^S`ZN+RB}d)A(;IUa?`T$FVB37(b*^(=^d`E7ZdbUL{&p z^rrv!^$35pznPa03nGiyz(1qLABHhKf(X^bwj&z#Eoi!?K~P+%qFg&rdr_ogj>KAC zz_7n=vRps2U*dV^A{Av*75|b?A(MinCOch8uVM1v(X5@7w)py#Mq7!t*kkQs*ezHn zSHIYz-#mtXwB1Ib)FS};DDM=eG_z31{5=en(6_g(hHvQceR=zXyQ#Y4F~`jb>#k59Mht0Qt~kL4=T0q zH6l^c>+hAE4&Q{}pUQ3Dc+IW zxx0Q1BXiV=q`Jp@5|ruIvMN>0$VA7{)iRVj+)hMIl<1l-M#n#;hU>}!`LvQ}1WR{QL$59u z@ZD5(enNj!Tl{EqZbtP8WE8e%zY=m&^qEgCcxN(Yz3JCi%h4ii$zT0Mre7oht7H}% zBOf{I30ihyPU7YxaTyw0b>^lw5QLe%SqaT)x-e3Te6lO-cxLiLwD|J)t<`*}9TY4l zDF2iP$*zIYt(9O;@95l+E31pY9J*sFw}Xy()jLri$G3wQD3v@g>fe;}R@e1rJf*@O zpLG+rKMe6lCCC0TijPIdwdPB zr1*ONKkB|}HUhg=Kb^FXE%h&Rl+X+1^2KOv=d1tzt+rgk@|!Zlo9+aUdk zofw2;=UVB+#tz((M8HtW=iW67MNz)+td@wMq!@KJqi8Wcuv$xY-T{PGg{1#DIui*I zUTu3>)Dl^7c@|HM&MQ2V(xbAN&S~d@0FN0G<<;@`lF`})=Rt`?f?mT|*nN-S!tP}- zo*zTYXd(XlbkkKwL-NYWsgC4CSm)q4gr5a~u3J~JyZMqsa$6bCW71A!RXW^;A0(r` zM|$zK{_?QqDb3M}Wafn*V2^o*)}dmZrkR~V&4?12o}0=K88O>hE{*`R!#?S2MLt8j?;0h}#XDq2ZJ*?uYo3t%~{6dUpr`7mxn50ZJZ7jbtXJ_{Ohs#$xlA`I_Oo8?ZKB9s3#$_-t&GMhDnk01 z-Uiv)A$0GP)r;XoLI7B$bp6JwV#m!xD9fr{rVrjoS(XWom(9UOXS z=F>@fW!9L7p#Z&YzKga<%Kvm+hA?`{aB9F4ln@I2`R^44ABxU`MPy$yr|K(E2kJTx)7tXc zWk^Aia>SaL``SiR+$|a(_t3|zxbwHc45zOY5sbNV{HNt>PSoX4!k9w+$QcDfuUg5b zElP5Py#9gTfw!=Wp4D?^+HJbt^Qb1f$QqHhi2?T%D3;oOh{=jkM)L-&z?ECgRtjq1 zenRRm6B_5yhSS>dAR6%DxblvoN)lZOD3{W&_Vy*2$9Z*7In4Ds*$@jM&i%AUo73V zz!}vODj=_+i72!X4nxX*$|$5G;k+XA$2`%D37UYq|NCvqE$rN|euQhfh0J7DYCuR& z5=;pi>KGE3`w|iKR}oc&EQJBr7q^w2G`Z~NS5+&{{X?vC-`OIuV^nji;ZWa?OeW{ArqxjsVwjzXI83ojI zU;k~o-|u%rA?tN4R;U<3TY0{~RPGkYUd(JL{^_UySxfTYJGCky0Y?PhD!5lli)1G` ze$^(Z7u1WDzTxJe1F*GwfoW3^{QGL94FiwMpJixer(IEi!1b()Ie{)Naoz&cicsV` zjQeS`gF|{QsF36F%LKlo7aQk1aD%3_$hwx9>}XCrwx-Crc0U6+uGkv9{m!Mkq43Oz z$mwM%)0;hjP<}LLN$}hiACcUNTLbiL_)ycqSh?Tak?DAH+IaTNbkDj(u-VT?V$}GY zd#x$8ohby>Yl@)=q}M5*L>X3y)Q6#v81{Hbr!wMqdqHp6AN(Z7k|B0c+rk-0%(+WT zA{|XQEP@~+ouVAP^@`Jbrti~)2>yAkb^wf#C8=(*0%t_6oGI{O>mhmRb3LQNek)&r zTaR=wvg~G=W1U`oXgopE2Sr~yTr!Zu^gUznM{L@DM0kRV9Bzu%S>2p{)& z{1~CRXqOQM3UByU7qo_j>2~aI$xQN9sl_=%G!Hd6BKlDL2GKYb5R|NXtwD;Ee|rai zxbz!P;Eje6@4M}9G29<5u`neP0auI?(ra83Mvg>>ureeV8tY1=vl$^yNPc=!b7?1w z@a?ffJgQYH{`PjVDd9+~;khy>Pz;HC?T(<_*C-BDR znuqH)t;QB_@ozHl*+^ZC|6M@aQCJ@WGaCA4%C4SGhbW@`v~V@s;cwMN-OkP7ObX@J z9M%ECAV9x-8vysA|3jLM`9#n;V@nz>|H$6)HxR8GHl;NPNR(Xd=v*sT+6}%HoV6FV zLAEc^ zWHlT!pxLNECb4O{U4PNt^zpBA>CI7pJ+fIG)14nL(l z705)hhdRG1c=I-xvt1WK$A@4#z|;6a?TS@=Ic6*;h|~q_SdEZ;Lu`|a1og~0z}6ksq(9Wvpr;*FCXvNVdnROz+)%QX*WrF>qQ-yyzTeN9GX(|C=-jHj zDOdGR0WbP~)Dc*je41h1R*Dz#)X#X&iDSM?r zIS+^$qMqw3np=@^p|n*iOz~^k@vGf3-FPN{kHsWQMr*nJ^v_|_lJ%habMzyxg)#*$ z;mvM=3QCk;Pi81FNJ_pPivoDATWYGHNP|_1P7-(GeE`4_^BuBJSL-i*j+`62>Z4Kr z5(Xx+iD+<*nB+JgtunrD;$uQvuRy6J#?rnl-iw8jTla5E)*nbd=%N1Cnh(MF6(J=_ z9$$02W_zqgKf<=6ZMNPL@ZfWitzf!&m>#a#5WNOs0B5qn<~@|fXKZip@KK)fL6h-szCrw5=Cr* z=iFCVK_!X^|4Ba%HnxR4f8((|HhO`N<-eWW)I z=gXcchy(npFt`!2B0@pD7#~VFYs}{I)WPd0E#%r_Hg>_;Ti3<^`>0X4$%2BOBwJFW z98&5dO#bVfU0P3L!eNImR-l~t7;T|cSltJVyOkXrpKsI0aTgV=)k}GU#-Uz){$=Z{ z@sv&3-Bn3zV&xCDVjC%J%k!$bgc_^KOHjELr0L-rwe=Kcy4xGiSH>|Rl5n(q;u1|` zG)Jkw0%U!gNE@c|GeJFes-z<(KWVT4#)S9r<|-T*o_8l4oUWh2b?%mHzXU*_`2x>O z*H7h^Q$*{QiZm~mvT>Zjh2;)aXaT)qkF!NshN|pGB}`tQQ4?V#@2#18l{M)&JAG{;%elkAG{>Ep3ivG2xlK55Q% zG3Fs!$I)D^_)HERl4DLFVSI!F5#xfq7Y3|7&8|$dt}WY68oN+YNnQOnHgyIWSOA0> z^gh-0%5h+P%u@MhKhWg!-t8ZhJI%WTkZ$nHa6zfGAJ{7SJ4hkjc=ONN_k8bvk|b9v zywIsNZc0E!9{NmVDL6A)rLY_x{+`>xHjl`i$l%nG7`wg;68PjV#vZuE)zeoLY3+Bqag3*SVZrz)c0 z60}eMfUs@4ly+{P4{G%Lf%8n`wa55INr8ib)c}^ZOo*yy&OEFO7x&|+_VH#A$^6Rr zspo_L1C3^qZXFlz)0<$BN@z3j?0YVi)hYnfbKGWamT<{8tx@9^_X4Vua9}Jh*4BBO z1Z-iJYSYf@WZKC0G@~Sp3}>esqZT6*c*`&oC`Ca>WnYgny*$BINcqc6H$`N^Mw^%D zYgR+Fj<0pH=Kv7SkE)=3^RW8uf3n*}xloHH0y_v+m-jyxRSb*aIe+}Bgvd*eS9|u7 zZ26NQ?Pxss`vGuEP)1O*m%jBCSi`B%XYI=euP%;Utc)Or>;BD`#mpb%!@nxir^Q@0 z<-bI4@0}~zMEPmcMtP0<4St*+my295_SQtzx6_bh%|@$F%}zm1C$;NS&+7~vH4QcwK8;pIc#c`P|BXUOi0rh@W5d%P$3ivGipGxyZ4h}xG0L? zqk{)_-7`G+76he8&pKnD>rw zMdj4TkP56iCEb26wW{&%bx7EGmv|$_oOn#keJy9N3~m;e|Ay z2LMfGBDYb!YAPW-D=eNIfq?HFA!D~hjNZ1Cs8}(TUlCbG(OdPHO@;H_7yHr45t0&T zdg|`!9l#!~9Tdmi>}cJ-yw&8@L(6^1<$qKI{s*zl`lyhw>3f#)VyTmLX=h$Puvyab zYHwjU;xe@e1QjM1RzFDY>w;yaEvDR)lrFnV-!{=_L}x%J&M2b&;wjspjjL?sH%B*G z4wZK(1i#?bajDz@{c2IK%^E9rKx3l-#C?<)tfJyV1^zTYD#LD5hpsxPDf4@Gmx(Sf ztsrPfdm>6IhZc7+UK3b2{}KPLUy4-^S1QOweu(fH;6qG8cY%Yz2uvIkn=v6VI}S|H zdp(ETwrI%@;((7%ez3YdIFY2TBo)^@l14mMShMM-Cn2ZM`7JU}AUp#{9(9#0($+F| z1xP+yw&xrI$RMJ>Q#3P=d@lUsx@fx?K875kImH~*5Dm5nKTpoi>EyuZ?L$QLe!p;5 z>g08S`Lg~uQZV9qwqq<6MZ|nX9oemMgx78R@89gEYU*2Um%x5iyb2Xo#9vGvuAkR~ z(2FecPAq=@+M1Epn$N!(f1TrnG67uzXEEh*h650Ax`CfO-{ zbS-W+{r)BPN?H4!`t1QT{OqD9tSZJ~#0f$-t;3f96=tDkY)E6WffZ?FD(Z=E)n}>| z4#TU3Kc8REsNkH3QUdZ_q4E?#>mk2~(ZkLm85&%B_WN_Ocy|vITQ1`Vjql1{!c%08 zidJ`u0}aHuo=)K?FD9->m(rez2_Ap!1PWc{EO=+`stkr0KEfEfZDb7Pc>~KUkHd+U#oGrN-PX+N2heUl%Yrn`2R%t zXfe6tO2)f*0VS8DMW+|F1uKY&uk*d|jxPI9!1?-1Co++tiXw8o-Y8H5tJ$t;@LWJJ z@JYC18%-MpR>G2s%Uzs*UNsLQHS<<#HVv3j*T!q{kWKtjaUUscl!G|1c3*1!n04^X zNTMXSlaid?sf=HVlfwvCqg2ZgG8{#{xV^Pa1EfvK`>KDY&g|De3=|UY&r7TL0*D5R z^J+S(Uv?x;&-UiUk_zhPzDfg)j)=FSvGAAS!@kRWM0b$K45Xss>)kM*y-XgtwAXSri+ z55_c=;FOU`EQj(1krK2z-(F?|82yQHcW-|-7>^-D8b=IVGZvT#Oqom{<@S$F` zW8=@vIra@cTRH>bJ$Bxpi#;7wIay$s#+DwpOM5LCzgoxe*Di`jnPP>a;YRN#cfcd@ z1C#o|NQn$_SHRx~UfXkZX$F@ox_&HT#F(FE-=jn=vk4?&I6eO_i7Iu?zIM*;&Yyy_ z%e={U)5J@pF;?EYswl9c1`qvIG1QkGS$LU@pw{7DomD+*?BLi;Y9IK^r-mKP7AQ8J zf`kW-t12*xYL|ZRelBVf>5Bv5h<~5`b$VH!`44CH4EHXq4&j%wp)Ripk{m4cB?3}- z_Bo4!JpkryO8Bnab#W!Le!fo)ex-Z-0Uz;6pP;W2SUz*ize6393hl&|vL+Owd}??W zetYVeu8puP&Sqo3_OxoL*~@x;g_`{j$PPSWG%U1Mm~CEddA%(R*FXhVBD455oJ00b zAec#SJ!<rIA`4Dz-HFmwzf_cw%{# zqF0VrWrj~L<=`*!t3Pq+pRk_Xom4rQ$sE5>7)5EDvE4T|)<%GE>UHY=Ww4K>ZAGa> zgcDJ6!I4&C7?r_ybKj*NK?Hak3R6bHn4tL&o&>26k7Z3#xAGX z)Yj`P)!~l&o-j*iA=EUhG5)q$4?~=!2kEO9_xY4c^E{H4y1%*ge#(j`f{G?>lSc?h z)d(z;j6GbaN7uJqs(bX=PC&a@tx$6!plHr#HZ05V;K{o1MMu_=Y$RSQvkHCJ)G1L&bl znW%3tn6N>KFv#;uJEMoR*}x1$fv1x(Zuo4SYOAIpotAQzxOsn{M-eTzHuV;euBb8H zTFLO^0{EvCx(jtp<3PqjV-ew>Bm@ApSsOy((bO`00`IFPv3J<`9=%Jsm$eD1NznqC zhlk#T_&;nUWe+&S+v*|Q&9jNMkRkoJIm2Qq7dFk=X5Zbs4u3OB4mUgDwusA!8p&t* zCV;EgjO}lXMNmcd^U7j(G-6-Jzk}B`9nbcHn&>>3;I!=v7MKQ^dAM9Bg(oOK)yJUb zjfFod7NjFv*S)!d!+8XSQHgpvl6bSYn2-I2EpIRM9VcZT_NJ274ciMpeRU%<+^HrC zw49qkxwNVi1EurXHnmjgcb^mtsg1L!d+K4+6+ET6rm!qSY90{4og|jjS72Ch2mu+}r*OlWRq@t#6gM z$ov3>fUYpxnFO!B%5YLAsj5)*(oYlImrKPcn5_L!)8FlHl?!sgv^#LYeu~f;%Eq3B8yBUhTViR$Nr~|QT2D98I zLr40&C=CBu&z}Oa+a~y>JE~mstW14{@ta}58{v>O{xKPyuA>cZDz50S^fD=>{#$YK zNGl-;dGq~g&{J!swVL^8(s!C-k3X-e=A;?4AES+I96DD}pA-P1!A(o2>+R=o*U(}z zdQB8OZviK6yEk6=_j7i-R$N*VU?SFSsB93HNWNw|H_vBArcFilRu{y|22ytw2PUd-MfK~OR?-<4dzg?L z{v{NoHgJka+*OL?Ye<@i>`sdQlSa%0qZ?IbKmbV2^NE*TnsEXRZvKFh_z)0*lnQ2( zq?C1D(%&!kNPTKTKooPFG|#dC2hofJ_BFw0$W81@Q;jG8_fLdK%Y6vfjASr zZ0Se_|DAOa^5hI!8^Pdj1|DGCxQa0~*W7M$IR*IqY`A%|)lFsO;+2^GUj#lW1{bXD zUa61&vcbbt83xLw_6FY|cev!ZsYTZ5N0upuAGn2341RIYC{5$>0ZT1@Lt6uz>;y^Q zEU({a8E{<&WxPoyC8-{Wm8;FLku1<5*mVdW8a@(GBLlk5IxKtW*DH8jk+*fColM(o zj1K0}ylwer3B>fXYv4NbvtnQPByy9ClzoG&^~l<^+kD$k>he!UD9)(Dx)7Io`_u7% z4m#`E~6n!_@nyR$0raa@#@*XF=Eb|nYQv1{d}8~gWYS^cZs_iHunVX3*eNcw7E zgrZ6|=lD+`r7ZpnJ6#d@BnEP6^u^tXXz9%DFzldL^;La&<#lu}5pOdKlc8!^Cpd}p z)NOXFDkc2RtK1txI6Wp#stl*Lz&6d~7Q5v40}rr-Vfy5D0Q+B6aPSBh0Q!t7eX(Dy zXp>ZksWMbTSD$axZe2z}c(9eTY$ucGXnWfjsRy!TmyEa^JWS^MWx7`VNmpje*y!z9 zx(w*m5RBG8r=+3k(~~H_^yI%QAy;9p{+kI~awc0!=OWz6B-?dvucD%t+BcL`p9qQj zK^s&ttEo(1LM~+nwsOb`&sGHm*K{EI3N6XKSj~#}zM5ge3N^24<)CK0rF(QOaRLly z3XXUZ4bgV*=oEs(=v+rN}-k^h2K%E{e*!*HB zMCC(pu3Avw4rt`T{DOw#5@3+5rYQToDq;cOhV%-*sl+X=^fs@mo{!PL_5)Tb`M$>r z)%5tEvwqv(yu4YT9TQ7>-{gSAvg`Ol=b7wtthy zbU@JPp}#`GS2X8HajM-XHTaUM;>& z6lQ^oN&t9;?k7BpfaPuQ@(JT{!zkl+?xPQ<5I8KSkTJ%p{uTMTX%VzzFO|PS0`1uu zlb8+MR6HSk4#Ar@Wf$^j&aXah^cE_m5-bSzW7$LHA

    `M8>h>T9UpW70pJ}{!e1h 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

      qCaZ_BO#EJE}oFo(?Z|w&f0H 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 literal 0 HcmV?d00001 diff --git a/loongarch_vars.bin b/loongarch_vars.bin new file mode 100644 index 0000000000000000000000000000000000000000..65bdb77af90b92dc268c0c5c70c054dee71599f4 GIT binary patch literal 389120 zcmeIuze+*@6bInbA98VUkd`K=h`TvRs~}|{)D)pZ4GBR@OHRsd5rT-OqN!Saf#@mf z2?AfC2k2hCx%LF|{e}bQoay(ily|GOxLK=3bfQv?`{XBo8r*dz B3V{Fs literal 0 HcmV?d00001 diff --git a/qemu-kvm.spec b/qemu-kvm.spec index a7ce6fa..da50836 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -55,7 +55,11 @@ %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 \ @@ -90,7 +94,7 @@ Epoch: 15 License: GPLv2 and GPLv2+ and CC-BY Group: Development/Tools URL: http://www.qemu.org/ -ExclusiveArch: x86_64 %{power64} aarch64 s390x +ExclusiveArch: x86_64 %{power64} aarch64 s390x loongarch64 Source0: http://wiki.qemu.org/download/qemu-6.2.0.tar.xz @@ -123,6 +127,8 @@ 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 @@ -359,6 +365,16 @@ Patch128: kvm-linux-aio-explain-why-max-batch-is-checked-in-laio_i.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 + BuildRequires: wget BuildRequires: rpm-build BuildRequires: ninja-build @@ -547,7 +563,7 @@ Requires(postun): systemd-units Requires: seabios-bin >= 1.10.2-1 Requires: sgabios-bin %endif -%ifnarch aarch64 s390x +%ifnarch aarch64 s390x loongarch64 Requires: seavgabios-bin >= 1.12.0-3 Requires: ipxe-roms-qemu >= 20170123-1 %endif @@ -686,6 +702,9 @@ 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} cp -f %{SOURCE37} tests/data/acpi/pc/SSDT.dimmpxm @@ -1154,6 +1173,8 @@ 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 @@ -1169,6 +1190,11 @@ 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 @@ -1270,10 +1296,12 @@ rm -rf $RPM_BUILD_ROOT%{qemudocdir}/specs popd %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 @@ -1394,6 +1422,10 @@ 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 @@ -1415,7 +1447,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} +%ifarch x86_64 %{power64} loongarch64 %{_libdir}/%{name}/hw-display-virtio-vga-gl.so %endif %{_libdir}/%{name}/accel-qtest-%{kvm_target}.so @@ -1508,7 +1540,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 +%ifarch x86_64 loongarch64 %{_libdir}/qemu-kvm/hw-display-qxl.so %endif %endif @@ -1526,8 +1558,9 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %changelog -* Thu Sep 15 2022 Jacob Wang - 6.2.0-11.0.1.5 -- Adjust limit for virtiofsd minor version +* Thu Sep 15 2022 Bo Ren - 6.2.0-11.0.1.5 +- Adjust limit for virtiofsd minor version (jacob.wang@openanolis.org) +- Add loongarch supporti (lixianglai@loongson.cn) * Mon Aug 29 2022 Jon Maloy - 6.2.0-11.el8_6.5 - kvm-linux-aio-fix-unbalanced-plugged-counter-in-laio_io_.patch [bz#2109570] -- Gitee

    hI^)cd=(ja+ZLc@t_so-0Z{BH9 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%0Dx>I}JdaouZ^+8ouz)5DddnTkZnR*QwPRO>E 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