diff --git a/0001-Add-Acpi-support.patch b/0001-Add-Acpi-support.patch deleted file mode 100644 index 101c3a43b23da4af913c04656cc8ccab673739d9..0000000000000000000000000000000000000000 --- a/0001-Add-Acpi-support.patch +++ /dev/null @@ -1,1348 +0,0 @@ -From 935f85c0025bbaaed976940ed0d57c23bfc68f94 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:11:23 -0400 -Subject: [PATCH 01/28] Add Acpi support. - -Change-Id: I208228b2178cddf365e97c6faf6111ef40e795eb -Signed-off-by: lixianglai ---- - hw/acpi/Kconfig | 8 + - hw/acpi/larch_7a.c | 600 +++++++++++++++++++++++++++++++++++++++++ - hw/acpi/ls7a.c | 598 ++++++++++++++++++++++++++++++++++++++++ - hw/acpi/meson.build | 1 + - include/hw/acpi/ls7a.h | 80 ++++++ - 5 files changed, 1287 insertions(+) - create mode 100644 hw/acpi/larch_7a.c - create mode 100644 hw/acpi/ls7a.c - create mode 100644 include/hw/acpi/ls7a.h - -diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig -index 622b0b50b..2f2fb33a7 100644 ---- a/hw/acpi/Kconfig -+++ b/hw/acpi/Kconfig -@@ -15,6 +15,14 @@ config ACPI_X86_ICH - bool - select ACPI_X86 - -+config ACPI_LOONGARCH -+ bool -+ select ACPI -+ select ACPI_CPU_HOTPLUG -+ select ACPI_MEMORY_HOTPLUG -+ select ACPI_PIIX4 -+ select ACPI_PCIHP -+ - config ACPI_CPU_HOTPLUG - bool - -diff --git a/hw/acpi/larch_7a.c b/hw/acpi/larch_7a.c -new file mode 100644 -index 000000000..35d4a7526 ---- /dev/null -+++ b/hw/acpi/larch_7a.c -@@ -0,0 +1,600 @@ -+#include "qemu/osdep.h" -+#include "sysemu/sysemu.h" -+#include "sysemu/runstate.h" -+#include "sysemu/reset.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/ls7a.h" -+#include "hw/nvram/fw_cfg.h" -+#include "qemu/config-file.h" -+#include "qapi/opts-visitor.h" -+#include "qapi/qapi-events-run-state.h" -+#include "qapi/error.h" -+#include "hw/loongarch/ls7a.h" -+#include "hw/mem/pc-dimm.h" -+#include "hw/mem/nvdimm.h" -+#include "migration/vmstate.h" -+ -+static void ls7a_pm_update_sci_fn(ACPIREGS *regs) -+{ -+ LS7APCIPMRegs *pm = container_of(regs, LS7APCIPMRegs, acpi_regs); -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static uint64_t ls7a_gpe_readb(void *opaque, hwaddr addr, unsigned width) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ return acpi_gpe_ioport_readb(&pm->acpi_regs, addr); -+} -+ -+static void ls7a_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static const MemoryRegionOps ls7a_gpe_ops = { -+ .read = ls7a_gpe_readb, -+ .write = ls7a_gpe_writeb, -+ .valid.min_access_size = 1, -+ .valid.max_access_size = 8, -+ .impl.min_access_size = 1, -+ .impl.max_access_size = 1, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+#define VMSTATE_GPE_ARRAY(_field, _state) \ -+ { \ -+ .name = (stringify(_field)), \ -+ .version_id = 0, \ -+ .num = ACPI_GPE0_LEN, \ -+ .info = &vmstate_info_uint8, \ -+ .size = sizeof(uint8_t), \ -+ .flags = VMS_ARRAY | VMS_POINTER, \ -+ .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ -+ } -+ -+static uint64_t ls7a_reset_readw(void *opaque, hwaddr addr, unsigned width) -+{ -+ return 0; -+} -+ -+static void ls7a_reset_writew(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ if (val & 1) { -+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); -+ return; -+ } -+} -+ -+static const MemoryRegionOps ls7a_reset_ops = { -+ .read = ls7a_reset_readw, -+ .write = ls7a_reset_writew, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static bool vmstate_test_use_memhp(void *opaque) -+{ -+ LS7APCIPMRegs *s = opaque; -+ return s->acpi_memory_hotplug.is_enabled; -+} -+ -+static const VMStateDescription vmstate_memhp_state = { -+ .name = "ls7a_pm/memhp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .needed = vmstate_test_use_memhp, -+ .fields = (VMStateField[]) { -+ VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const VMStateDescription vmstate_cpuhp_state = { -+ .name = "ls7a_pm/cpuhp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_CPU_HOTPLUG(cpuhp_state, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+const VMStateDescription vmstate_ls7a_pm = { -+ .name = "ls7a_pm", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT16(acpi_regs.pm1.evt.sts, LS7APCIPMRegs), -+ VMSTATE_UINT16(acpi_regs.pm1.evt.en, LS7APCIPMRegs), -+ VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, LS7APCIPMRegs), -+ VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, LS7APCIPMRegs), -+ VMSTATE_INT64(acpi_regs.tmr.overflow_time, LS7APCIPMRegs), -+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, LS7APCIPMRegs), -+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ }, -+ .subsections = (const VMStateDescription * []) { -+ &vmstate_memhp_state, -+ &vmstate_cpuhp_state, -+ NULL -+ } -+}; -+ -+static inline int64_t acpi_pm_tmr_get_clock(void) -+{ -+ return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY, -+ NANOSECONDS_PER_SECOND); -+} -+ -+static uint32_t acpi_pm_tmr_get(ACPIREGS *ar) -+{ -+ uint32_t d = acpi_pm_tmr_get_clock(); -+ return d & 0xffffff; -+} -+ -+static void acpi_pm_tmr_timer(void *opaque) -+{ -+ ACPIREGS *ar = opaque; -+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL); -+ ar->tmr.update_sci(ar); -+} -+ -+static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ return acpi_pm_tmr_get(opaque); -+} -+ -+static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ /* nothing */ -+} -+ -+static const MemoryRegionOps acpi_pm_tmr_ops = { -+ .read = acpi_pm_tmr_read, -+ .write = acpi_pm_tmr_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void ls7a_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, -+ MemoryRegion *parent, uint64_t offset) -+{ -+ ar->tmr.update_sci = update_sci; -+ ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar); -+ memory_region_init_io(&ar->tmr.io, memory_region_owner(parent), -+ &acpi_pm_tmr_ops, ar, "acpi-tmr", 4); -+ memory_region_add_subregion(parent, offset, &ar->tmr.io); -+} -+ -+static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) -+{ -+ uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar); -+ if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { -+ /* if TMRSTS is reset, then compute the new overflow time */ -+ acpi_pm_tmr_calc_overflow_time(ar); -+ } -+ ar->pm1.evt.sts &= ~val; -+} -+ -+static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ switch (addr) { -+ case 0: -+ return acpi_pm1_evt_get_sts(ar); -+ case 4: -+ return ar->pm1.evt.en; -+ default: -+ return 0; -+ } -+} -+ -+static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) -+{ -+ ar->pm1.evt.en = val; -+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, -+ val & ACPI_BITMASK_RT_CLOCK_ENABLE); -+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, -+ val & ACPI_BITMASK_TIMER_ENABLE); -+} -+ -+static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ switch (addr) { -+ case 0: -+ acpi_pm1_evt_write_sts(ar, val); -+ ar->pm1.evt.update_sci(ar); -+ break; -+ case 4: -+ acpi_pm1_evt_write_en(ar, val); -+ ar->pm1.evt.update_sci(ar); -+ break; -+ } -+} -+ -+static const MemoryRegionOps acpi_pm_evt_ops = { -+ .read = acpi_pm_evt_read, -+ .write = acpi_pm_evt_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void ls7a_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, -+ MemoryRegion *parent, uint64_t offset) -+{ -+ ar->pm1.evt.update_sci = update_sci; -+ memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent), -+ &acpi_pm_evt_ops, ar, "acpi-evt", 8); -+ memory_region_add_subregion(parent, offset, &ar->pm1.evt.io); -+} -+ -+static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ return ar->pm1.cnt.cnt; -+} -+ -+/* ACPI PM1aCNT */ -+static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) -+{ -+ ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); -+ if (val & ACPI_BITMASK_SLEEP_ENABLE) { -+ /* change suspend type */ -+ uint16_t sus_typ = (val >> 10) & 7; -+ switch (sus_typ) { -+ /* s3,s4 not support */ -+ case 5: -+ case 6: -+ warn_report("acpi s3,s4 state not support"); -+ break; -+ /* s5: soft off */ -+ case 7: -+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); -+ break; -+ default: -+ break; -+ } -+ } -+} -+ -+static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ acpi_pm1_cnt_write(opaque, val); -+} -+ -+static const MemoryRegionOps acpi_pm_cnt_ops = { -+ .read = acpi_pm_cnt_read, -+ .write = acpi_pm_cnt_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void acpi_notify_wakeup(Notifier *notifier, void *data) -+{ -+ ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup); -+ WakeupReason *reason = data; -+ -+ switch (*reason) { -+ case QEMU_WAKEUP_REASON_RTC: -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS); -+ break; -+ case QEMU_WAKEUP_REASON_PMTIMER: -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS); -+ break; -+ case QEMU_WAKEUP_REASON_OTHER: -+ /* ACPI_BITMASK_WAKE_STATUS should be set on resume. -+ * Pretend that resume was caused by power button */ -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void ls7a_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, -+ bool disable_s3, bool disable_s4, uint8_t s4_val, uint64_t offset) -+{ -+ FWCfgState *fw_cfg; -+ -+ ar->pm1.cnt.s4_val = s4_val; -+ ar->wakeup.notify = acpi_notify_wakeup; -+ qemu_register_wakeup_notifier(&ar->wakeup); -+ memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent), -+ &acpi_pm_cnt_ops, ar, "acpi-cnt", 4); -+ memory_region_add_subregion(parent, offset, &ar->pm1.cnt.io); -+ -+ fw_cfg = fw_cfg_find(); -+ if (fw_cfg) { -+ uint8_t suspend[6] = {128, 0, 0, 129, 128, 128}; -+ suspend[3] = 1 | ((!disable_s3) << 7); -+ suspend[4] = s4_val | ((!disable_s4) << 7); -+ fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6); -+ } -+} -+ -+static void ls7a_pm_reset(void *opaque) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ -+ acpi_pm1_evt_reset(&pm->acpi_regs); -+ acpi_pm1_cnt_reset(&pm->acpi_regs); -+ acpi_pm_tmr_reset(&pm->acpi_regs); -+ acpi_gpe_reset(&pm->acpi_regs); -+ -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static void pm_powerdown_req(Notifier *n, void *opaque) -+{ -+ LS7APCIPMRegs *pm = container_of(n, LS7APCIPMRegs, powerdown_notifier); -+ -+ acpi_pm1_evt_power_down(&pm->acpi_regs); -+} -+ -+void ls7a_pm_init(LS7APCIPMRegs *pm, qemu_irq *pic) -+{ -+ unsigned long base, gpe_len, acpi_aci_irq; -+ -+ /* ls7a board acpi hardware info, including -+ * acpi system io base address -+ * acpi gpe length -+ * acpi sci irq number -+ */ -+ base = ACPI_IO_BASE; -+ gpe_len = ACPI_GPE0_LEN; -+ acpi_aci_irq = ACPI_SCI_IRQ; -+ -+ pm->irq = pic[acpi_aci_irq - 64]; -+ memory_region_init(&pm->iomem, NULL, "ls7a_pm", ACPI_IO_SIZE); -+ memory_region_add_subregion(get_system_memory(), base, &pm->iomem); -+ -+ cpu_hotplug_hw_init(get_system_memory(), NULL, -+ &pm->cpuhp_state, CPU_HOTPLUG_BASE); -+ -+ ls7a_pm_tmr_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, LS7A_PM_TMR_BLK); -+ ls7a_pm1_evt_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, LS7A_PM_EVT_BLK); -+ ls7a_pm1_cnt_init(&pm->acpi_regs, &pm->iomem, false, false, 2, LS7A_PM_CNT_BLK); -+ -+ acpi_gpe_init(&pm->acpi_regs, gpe_len); -+ memory_region_init_io(&pm->iomem_gpe, NULL, &ls7a_gpe_ops, pm, -+ "acpi-gpe0", gpe_len); -+ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_STS_REG, &pm->iomem_gpe); -+ -+ memory_region_init_io(&pm->iomem_reset, NULL, &ls7a_reset_ops, pm, -+ "acpi-reset", 4); -+ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_RESET_REG, &pm->iomem_reset); -+ -+ qemu_register_reset(ls7a_pm_reset, pm); -+ -+ pm->powerdown_notifier.notify = pm_powerdown_req; -+ qemu_register_powerdown_notifier(&pm->powerdown_notifier); -+ -+ if (pm->acpi_memory_hotplug.is_enabled) { -+ acpi_memory_hotplug_init(get_system_memory(), NULL, -+ &pm->acpi_memory_hotplug, MEMORY_HOTPLUG_BASE); -+ } -+} -+ -+ -+static void ls7a_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ uint64_t value = ACPI_IO_BASE + LS7A_GPE0_STS_REG; -+ -+ visit_type_uint64(v, name, &value, errp); -+} -+ -+static bool ls7a_pm_get_memory_hotplug_support(Object *obj, Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ return ls7a->pm.acpi_memory_hotplug.is_enabled; -+} -+ -+static void ls7a_pm_set_memory_hotplug_support(Object *obj, bool value, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ ls7a->pm.acpi_memory_hotplug.is_enabled = value; -+} -+ -+static void ls7a_pm_get_disable_s3(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->disable_s3; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_disable_s3(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->disable_s3 = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void ls7a_pm_get_disable_s4(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->disable_s4; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_disable_s4(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->disable_s4 = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void ls7a_pm_get_s4_val(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->s4_val; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_s4_val(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->s4_val = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+void ls7a_pm_add_properties(Object *obj, LS7APCIPMRegs *pm, Error **errp) -+{ -+ static const uint32_t gpe0_len = ACPI_GPE0_LEN; -+ pm->acpi_memory_hotplug.is_enabled = true; -+ pm->disable_s3 = 0; -+ pm->disable_s4 = 0; -+ pm->s4_val = 2; -+ -+ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, -+ &pm->pm_io_base, OBJ_PROP_FLAG_READ); -+ object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", -+ ls7a_pm_get_gpe0_blk, -+ NULL, NULL, pm); -+ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, -+ &gpe0_len, OBJ_PROP_FLAG_READ); -+ object_property_add_bool(obj, "memory-hotplug-support", -+ ls7a_pm_get_memory_hotplug_support, -+ ls7a_pm_set_memory_hotplug_support); -+ object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8", -+ ls7a_pm_get_disable_s3, -+ ls7a_pm_set_disable_s3, -+ NULL, pm); -+ object_property_add(obj, ACPI_PM_PROP_S4_DISABLED, "uint8", -+ ls7a_pm_get_disable_s4, -+ ls7a_pm_set_disable_s4, -+ NULL, pm); -+ object_property_add(obj, ACPI_PM_PROP_S4_VAL, "uint8", -+ ls7a_pm_get_s4_val, -+ ls7a_pm_set_s4_val, -+ NULL, pm); -+} -+ -+void ls7a_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { -+ nvdimm_acpi_plug_cb(hotplug_dev, dev); -+ } else { -+ acpi_memory_plug_cb(hotplug_dev, &ls7a->pm.acpi_memory_hotplug, -+ dev, errp); -+ } -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_plug_cb(hotplug_dev, &ls7a->pm.cpuhp_state, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device plug request for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ acpi_memory_unplug_request_cb(hotplug_dev, -+ &ls7a->pm.acpi_memory_hotplug, dev, -+ errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_unplug_request_cb(hotplug_dev, &ls7a->pm.cpuhp_state, -+ dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug request for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ acpi_memory_unplug_cb(&ls7a->pm.acpi_memory_hotplug, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_unplug_cb(&ls7a->pm.cpuhp_state, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); -+ -+ acpi_memory_ospm_status(&ls7a->pm.acpi_memory_hotplug, list); -+ acpi_cpu_ospm_status(&ls7a->pm.cpuhp_state, list); -+} -+ -+void ls7a_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); -+ -+ acpi_send_gpe_event(&ls7a->pm.acpi_regs, ls7a->pm.irq, ev); -+} -+ -+ -+ -diff --git a/hw/acpi/ls7a.c b/hw/acpi/ls7a.c -new file mode 100644 -index 000000000..2de50ccb9 ---- /dev/null -+++ b/hw/acpi/ls7a.c -@@ -0,0 +1,598 @@ -+#include "qemu/osdep.h" -+#include "sysemu/sysemu.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/ls7a.h" -+#include "hw/nvram/fw_cfg.h" -+#include "qemu/config-file.h" -+#include "qapi/opts-visitor.h" -+#include "qapi/qapi-events-run-state.h" -+#include "qapi/error.h" -+#include "hw/mips/ls7a.h" -+#include "hw/mem/pc-dimm.h" -+#include "hw/mem/nvdimm.h" -+ -+static void ls7a_pm_update_sci_fn(ACPIREGS *regs) -+{ -+ LS7APCIPMRegs *pm = container_of(regs, LS7APCIPMRegs, acpi_regs); -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static uint64_t ls7a_gpe_readb(void *opaque, hwaddr addr, unsigned width) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ return acpi_gpe_ioport_readb(&pm->acpi_regs, addr); -+} -+ -+static void ls7a_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static const MemoryRegionOps ls7a_gpe_ops = { -+ .read = ls7a_gpe_readb, -+ .write = ls7a_gpe_writeb, -+ .valid.min_access_size = 1, -+ .valid.max_access_size = 8, -+ .impl.min_access_size = 1, -+ .impl.max_access_size = 1, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+#define VMSTATE_GPE_ARRAY(_field, _state) \ -+ { \ -+ .name = (stringify(_field)), \ -+ .version_id = 0, \ -+ .num = ACPI_GPE0_LEN, \ -+ .info = &vmstate_info_uint8, \ -+ .size = sizeof(uint8_t), \ -+ .flags = VMS_ARRAY | VMS_POINTER, \ -+ .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ -+ } -+ -+static uint64_t ls7a_reset_readw(void *opaque, hwaddr addr, unsigned width) -+{ -+ return 0; -+} -+ -+static void ls7a_reset_writew(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ if (val & 1) { -+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); -+ return; -+ } -+} -+ -+static const MemoryRegionOps ls7a_reset_ops = { -+ .read = ls7a_reset_readw, -+ .write = ls7a_reset_writew, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static bool vmstate_test_use_memhp(void *opaque) -+{ -+ LS7APCIPMRegs *s = opaque; -+ return s->acpi_memory_hotplug.is_enabled; -+} -+ -+static const VMStateDescription vmstate_memhp_state = { -+ .name = "ls7a_pm/memhp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .needed = vmstate_test_use_memhp, -+ .fields = (VMStateField[]) { -+ VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const VMStateDescription vmstate_cpuhp_state = { -+ .name = "ls7a_pm/cpuhp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_CPU_HOTPLUG(cpuhp_state, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+const VMStateDescription vmstate_ls7a_pm = { -+ .name = "ls7a_pm", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT16(acpi_regs.pm1.evt.sts, LS7APCIPMRegs), -+ VMSTATE_UINT16(acpi_regs.pm1.evt.en, LS7APCIPMRegs), -+ VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, LS7APCIPMRegs), -+ VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, LS7APCIPMRegs), -+ VMSTATE_INT64(acpi_regs.tmr.overflow_time, LS7APCIPMRegs), -+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, LS7APCIPMRegs), -+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, LS7APCIPMRegs), -+ VMSTATE_END_OF_LIST() -+ }, -+ .subsections = (const VMStateDescription * []) { -+ &vmstate_memhp_state, -+ &vmstate_cpuhp_state, -+ NULL -+ } -+}; -+ -+static inline int64_t acpi_pm_tmr_get_clock(void) -+{ -+ return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY, -+ NANOSECONDS_PER_SECOND); -+} -+ -+static uint32_t acpi_pm_tmr_get(ACPIREGS *ar) -+{ -+ uint32_t d = acpi_pm_tmr_get_clock(); -+ return d & 0xffffff; -+} -+ -+static void acpi_pm_tmr_timer(void *opaque) -+{ -+ ACPIREGS *ar = opaque; -+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL); -+ ar->tmr.update_sci(ar); -+} -+ -+static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ return acpi_pm_tmr_get(opaque); -+} -+ -+static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ /* nothing */ -+} -+ -+static const MemoryRegionOps acpi_pm_tmr_ops = { -+ .read = acpi_pm_tmr_read, -+ .write = acpi_pm_tmr_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void ls7a_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, -+ MemoryRegion *parent, uint64_t offset) -+{ -+ ar->tmr.update_sci = update_sci; -+ ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar); -+ memory_region_init_io(&ar->tmr.io, memory_region_owner(parent), -+ &acpi_pm_tmr_ops, ar, "acpi-tmr", 4); -+ memory_region_add_subregion(parent, offset, &ar->tmr.io); -+} -+ -+static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) -+{ -+ uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar); -+ if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { -+ /* if TMRSTS is reset, then compute the new overflow time */ -+ acpi_pm_tmr_calc_overflow_time(ar); -+ } -+ ar->pm1.evt.sts &= ~val; -+} -+ -+static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ switch (addr) { -+ case 0: -+ return acpi_pm1_evt_get_sts(ar); -+ case 4: -+ return ar->pm1.evt.en; -+ default: -+ return 0; -+ } -+} -+ -+static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) -+{ -+ ar->pm1.evt.en = val; -+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, -+ val & ACPI_BITMASK_RT_CLOCK_ENABLE); -+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, -+ val & ACPI_BITMASK_TIMER_ENABLE); -+} -+ -+static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ switch (addr) { -+ case 0: -+ acpi_pm1_evt_write_sts(ar, val); -+ ar->pm1.evt.update_sci(ar); -+ break; -+ case 4: -+ acpi_pm1_evt_write_en(ar, val); -+ ar->pm1.evt.update_sci(ar); -+ break; -+ } -+} -+ -+static const MemoryRegionOps acpi_pm_evt_ops = { -+ .read = acpi_pm_evt_read, -+ .write = acpi_pm_evt_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void ls7a_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, -+ MemoryRegion *parent, uint64_t offset) -+{ -+ ar->pm1.evt.update_sci = update_sci; -+ memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent), -+ &acpi_pm_evt_ops, ar, "acpi-evt", 8); -+ memory_region_add_subregion(parent, offset, &ar->pm1.evt.io); -+} -+ -+static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) -+{ -+ ACPIREGS *ar = opaque; -+ return ar->pm1.cnt.cnt; -+} -+ -+/* ACPI PM1aCNT */ -+static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) -+{ -+ ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); -+ -+ if (val & ACPI_BITMASK_SLEEP_ENABLE) { -+ /* change suspend type */ -+ uint16_t sus_typ = (val >> 10) & 7; -+ switch (sus_typ) { -+ case 0: /* soft power off */ -+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); -+ break; -+ case 1: -+ qemu_system_suspend_request(); -+ break; -+ default: -+ if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */ -+ qapi_event_send_suspend_disk(); -+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); -+ } -+ break; -+ } -+ } -+} -+ -+static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, -+ unsigned width) -+{ -+ acpi_pm1_cnt_write(opaque, val); -+} -+ -+static const MemoryRegionOps acpi_pm_cnt_ops = { -+ .read = acpi_pm_cnt_read, -+ .write = acpi_pm_cnt_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static void acpi_notify_wakeup(Notifier *notifier, void *data) -+{ -+ ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup); -+ WakeupReason *reason = data; -+ -+ switch (*reason) { -+ case QEMU_WAKEUP_REASON_RTC: -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS); -+ break; -+ case QEMU_WAKEUP_REASON_PMTIMER: -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS); -+ break; -+ case QEMU_WAKEUP_REASON_OTHER: -+ /* ACPI_BITMASK_WAKE_STATUS should be set on resume. -+ * Pretend that resume was caused by power button */ -+ ar->pm1.evt.sts |= -+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void ls7a_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, -+ bool disable_s3, bool disable_s4, uint8_t s4_val, uint64_t offset) -+{ -+ FWCfgState *fw_cfg; -+ -+ ar->pm1.cnt.s4_val = s4_val; -+ ar->wakeup.notify = acpi_notify_wakeup; -+ qemu_register_wakeup_notifier(&ar->wakeup); -+ memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent), -+ &acpi_pm_cnt_ops, ar, "acpi-cnt", 4); -+ memory_region_add_subregion(parent, offset, &ar->pm1.cnt.io); -+ -+ fw_cfg = fw_cfg_find(); -+ if (fw_cfg) { -+ uint8_t suspend[6] = {128, 0, 0, 129, 128, 128}; -+ suspend[3] = 1 | ((!disable_s3) << 7); -+ suspend[4] = s4_val | ((!disable_s4) << 7); -+ fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6); -+ } -+} -+ -+static void ls7a_pm_reset(void *opaque) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ -+ acpi_pm1_evt_reset(&pm->acpi_regs); -+ acpi_pm1_cnt_reset(&pm->acpi_regs); -+ acpi_pm_tmr_reset(&pm->acpi_regs); -+ acpi_gpe_reset(&pm->acpi_regs); -+ -+ acpi_update_sci(&pm->acpi_regs, pm->irq); -+} -+ -+static void pm_powerdown_req(Notifier *n, void *opaque) -+{ -+ LS7APCIPMRegs *pm = container_of(n, LS7APCIPMRegs, powerdown_notifier); -+ -+ acpi_pm1_evt_power_down(&pm->acpi_regs); -+} -+ -+void ls7a_pm_init(LS7APCIPMRegs *pm, qemu_irq *pic) -+{ -+ unsigned long base, gpe_len, acpi_aci_irq; -+ -+ /* ls7a board acpi hardware info, including -+ * acpi system io base address -+ * acpi gpe length -+ * acpi sci irq number -+ */ -+ base = ACPI_IO_BASE; -+ gpe_len = ACPI_GPE0_LEN; -+ acpi_aci_irq = ACPI_SCI_IRQ; -+ -+ pm->irq = pic[acpi_aci_irq - 64]; -+ memory_region_init(&pm->iomem, NULL, "ls7a_pm", ACPI_IO_SIZE); -+ memory_region_add_subregion(get_system_memory(), base, &pm->iomem); -+ -+ cpu_hotplug_hw_init(get_system_memory(), NULL, &pm->cpuhp_state, CPU_HOTPLUG_BASE); -+ -+ ls7a_pm_tmr_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, LS7A_PM_TMR_BLK); -+ ls7a_pm1_evt_init(&pm->acpi_regs, ls7a_pm_update_sci_fn, &pm->iomem, LS7A_PM_EVT_BLK); -+ ls7a_pm1_cnt_init(&pm->acpi_regs, &pm->iomem, false, false, 2, LS7A_PM_CNT_BLK); -+ -+ acpi_gpe_init(&pm->acpi_regs, gpe_len); -+ memory_region_init_io(&pm->iomem_gpe, NULL, &ls7a_gpe_ops, pm, -+ "acpi-gpe0", gpe_len); -+ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_STS_REG, &pm->iomem_gpe); -+ -+ memory_region_init_io(&pm->iomem_reset, NULL, &ls7a_reset_ops, pm, -+ "acpi-reset", 4); -+ memory_region_add_subregion(&pm->iomem, LS7A_GPE0_RESET_REG, &pm->iomem_reset); -+ -+ qemu_register_reset(ls7a_pm_reset, pm); -+ -+ pm->powerdown_notifier.notify = pm_powerdown_req; -+ qemu_register_powerdown_notifier(&pm->powerdown_notifier); -+ -+ if (pm->acpi_memory_hotplug.is_enabled) { -+ acpi_memory_hotplug_init(get_system_memory(), NULL, -+ &pm->acpi_memory_hotplug, MEMORY_HOTPLUG_BASE); -+ } -+} -+ -+ -+static void ls7a_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ uint64_t value = ACPI_IO_BASE + LS7A_GPE0_STS_REG; -+ -+ visit_type_uint64(v, name, &value, errp); -+} -+ -+static bool ls7a_pm_get_memory_hotplug_support(Object *obj, Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ return ls7a->pm.acpi_memory_hotplug.is_enabled; -+} -+ -+static void ls7a_pm_set_memory_hotplug_support(Object *obj, bool value, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ ls7a->pm.acpi_memory_hotplug.is_enabled = value; -+} -+ -+static void ls7a_pm_get_disable_s3(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->disable_s3; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_disable_s3(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->disable_s3 = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void ls7a_pm_get_disable_s4(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->disable_s4; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_disable_s4(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->disable_s4 = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void ls7a_pm_get_s4_val(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ uint8_t value = pm->s4_val; -+ -+ visit_type_uint8(v, name, &value, errp); -+} -+ -+static void ls7a_pm_set_s4_val(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LS7APCIPMRegs *pm = opaque; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_uint8(v, name, &value, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ pm->s4_val = value; -+out: -+ error_propagate(errp, local_err); -+} -+ -+void ls7a_pm_add_properties(Object *obj, LS7APCIPMRegs *pm, Error **errp) -+{ -+ static const uint32_t gpe0_len = ACPI_GPE0_LEN; -+ pm->acpi_memory_hotplug.is_enabled = true; -+ pm->disable_s3 = 0; -+ pm->disable_s4 = 0; -+ pm->s4_val = 2; -+ -+ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, -+ &pm->pm_io_base, OBJ_PROP_FLAG_READ); -+ object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", -+ ls7a_pm_get_gpe0_blk, -+ NULL, NULL, pm); -+ object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, -+ &gpe0_len, OBJ_PROP_FLAG_READ); -+ object_property_add_bool(obj, "memory-hotplug-support", -+ ls7a_pm_get_memory_hotplug_support, -+ ls7a_pm_set_memory_hotplug_support); -+ object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8", -+ ls7a_pm_get_disable_s3, -+ ls7a_pm_set_disable_s3, -+ NULL, pm); -+ object_property_add(obj, ACPI_PM_PROP_S4_DISABLED, "uint8", -+ ls7a_pm_get_disable_s4, -+ ls7a_pm_set_disable_s4, -+ NULL, pm); -+ object_property_add(obj, ACPI_PM_PROP_S4_VAL, "uint8", -+ ls7a_pm_get_s4_val, -+ ls7a_pm_set_s4_val, -+ NULL, pm); -+} -+ -+void ls7a_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { -+ nvdimm_acpi_plug_cb(hotplug_dev, dev); -+ } else { -+ acpi_memory_plug_cb(hotplug_dev, &ls7a->pm.acpi_memory_hotplug, -+ dev, errp); -+ } -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_plug_cb(hotplug_dev, &ls7a->pm.cpuhp_state, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device plug request for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ acpi_memory_unplug_request_cb(hotplug_dev, -+ &ls7a->pm.acpi_memory_hotplug, dev, -+ errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_unplug_request_cb(hotplug_dev, &ls7a->pm.cpuhp_state, -+ dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug request for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(hotplug_dev)); -+ -+ if (ls7a->pm.acpi_memory_hotplug.is_enabled && -+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ acpi_memory_unplug_cb(&ls7a->pm.acpi_memory_hotplug, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { -+ acpi_cpu_unplug_cb(&ls7a->pm.cpuhp_state, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+} -+ -+void ls7a_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); -+ -+ acpi_memory_ospm_status(&ls7a->pm.acpi_memory_hotplug, list); -+ acpi_cpu_ospm_status(&ls7a->pm.cpuhp_state, list); -+} -+ -+void ls7a_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(OBJECT(adev)); -+ -+ acpi_send_gpe_event(&ls7a->pm.acpi_regs, ls7a->pm.irq, ev); -+} -+ -+ -+ -diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build -index adf6347bc..5fe4cfa4f 100644 ---- a/hw/acpi/meson.build -+++ b/hw/acpi/meson.build -@@ -6,6 +6,7 @@ acpi_ss.add(files( - 'core.c', - 'utils.c', - )) -+acpi_ss.add(when: 'CONFIG_ACPI_LOONGARCH', if_true: files('larch_7a.c')) - acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_true: files('cpu.c', 'cpu_hotplug.c')) - acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_false: files('acpi-cpu-hotplug-stub.c')) - acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_true: files('memory_hotplug.c')) -diff --git a/include/hw/acpi/ls7a.h b/include/hw/acpi/ls7a.h -new file mode 100644 -index 000000000..4401515c7 ---- /dev/null -+++ b/include/hw/acpi/ls7a.h -@@ -0,0 +1,80 @@ -+/* -+ * QEMU GMCH/LS7A PCI PM Emulation -+ * -+ * Copyright (c) 2009 Isaku Yamahata -+ * VA Linux Systems Japan K.K. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see -+ */ -+ -+#ifndef HW_ACPI_LS7A_H -+#define HW_ACPI_LS7A_H -+ -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/cpu_hotplug.h" -+#include "hw/acpi/cpu.h" -+#include "hw/acpi/memory_hotplug.h" -+#include "hw/acpi/acpi_dev_interface.h" -+#include "hw/acpi/tco.h" -+ -+#define CPU_HOTPLUG_BASE 0x1e000000 -+#define MEMORY_HOTPLUG_BASE 0x1e00000c -+ -+typedef struct LS7APCIPMRegs { -+ /* -+ * In ls7a spec says that pm1_cnt register is 32bit width and -+ * that the upper 16bits are reserved and unused. -+ * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t. -+ */ -+ ACPIREGS acpi_regs; -+ -+ MemoryRegion iomem; -+ MemoryRegion iomem_gpe; -+ MemoryRegion iomem_smi; -+ MemoryRegion iomem_reset; -+ -+ qemu_irq irq; /* SCI */ -+ -+ uint32_t pm_io_base; -+ Notifier powerdown_notifier; -+ -+ bool cpu_hotplug_legacy; -+ AcpiCpuHotplug gpe_cpu; -+ CPUHotplugState cpuhp_state; -+ -+ MemHotplugState acpi_memory_hotplug; -+ -+ uint8_t disable_s3; -+ uint8_t disable_s4; -+ uint8_t s4_val; -+} LS7APCIPMRegs; -+ -+void ls7a_pm_init(LS7APCIPMRegs *ls7a, qemu_irq *sci_irq); -+ -+void ls7a_pm_iospace_update(LS7APCIPMRegs *pm, uint32_t pm_io_base); -+extern const VMStateDescription vmstate_ls7a_pm; -+ -+void ls7a_pm_add_properties(Object *obj, LS7APCIPMRegs *pm, Error **errp); -+ -+void ls7a_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp); -+void ls7a_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+void ls7a_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp); -+ -+void ls7a_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); -+ -+void ls7a_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev); -+#endif /* HW_ACPI_LS7A_H */ --- -2.43.5 - diff --git a/0001-anolis-csv-i386-add-CSV-context.patch b/0001-anolis-csv-i386-add-CSV-context.patch deleted file mode 100644 index 89e3d493cab8965bf56d9d2356d5b12b25ed98ba..0000000000000000000000000000000000000000 --- a/0001-anolis-csv-i386-add-CSV-context.patch +++ /dev/null @@ -1,205 +0,0 @@ -From fda324e163898d543e215cfec1aa3d26ba816426 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Tue, 24 Aug 2021 14:57:28 +0800 -Subject: [PATCH 1/8] anolis: csv/i386: add CSV context - -CSV is the secure virtualization feature on Hygon CPU. -It is compatible with the AMD SEV/SEV-ES and extends out -specific funtionality by setting bit 6 of guest policy. - -Add the context and the build option. - -Change-Id: I02b48c779dd25ddda4546fe3e28c1fe0c8c2e4c6 -Signed-off-by: Xin Jiang ---- - configs/devices/i386-softmmu/default.mak | 1 + - .../x86_64-softmmu/x86_64-rh-devices.mak | 1 + - hw/i386/Kconfig | 5 ++ - target/i386/csv-sysemu-stub.c | 16 ++++++ - target/i386/csv.c | 51 +++++++++++++++++++ - target/i386/csv.h | 35 +++++++++++++ - target/i386/meson.build | 1 + - 7 files changed, 110 insertions(+) - create mode 100644 target/i386/csv-sysemu-stub.c - create mode 100644 target/i386/csv.c - create mode 100644 target/i386/csv.h - -diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak -index 598c6646df..db83ffcab9 100644 ---- a/configs/devices/i386-softmmu/default.mak -+++ b/configs/devices/i386-softmmu/default.mak -@@ -23,6 +23,7 @@ - #CONFIG_TPM_TIS_ISA=n - #CONFIG_VTD=n - #CONFIG_SGX=n -+#CONFIG_CSV=n - - # Boards: - # -diff --git a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak -index 31ce08edab..ee1df7aa52 100644 ---- a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak -+++ b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak -@@ -102,3 +102,4 @@ CONFIG_TPM_TIS_ISA=y - CONFIG_TPM_EMULATOR=y - CONFIG_TPM_PASSTHROUGH=y - CONFIG_SGX=y -+CONFIG_CSV=y -diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig -index d22ac4a4b9..ed35d762b3 100644 ---- a/hw/i386/Kconfig -+++ b/hw/i386/Kconfig -@@ -10,6 +10,10 @@ config SGX - bool - depends on KVM - -+config CSV -+ bool -+ depends on SEV -+ - config PC - bool - imply APPLESMC -@@ -26,6 +30,7 @@ config PC - imply QXL - imply SEV - imply SGX -+ imply CSV - imply SGA - imply TEST_DEVICES - imply TPM_CRB -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -new file mode 100644 -index 0000000000..a89b2600e7 ---- /dev/null -+++ b/target/i386/csv-sysemu-stub.c -@@ -0,0 +1,16 @@ -+/* -+ * QEMU CSV support -+ * -+ * Copyright: Hygon Info Technologies Ltd. 2022 -+ * -+ * Author: -+ * Jiang Xin -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include "sev.h" -+#include "csv.h" -diff --git a/target/i386/csv.c b/target/i386/csv.c -new file mode 100644 -index 0000000000..aac825d3f9 ---- /dev/null -+++ b/target/i386/csv.c -@@ -0,0 +1,51 @@ -+/* -+ * QEMU CSV support -+ * -+ * Copyright: Hygon Info Technologies Ltd. 2022 -+ * -+ * Author: -+ * Jiang Xin -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ */ -+ -+#include "qemu/osdep.h" -+ -+#include "cpu.h" -+#include "sev.h" -+#include "csv.h" -+ -+CsvGuestState csv_guest = { 0 }; -+ -+#define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ -+#define CPUID_VENDOR_HYGON_ECX 0x656e6975 /* "uine" */ -+#define CPUID_VENDOR_HYGON_EDX 0x6e65476e /* "nGen" */ -+ -+#define GUEST_POLICY_CSV_BIT (1 << 6) -+ -+static bool is_hygon_cpu(void) -+{ -+ uint32_t ebx = 0; -+ uint32_t ecx = 0; -+ uint32_t edx = 0; -+ -+ host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); -+ -+ if (ebx == CPUID_VENDOR_HYGON_EBX && -+ ecx == CPUID_VENDOR_HYGON_ECX && -+ edx == CPUID_VENDOR_HYGON_EDX) -+ return true; -+ else -+ return false; -+} -+ -+bool -+csv_enabled(void) -+{ -+ if (!is_hygon_cpu()) -+ return false; -+ -+ return sev_es_enabled() && (csv_guest.policy & GUEST_POLICY_CSV_BIT); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -new file mode 100644 -index 0000000000..057d37d975 ---- /dev/null -+++ b/target/i386/csv.h -@@ -0,0 +1,35 @@ -+/* -+ * QEMU CSV support -+ * -+ * Copyright: Hygon Info Technologies Ltd. 2022 -+ * -+ * Author: -+ * Jiang Xin -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ */ -+ -+#ifndef QEMU_CSV_H -+#define QEMU_CSV_H -+ -+#include "qapi/qapi-commands-misc-target.h" -+ -+#ifdef CONFIG_CSV -+bool csv_enabled(void); -+#else -+#define csv_enabled() 0 -+#endif -+ -+struct CsvGuestState { -+ uint32_t policy; -+ int sev_fd; -+ void *state; -+}; -+ -+typedef struct CsvGuestState CsvGuestState; -+ -+extern struct CsvGuestState csv_guest; -+ -+#endif -diff --git a/target/i386/meson.build b/target/i386/meson.build -index ae38dc9563..361dea9290 100644 ---- a/target/i386/meson.build -+++ b/target/i386/meson.build -@@ -21,6 +21,7 @@ i386_softmmu_ss.add(files( - 'cpu-sysemu.c', - )) - i386_softmmu_ss.add(when: 'CONFIG_SEV', if_true: files('sev.c'), if_false: files('sev-sysemu-stub.c')) -+i386_softmmu_ss.add(when: 'CONFIG_CSV', if_true: files('csv.c'), if_false: files('csv-sysemu-stub.c')) - - i386_user_ss = ss.source_set() - --- -2.17.1 - diff --git a/0002-Support-rtc.patch b/0002-Support-rtc.patch deleted file mode 100644 index 989778e8f185a754e2cb087bdd3c7066f6c72195..0000000000000000000000000000000000000000 --- a/0002-Support-rtc.patch +++ /dev/null @@ -1,370 +0,0 @@ -From e0a8c8cb06e866bd334501d637e7219a14ae601b Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:15:49 -0400 -Subject: [PATCH 02/28] Support rtc. - -Change-Id: Idd50274dd2a6c00b21ec0cd099f8d115ab4fa449 -Signed-off-by: lixianglai ---- - hw/timer/Kconfig | 2 + - hw/timer/ls7a_rtc.c | 325 +++++++++++++++++++++++++++++++++++++++++++ - hw/timer/meson.build | 1 + - 3 files changed, 328 insertions(+) - create mode 100644 hw/timer/ls7a_rtc.c - -diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig -index 010be7ed1..b395c72d7 100644 ---- a/hw/timer/Kconfig -+++ b/hw/timer/Kconfig -@@ -60,3 +60,5 @@ config STELLARIS_GPTM - - config AVR_TIMER16 - bool -+config LS7A_RTC -+ bool -diff --git a/hw/timer/ls7a_rtc.c b/hw/timer/ls7a_rtc.c -new file mode 100644 -index 000000000..756f2fc9c ---- /dev/null -+++ b/hw/timer/ls7a_rtc.c -@@ -0,0 +1,325 @@ -+#include "qemu/osdep.h" -+#include "hw/sysbus.h" -+#include "hw/irq.h" -+#include "include/hw/register.h" -+#include "qemu/timer.h" -+#include "sysemu/sysemu.h" -+#include "qemu/cutils.h" -+#include "qemu/log.h" -+#include "qemu-common.h" -+#include "migration/vmstate.h" -+ -+#ifdef DEBUG_LS7A_RTC -+#define DPRINTF (fmt, ...) \ -+do { printf("ls7a_rtc: " fmt , ## __VA_ARGS__); } while (0) -+#else -+#define DPRINTF (fmt, ...) do {} while (0) -+#endif -+ -+ -+#define SYS_TOYTRIM 0x20 -+#define SYS_TOYWRITE0 0x24 -+#define SYS_TOYWRITE1 0x28 -+#define SYS_TOYREAD0 0x2C -+#define SYS_TOYREAD1 0x30 -+#define SYS_TOYMATCH0 0x34 -+#define SYS_TOYMATCH1 0x38 -+#define SYS_TOYMATCH2 0x3C -+#define SYS_RTCCTRL 0x40 -+#define SYS_RTCTRIM 0x60 -+#define SYS_RTCWRTIE0 0x64 -+#define SYS_RTCREAD0 0x68 -+#define SYS_RTCMATCH0 0x6C -+#define SYS_RTCMATCH1 0x70 -+#define SYS_RTCMATCH2 0x74 -+ -+/** -+ ** shift bits and filed mask -+ **/ -+#define TOY_MON_MASK 0x3f -+#define TOY_DAY_MASK 0x1f -+#define TOY_HOUR_MASK 0x1f -+#define TOY_MIN_MASK 0x3f -+#define TOY_SEC_MASK 0x3f -+#define TOY_MSEC_MASK 0xf -+ -+#define TOY_MON_SHIFT 26 -+#define TOY_DAY_SHIFT 21 -+#define TOY_HOUR_SHIFT 16 -+#define TOY_MIN_SHIFT 10 -+#define TOY_SEC_SHIFT 4 -+#define TOY_MSEC_SHIFT 0 -+ -+#define TOY_MATCH_YEAR_MASK 0x3f -+#define TOY_MATCH_MON_MASK 0xf -+#define TOY_MATCH_DAY_MASK 0x1f -+#define TOY_MATCH_HOUR_MASK 0x1f -+#define TOY_MATCH_MIN_MASK 0x3f -+#define TOY_MATCH_SEC_MASK 0x3f -+ -+ -+#define TOY_MATCH_YEAR_SHIFT 26 -+#define TOY_MATCH_MON_SHIFT 22 -+#define TOY_MATCH_DAY_SHIFT 17 -+#define TOY_MATCH_HOUR_SHIFT 12 -+#define TOY_MATCH_MIN_SHIFT 6 -+#define TOY_MATCH_SEC_SHIFT 0 -+ -+#define TOY_ENABLE_BIT (1U << 11) -+ -+#define TYPE_LS7A_RTC "ls7a_rtc" -+#define LS7A_RTC(obj) OBJECT_CHECK(LS7A_RTCState, (obj), TYPE_LS7A_RTC) -+ -+typedef struct LS7A_RTCState { -+ SysBusDevice parent_obj; -+ -+ MemoryRegion iomem; -+ QEMUTimer *timer; -+ /* Needed to preserve the tick_count across migration, even if the -+ * absolute value of the rtc_clock is different on the source and -+ * destination. -+ */ -+ int64_t offset; -+ int64_t data; -+ int64_t save_alarm_offset; -+ int tidx; -+ uint32_t toymatch[3]; -+ uint32_t toytrim; -+ uint32_t cntrctl; -+ uint32_t rtctrim; -+ uint32_t rtccount; -+ uint32_t rtcmatch[3]; -+ qemu_irq toy_irq; -+} LS7A_RTCState; -+ -+enum { -+TOYEN = 1UL << 11, -+RTCEN = 1UL << 13, -+}; -+ -+static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, -+ unsigned size) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *)opaque; -+ struct tm tm; -+ unsigned int val; -+ -+ val = 0; -+ -+ switch (addr) { -+ case SYS_TOYREAD0: -+ qemu_get_timedate(&tm, s->offset); -+ val = (((tm.tm_mon + 1) & TOY_MON_MASK) << TOY_MON_SHIFT) -+ | (((tm.tm_mday) & TOY_DAY_MASK) << TOY_DAY_SHIFT) -+ | (((tm.tm_hour) & TOY_HOUR_MASK) << TOY_HOUR_SHIFT) -+ | (((tm.tm_min) & TOY_MIN_MASK) << TOY_MIN_SHIFT) -+ | (((tm.tm_sec) & TOY_SEC_MASK) << TOY_SEC_SHIFT) | 0x0; -+ break; -+ case SYS_TOYREAD1: -+ qemu_get_timedate(&tm, s->offset); -+ val = tm.tm_year; -+ break; -+ case SYS_TOYMATCH0: -+ val = s->toymatch[0]; -+ break; -+ case SYS_TOYMATCH1: -+ val = s->toymatch[1]; -+ break; -+ case SYS_TOYMATCH2: -+ val = s->toymatch[2]; -+ break; -+ case SYS_RTCCTRL: -+ val = s->cntrctl; -+ break; -+ case SYS_RTCREAD0: -+ val = s->rtccount; -+ break; -+ case SYS_RTCMATCH0: -+ val = s->rtcmatch[0]; -+ break; -+ case SYS_RTCMATCH1: -+ val = s->rtcmatch[1]; -+ break; -+ case SYS_RTCMATCH2: -+ val = s->rtcmatch[2]; -+ break; -+ default: -+ val = 0; -+ break; -+ } -+ return val; -+} -+ -+ -+static void ls7a_rtc_write(void *opaque, hwaddr addr, -+ uint64_t val, unsigned size) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *)opaque; -+ struct tm tm; -+ int64_t alarm_offset, year_diff, expire_time; -+ -+ switch (addr) { -+ case SYS_TOYWRITE0: -+ qemu_get_timedate(&tm, s->offset); -+ tm.tm_sec = (val >> TOY_SEC_SHIFT) & TOY_SEC_MASK; -+ tm.tm_min = (val >> TOY_MIN_SHIFT) & TOY_MIN_MASK; -+ tm.tm_hour = (val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK; -+ tm.tm_mday = ((val >> TOY_DAY_SHIFT) & TOY_DAY_MASK); -+ tm.tm_mon = ((val >> TOY_MON_SHIFT) & TOY_MON_MASK) - 1; -+ s->offset = qemu_timedate_diff(&tm); -+ break; -+ case SYS_TOYWRITE1: -+ qemu_get_timedate(&tm, s->offset); -+ tm.tm_year = val; -+ s->offset = qemu_timedate_diff(&tm); -+ break; -+ case SYS_TOYMATCH0: -+ s->toymatch[0] = val; -+ qemu_get_timedate(&tm, s->offset); -+ tm.tm_sec = (val >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK; -+ tm.tm_min = (val >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK; -+ tm.tm_hour = ((val >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK); -+ tm.tm_mday = ((val >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK); -+ tm.tm_mon = ((val >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1; -+ year_diff = ((val >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK); -+ year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK); -+ tm.tm_year = tm.tm_year + year_diff; -+ alarm_offset = qemu_timedate_diff(&tm) - s->offset; -+ if ((alarm_offset < 0) && (alarm_offset > -5)) { -+ alarm_offset = 0; -+ } -+ expire_time = qemu_clock_get_ms(rtc_clock); -+ expire_time += ((alarm_offset * 1000) + 100); -+ timer_mod(s->timer, expire_time); -+ break; -+ case SYS_TOYMATCH1: -+ s->toymatch[1] = val; -+ break; -+ case SYS_TOYMATCH2: -+ s->toymatch[2] = val; -+ break; -+ case SYS_RTCCTRL: -+ s->cntrctl = val; -+ break; -+ case SYS_RTCWRTIE0: -+ s->rtccount = val; -+ break; -+ case SYS_RTCMATCH0: -+ s->rtcmatch[0] = val; -+ break; -+ case SYS_RTCMATCH1: -+ val = s->rtcmatch[1]; -+ break; -+ case SYS_RTCMATCH2: -+ val = s->rtcmatch[2]; -+ break; -+ default: -+ break; -+ } -+} -+ -+static const MemoryRegionOps ls7a_rtc_ops = { -+ .read = ls7a_rtc_read, -+ .write = ls7a_rtc_write, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+ .valid = { -+ .min_access_size = 4, -+ .max_access_size = 4, -+ }, -+ -+}; -+ -+static void toy_timer(void *opaque) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *) opaque; -+ -+ if (s->cntrctl & TOY_ENABLE_BIT) { -+ qemu_irq_pulse(s->toy_irq); -+ } -+} -+ -+static void ls7a_rtc_realize(DeviceState *dev, Error **errp) -+{ -+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev); -+ LS7A_RTCState *d = LS7A_RTC(sbd); -+ memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops, -+ (void *)d, "ls7a_rtc", 0x100); -+ -+ sysbus_init_irq(sbd, &d->toy_irq); -+ -+ sysbus_init_mmio(sbd, &d->iomem); -+ d->timer = timer_new_ms(rtc_clock, toy_timer, d); -+ timer_mod(d->timer, qemu_clock_get_ms(rtc_clock) + 100); -+ d->offset = 0; -+} -+ -+static int ls7a_rtc_pre_save(void *opaque) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *)opaque; -+ struct tm tm; -+ int64_t year_diff, value; -+ -+ value = s->toymatch[0]; -+ qemu_get_timedate(&tm, s->offset); -+ tm.tm_sec = (value >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK; -+ tm.tm_min = (value >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK; -+ tm.tm_hour = ((value >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK); -+ tm.tm_mday = ((value >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK); -+ tm.tm_mon = ((value >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1; -+ year_diff = ((value >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK); -+ year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK); -+ tm.tm_year = tm.tm_year + year_diff; -+ s->save_alarm_offset = qemu_timedate_diff(&tm) - s->offset; -+ -+ return 0; -+} -+ -+ -+static int ls7a_rtc_post_load(void *opaque, int version_id) -+{ -+ LS7A_RTCState *s = (LS7A_RTCState *)opaque; -+ int64_t expire_time; -+ -+ expire_time = qemu_clock_get_ms(rtc_clock) + (s->save_alarm_offset * 1000); -+ timer_mod(s->timer, expire_time); -+ -+ return 0; -+} -+ -+static const VMStateDescription vmstate_ls7a_rtc = { -+ .name = "ls7a_rtc", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = ls7a_rtc_pre_save, -+ .post_load = ls7a_rtc_post_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_INT64(offset, LS7A_RTCState), -+ VMSTATE_INT64(save_alarm_offset, LS7A_RTCState), -+ VMSTATE_UINT32(toymatch[0], LS7A_RTCState), -+ VMSTATE_UINT32(cntrctl, LS7A_RTCState), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+static void ls7a_rtc_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ dc->vmsd = &vmstate_ls7a_rtc; -+ dc->realize = ls7a_rtc_realize; -+ dc->desc = "ls7a rtc"; -+} -+ -+static const TypeInfo ls7a_rtc_info = { -+ .name = TYPE_LS7A_RTC, -+ .parent = TYPE_SYS_BUS_DEVICE, -+ .instance_size = sizeof(LS7A_RTCState), -+ .class_init = ls7a_rtc_class_init, -+}; -+ -+static void ls7a_rtc_register_types(void) -+{ -+ type_register_static(&ls7a_rtc_info); -+} -+ -+type_init(ls7a_rtc_register_types) -diff --git a/hw/timer/meson.build b/hw/timer/meson.build -index 03092e2ce..e841a2f6e 100644 ---- a/hw/timer/meson.build -+++ b/hw/timer/meson.build -@@ -16,6 +16,7 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_mct.c')) - softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pwm.c')) - softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_gptimer.c')) - softmmu_ss.add(when: 'CONFIG_HPET', if_true: files('hpet.c')) -+softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c')) - softmmu_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c')) - softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c')) - softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c')) --- -2.43.5 - diff --git a/0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch b/0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch deleted file mode 100644 index a62796a134af0812162e9f211720ce26446732f7..0000000000000000000000000000000000000000 --- a/0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 3239acc6c33806fac55fc08d7e5a81ef9ce85e23 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Wed, 25 Aug 2021 11:07:41 +0800 -Subject: [PATCH 2/8] anolis: csv/i386: add command to initialize CSV context - -When CSV is enabled, KVM_CSV_INIT command is used to initialize -the platform, which is implemented by reusing the SEV API -framework and extending the functionality. - -The KVM_CSV_INIT command should be performed earlier than -any other command. - -Signed-off-by: Xin Jiang -Change-Id: Ia4201dc90c250c23658e1cf5e19b528df9075330 ---- - linux-headers/linux/kvm.h | 11 +++++++++ - target/i386/csv-sysemu-stub.c | 5 ++++ - target/i386/csv.c | 44 +++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 3 +++ - target/i386/sev.c | 17 ++++++++++++++ - target/i386/sev.h | 5 ++++ - 6 files changed, 85 insertions(+) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index bcaf66cc4d..b15b8f5550 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1808,6 +1808,17 @@ struct kvm_sev_receive_update_data { - __u32 trans_len; - }; - -+/* CSV command */ -+enum csv_cmd_id { -+ KVM_CSV_NR_MIN = 0xc0, -+ -+ KVM_CSV_INIT = KVM_CSV_NR_MIN, -+}; -+ -+struct kvm_csv_init_data { -+ __u64 nodemask; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index a89b2600e7..dbd710dc6f 100644 ---- a/target/i386/csv-sysemu-stub.c -+++ b/target/i386/csv-sysemu-stub.c -@@ -14,3 +14,8 @@ - #include "qemu/osdep.h" - #include "sev.h" - #include "csv.h" -+ -+int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) -+{ -+ return 0; -+} -diff --git a/target/i386/csv.c b/target/i386/csv.c -index aac825d3f9..c11f59f30c 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -13,6 +13,12 @@ - - #include "qemu/osdep.h" - -+#include -+ -+#ifdef CONFIG_NUMA -+#include -+#endif -+ - #include "cpu.h" - #include "sev.h" - #include "csv.h" -@@ -41,6 +47,44 @@ static bool is_hygon_cpu(void) - return false; - } - -+int -+csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) -+{ -+ int fw_error; -+ int ret; -+ struct kvm_csv_init_data data = { 0 }; -+ -+#ifdef CONFIG_NUMA -+ int mode; -+ unsigned long nodemask; -+ -+ /* Set flags as 0 to retrieve the default NUMA policy. */ -+ ret = get_mempolicy(&mode, &nodemask, sizeof(nodemask) * 8, NULL, 0); -+ if (ret == 0 && (mode == MPOL_BIND)) -+ data.nodemask = nodemask; -+#endif -+ -+ if (!ops || !ops->sev_ioctl || !ops->fw_error_to_str) -+ return -1; -+ -+ csv_guest.policy = policy; -+ if (csv_enabled()) { -+ ret = ops->sev_ioctl(fd, KVM_CSV_INIT, &data, &fw_error); -+ if (ret) { -+ csv_guest.policy = 0; -+ error_report("%s: Fail to initialize ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, ops->fw_error_to_str(fw_error)); -+ return -1; -+ } -+ -+ csv_guest.sev_fd = fd; -+ csv_guest.state = state; -+ csv_guest.sev_ioctl = ops->sev_ioctl; -+ csv_guest.fw_error_to_str = ops->fw_error_to_str; -+ } -+ return 0; -+} -+ - bool - csv_enabled(void) - { -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 057d37d975..886dbb2613 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -26,10 +26,13 @@ struct CsvGuestState { - uint32_t policy; - int sev_fd; - void *state; -+ int (*sev_ioctl)(int fd, int cmd, void *data, int *error); -+ const char *(*fw_error_to_str)(int code); - }; - - typedef struct CsvGuestState CsvGuestState; - - extern struct CsvGuestState csv_guest; -+extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); - - #endif -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 025ff7a6f8..023532f4ec 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -26,6 +26,7 @@ - #include "crypto/hash.h" - #include "sysemu/kvm.h" - #include "sev.h" -+#include "csv.h" - #include "sysemu/sysemu.h" - #include "sysemu/runstate.h" - #include "trace.h" -@@ -43,6 +44,8 @@ - OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST) - - -+extern struct sev_ops sev_ops; -+ - /** - * SevGuestState: - * -@@ -952,6 +955,15 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - goto err; - } - -+ /* Support CSV */ -+ if (!ret && cmd == KVM_SEV_ES_INIT) { -+ ret = csv_init(sev_guest->policy, sev->sev_fd, &sev->state, &sev_ops); -+ if (ret) { -+ error_setg(errp, "%s: failed to init csv context", __func__); -+ goto err; -+ } -+ } -+ - ret = sev_launch_start(sev); - if (ret) { - error_setg(errp, "%s: failed to create encryption context", __func__); -@@ -1332,6 +1344,11 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) - return ret; - } - -+struct sev_ops sev_ops = { -+ .sev_ioctl = sev_ioctl, -+ .fw_error_to_str = fw_error_to_str, -+}; -+ - static void - sev_register_types(void) - { -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 83e82aa42c..1c97bff99e 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -59,4 +59,9 @@ void sev_es_set_reset_vector(CPUState *cpu); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - -+struct sev_ops { -+ int (*sev_ioctl)(int fd, int cmd, void *data, int *error); -+ const char *(*fw_error_to_str)(int code); -+}; -+ - #endif --- -2.17.1 - diff --git a/0003-Add-loongarch-machine.patch b/0003-Add-loongarch-machine.patch deleted file mode 100644 index 9052ba77a56a3f014f4d2f1f2d1d41b70b1f15b7..0000000000000000000000000000000000000000 --- a/0003-Add-loongarch-machine.patch +++ /dev/null @@ -1,5752 +0,0 @@ -From 3cb18285115f8dd7f9135c65b39c93cb7eb3580c Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:39:00 -0400 -Subject: [PATCH 03/28] Add loongarch machine. - -Change-Id: I7e31f874c676b740269945d5e19c6bc836de6a99 -Signed-off-by: lixianglai ---- - hw/loongarch/Kconfig | 17 + - hw/loongarch/acpi-build.c | 783 ++++++++++++ - hw/loongarch/acpi-build.h | 16 + - hw/loongarch/apic.c | 675 +++++++++++ - hw/loongarch/ioapic.c | 422 +++++++ - hw/loongarch/iocsr.c | 219 ++++ - hw/loongarch/ipi.c | 267 +++++ - hw/loongarch/larch_3a.c | 2026 ++++++++++++++++++++++++++++++++ - hw/loongarch/larch_hotplug.c | 355 ++++++ - hw/loongarch/larch_int.c | 91 ++ - hw/loongarch/ls7a_nb.c | 352 ++++++ - hw/loongarch/meson.build | 15 + - include/hw/loongarch/bios.h | 5 + - include/hw/loongarch/cpudevs.h | 53 + - include/hw/loongarch/larch.h | 163 +++ - include/hw/loongarch/ls7a.h | 152 +++ - 16 files changed, 5611 insertions(+) - create mode 100644 hw/loongarch/Kconfig - create mode 100644 hw/loongarch/acpi-build.c - create mode 100644 hw/loongarch/acpi-build.h - create mode 100644 hw/loongarch/apic.c - create mode 100644 hw/loongarch/ioapic.c - create mode 100644 hw/loongarch/iocsr.c - create mode 100644 hw/loongarch/ipi.c - create mode 100644 hw/loongarch/larch_3a.c - create mode 100644 hw/loongarch/larch_hotplug.c - create mode 100644 hw/loongarch/larch_int.c - create mode 100644 hw/loongarch/ls7a_nb.c - create mode 100644 hw/loongarch/meson.build - create mode 100644 include/hw/loongarch/bios.h - create mode 100644 include/hw/loongarch/cpudevs.h - create mode 100644 include/hw/loongarch/larch.h - create mode 100644 include/hw/loongarch/ls7a.h - -diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig -new file mode 100644 -index 000000000..3fe2677fd ---- /dev/null -+++ b/hw/loongarch/Kconfig -@@ -0,0 +1,17 @@ -+config LS7A_APIC -+ bool -+ -+config LS7A_RTC -+ bool -+ -+config LOONGSON3A -+ bool -+ -+config MEM_HOTPLUG -+ bool -+ -+config ACPI_LOONGARCH -+ bool -+ -+config E1000E_PCI -+ bool -diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c -new file mode 100644 -index 000000000..6ba637be5 ---- /dev/null -+++ b/hw/loongarch/acpi-build.c -@@ -0,0 +1,783 @@ -+/* Support for generating ACPI tables and passing them to Guests -+ * -+ * Copyright (C) 2008-2010 Kevin O'Connor -+ * Copyright (C) 2006 Fabrice Bellard -+ * Copyright (C) 2013 Red Hat Inc -+ * -+ * Author: Michael S. Tsirkin -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "qapi/qmp/qnum.h" -+#include "acpi-build.h" -+#include "qemu-common.h" -+#include "qemu/bitmap.h" -+#include "qemu/error-report.h" -+#include "hw/pci/pci.h" -+#include "hw/boards.h" -+#include "hw/core/cpu.h" -+#include "target/loongarch64/cpu.h" -+#include "hw/misc/pvpanic.h" -+#include "hw/timer/hpet.h" -+#include "hw/acpi/acpi-defs.h" -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/cpu.h" -+#include "hw/nvram/fw_cfg.h" -+#include "hw/acpi/bios-linker-loader.h" -+#include "hw/loader.h" -+#include "hw/isa/isa.h" -+#include "hw/block/fdc.h" -+#include "hw/acpi/memory_hotplug.h" -+#include "sysemu/tpm.h" -+#include "hw/acpi/tpm.h" -+#include "hw/acpi/vmgenid.h" -+#include "sysemu/tpm_backend.h" -+#include "hw/rtc/mc146818rtc_regs.h" -+#include "sysemu/numa.h" -+#include "sysemu/runstate.h" -+#include "sysemu/reset.h" -+#include "migration/vmstate.h" -+#include "hw/mem/memory-device.h" -+#include "hw/acpi/utils.h" -+#include "hw/acpi/pci.h" -+/* Supported chipsets: */ -+#include "hw/acpi/aml-build.h" -+#include "hw/loongarch/larch.h" -+#include "hw/loongarch/ls7a.h" -+ -+#include "hw/acpi/ipmi.h" -+#include "hw/acpi/ls7a.h" -+ -+/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and -+ * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows -+ * a little bit, there should be plenty of free space since the DSDT -+ * shrunk by ~1.5k between QEMU 2.0 and QEMU 2.1. -+ */ -+#define ACPI_BUILD_ALIGN_SIZE 0x1000 -+ -+#define ACPI_BUILD_TABLE_SIZE 0x20000 -+ -+/* #define DEBUG_ACPI_BUILD */ -+#ifdef DEBUG_ACPI_BUILD -+#define ACPI_BUILD_DPRINTF(fmt, ...) \ -+ do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0) -+#else -+#define ACPI_BUILD_DPRINTF(fmt, ...) -+#endif -+ -+/* Default IOAPIC ID */ -+#define ACPI_BUILD_IOAPIC_ID 0x0 -+ -+/* PCI fw r3.0 MCFG table. */ -+/* Subtable */ -+ -+typedef struct AcpiMiscInfo { -+ bool is_piix4; -+ bool has_hpet; -+ TPMVersion tpm_version; -+ const unsigned char *dsdt_code; -+ unsigned dsdt_size; -+ uint16_t pvpanic_port; -+ uint16_t applesmc_io_base; -+} AcpiMiscInfo; -+ -+typedef struct AcpiBuildPciBusHotplugState { -+ GArray *device_table; -+ GArray *notify_table; -+ struct AcpiBuildPciBusHotplugState *parent; -+ bool pcihp_bridge_en; -+} AcpiBuildPciBusHotplugState; -+ -+static void init_common_fadt_data(AcpiFadtData *data) -+{ -+ AmlAddressSpace as = AML_AS_SYSTEM_MEMORY; -+ uint64_t base = LS7A_ACPI_REG_BASE; -+ AcpiFadtData fadt = { -+ .rev = 3, -+ .flags = -+ (1 << ACPI_FADT_F_WBINVD) | -+ (1 << ACPI_FADT_F_PROC_C1) | -+ (1 << ACPI_FADT_F_SLP_BUTTON) | -+ (1 << ACPI_FADT_F_TMR_VAL_EXT) | -+ (1 << ACPI_FADT_F_RESET_REG_SUP) , -+ .plvl2_lat = 0xfff /* C2 state not supported */, -+ .plvl3_lat = 0xfff /* C3 state not supported */, -+ .smi_cmd = 0x00, -+ .sci_int = ACPI_SCI_IRQ, -+ .acpi_enable_cmd = 0x00, -+ .acpi_disable_cmd = 0x00, -+ .pm1a_evt = { .space_id = as, .bit_width = 8 * 8, -+ .address = base + LS7A_PM_EVT_BLK }, -+ .pm1a_cnt = { .space_id = as, .bit_width = 4 * 8, -+ .address = base + LS7A_PM_CNT_BLK }, -+ .pm_tmr = { .space_id = as, .bit_width = 4 * 8, -+ .address = base + LS7A_PM_TMR_BLK }, -+ .gpe0_blk = { .space_id = as, .bit_width = 8 * 8, -+ .address = base + LS7A_GPE0_STS_REG}, -+ .reset_reg = { .space_id = as, .bit_width = 4 * 8, -+ .address = base + LS7A_GPE0_RESET_REG}, -+ .reset_val = 0x1, -+ }; -+ *data = fadt; -+} -+ -+static void acpi_align_size(GArray *blob, unsigned align) -+{ -+ /* Align size to multiple of given size. This reduces the chance -+ * we need to change size in the future (breaking cross version migration). -+ */ -+ g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); -+} -+ -+/* FACS */ -+static void -+build_facs(GArray *table_data) -+{ -+ const char *sig = "FACS"; -+ const uint8_t reserved[40] = {}; -+ -+ g_array_append_vals(table_data, sig, 4); /* Signature */ -+ build_append_int_noprefix(table_data, 64, 4); /* Length */ -+ build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */ -+ build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */ -+ build_append_int_noprefix(table_data, 0, 4); /* Global Lock */ -+ build_append_int_noprefix(table_data, 0, 4); /* Flags */ -+ g_array_append_vals(table_data, reserved, 40); /* Reserved */ -+} -+ -+void ls7a_madt_cpu_entry(AcpiDeviceIf *adev, int uid, -+ const CPUArchIdList *apic_ids, GArray *entry, bool force_enabled) -+{ -+ uint32_t apic_id = apic_ids->cpus[uid].arch_id; -+ /* Flags – Local APIC Flags */ -+ uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? -+ 1 /* Enabled */ : 0; -+ -+ /* Rev 1.0b, Table 5-13 Processor Local APIC Structure */ -+ build_append_int_noprefix(entry, 0, 1); /* Type */ -+ build_append_int_noprefix(entry, 8, 1); /* Length */ -+ build_append_int_noprefix(entry, uid, 1); /* ACPI Processor ID */ -+ build_append_int_noprefix(entry, apic_id, 1); /* APIC ID */ -+ build_append_int_noprefix(entry, flags, 4); /* Flags */ -+} -+static void build_ioapic(GArray *entry, uint8_t id, uint32_t addr, uint32_t irq) -+{ -+ /* Rev 1.0b, 5.2.8.2 IO APIC */ -+ build_append_int_noprefix(entry, 1, 1); /* Type */ -+ build_append_int_noprefix(entry, 12, 1); /* Length */ -+ build_append_int_noprefix(entry, id, 1); /* IO APIC ID */ -+ build_append_int_noprefix(entry, 0, 1); /* Reserved */ -+ build_append_int_noprefix(entry, addr, 4); /* IO APIC Address */ -+ build_append_int_noprefix(entry, irq, 4); /* System Vector Base */ -+} -+ -+static void -+build_madt(GArray *table_data, BIOSLinker *linker, LoongarchMachineState *lsms) -+{ -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ MachineClass *mc = MACHINE_GET_CLASS(lsms); -+ const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(lsms)); -+ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(lsms->acpi_dev); -+ AcpiDeviceIf *adev = ACPI_DEVICE_IF(lsms->acpi_dev); -+ int i; -+ AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lsms->oem_id, -+ .oem_table_id = lsms->oem_table_id}; -+ -+ acpi_table_begin(&table, table_data); -+ -+ /* Local APIC Address */ -+ build_append_int_noprefix(table_data, 0, 4); -+ build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ -+ -+ -+ for (i = 0; i < apic_ids->len; i++) { -+ adevc->madt_cpu(adev, i, apic_ids, table_data, false); -+ } -+ -+ -+ build_ioapic(table_data, ACPI_BUILD_IOAPIC_ID, lsmc->ls7a_ioapic_reg_base, LOONGARCH_PCH_IRQ_BASE); -+ -+ /* Rev 1.0b, 5.2.8.3.3 Local APIC NMI */ -+ build_append_int_noprefix(table_data, 3, 1); /* Type */ -+ build_append_int_noprefix(table_data, 6, 1); /* Length */ -+ /* ACPI Processor ID */ -+ build_append_int_noprefix(table_data, 0xFF /* all processors */, 1); -+ build_append_int_noprefix(table_data, 0, 2); /* Flags */ -+ /* Local APIC INTI# */ -+ build_append_int_noprefix(table_data, 1 /* ACPI_LINT1 */, 1); -+ -+ /* Rev 1.0b, 5.2.8.3.3 Local APIC NMI */ -+ build_append_int_noprefix(table_data, 4, 1); /* Type */ -+ build_append_int_noprefix(table_data, 6, 1); /* Length */ -+ /* ACPI Processor ID */ -+ build_append_int_noprefix(table_data, 0xFF /* all processors */, 1); -+ build_append_int_noprefix(table_data, 0, 2); /* Flags */ -+ /* Local APIC INTI# */ -+ build_append_int_noprefix(table_data, 1 /* ACPI_LINT1 */, 1); -+ -+ -+ acpi_table_end(linker, &table); -+} -+ -+static void -+build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) -+{ -+ uint64_t i, mem_len, mem_base; -+ MachineClass *mc = MACHINE_GET_CLASS(machine); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine); -+ int nb_numa_nodes = machine->numa_state->num_nodes; -+ NodeInfo *numa_info = machine->numa_state->nodes; -+ AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lsms->oem_id, -+ .oem_table_id = lsms->oem_table_id}; -+ -+ acpi_table_begin(&table, table_data); -+ build_append_int_noprefix(table_data, 1, 4); /* Reserved */ -+ build_append_int_noprefix(table_data, 0, 8); /* Reserved */ -+ -+ for (i = 0; i < apic_ids->len; ++i) { -+ /* 5.2.15.1 Processor Local APIC/SAPIC Affinity Structure */ -+ build_append_int_noprefix(table_data, 0, 1); /* Type */ -+ build_append_int_noprefix(table_data, 16, 1); /* Length */ -+ /* Proximity Domain [7:0] */ -+ build_append_int_noprefix(table_data, apic_ids->cpus[i].props.node_id, 1); -+ build_append_int_noprefix(table_data, apic_ids->cpus[i].arch_id, 1); /* APIC ID */ -+ /* Flags, Table 5-36 */ -+ build_append_int_noprefix(table_data, 1, 4); -+ build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */ -+ /* Proximity Domain [31:8] */ -+ build_append_int_noprefix(table_data, 0, 3); -+ build_append_int_noprefix(table_data, 0, 4); /* Reserved */ -+ } -+ -+ /* node0 */ -+ mem_base = (uint64_t)0; -+ mem_len = 0x10000000; -+ build_srat_memory(table_data, mem_base, mem_len, -+ 0, MEM_AFFINITY_ENABLED); -+ mem_base = 0x90000000; -+ if (!nb_numa_nodes) { -+ mem_len = machine->ram_size - 0x10000000; -+ } else { -+ mem_len = numa_info[0].node_mem - 0x10000000; -+ } -+ -+ build_srat_memory(table_data, mem_base, mem_len, -+ 0, MEM_AFFINITY_ENABLED); -+ mem_base += mem_len; -+ -+ /* node1 ~ nodemax */ -+ for (i = 1; i < nb_numa_nodes; ++i) { -+ mem_len = numa_info[i].node_mem; -+ build_srat_memory(table_data, mem_base, mem_len, -+ i, MEM_AFFINITY_ENABLED); -+ mem_base += mem_len; -+ } -+ -+ if (lsms->hotplug_memory_size) { -+ build_srat_memory(table_data, machine->device_memory->base, -+ lsms->hotplug_memory_size, 0, -+ MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); -+ } -+ -+ acpi_table_end(linker, &table); -+ -+} -+ -+typedef -+struct AcpiBuildState { -+ /* Copy of table in RAM (for patching). */ -+ MemoryRegion *table_mr; -+ /* Is table patched? */ -+ uint8_t patched; -+ void *rsdp; -+ MemoryRegion *rsdp_mr; -+ MemoryRegion *linker_mr; -+} AcpiBuildState; -+ -+static void build_ls7a_pci0_int(Aml *table) -+{ -+ Aml *sb_scope = aml_scope("_SB"); -+ Aml *pci0_scope = aml_scope("PCI0"); -+ Aml *prt_pkg = aml_varpackage(128); -+ int slot, pin; -+ -+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { -+ for (pin = 0; pin < PCI_NUM_PINS; pin++) { -+ Aml *pkg = aml_package(4); -+ aml_append(pkg, aml_int((slot << 16) | 0xFFFF)); -+ aml_append(pkg, aml_int(pin)); -+ aml_append(pkg, aml_int(0)); -+ aml_append(pkg, aml_int(LOONGARCH_PCH_IRQ_BASE + 16 + (slot * 4 + pin) % 16)); -+ aml_append(prt_pkg, pkg); -+ } -+ } -+ aml_append(pci0_scope, -+ aml_name_decl("_PRT", prt_pkg)); -+ -+ aml_append(sb_scope, pci0_scope); -+ -+ aml_append(table, sb_scope); -+} -+ -+static void build_dbg_aml(Aml *table) -+{ -+ Aml *field; -+ Aml *method; -+ Aml *while_ctx; -+ Aml *scope = aml_scope("\\"); -+ Aml *buf = aml_local(0); -+ Aml *len = aml_local(1); -+ Aml *idx = aml_local(2); -+ -+ aml_append(scope, -+ aml_operation_region("DBG", AML_SYSTEM_IO, aml_int(0x0402), 0x01)); -+ field = aml_field("DBG", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); -+ aml_append(field, aml_named_field("DBGB", 8)); -+ aml_append(scope, field); -+ -+ method = aml_method("DBUG", 1, AML_NOTSERIALIZED); -+ -+ aml_append(method, aml_to_hexstring(aml_arg(0), buf)); -+ aml_append(method, aml_to_buffer(buf, buf)); -+ aml_append(method, aml_subtract(aml_sizeof(buf), aml_int(1), len)); -+ aml_append(method, aml_store(aml_int(0), idx)); -+ -+ while_ctx = aml_while(aml_lless(idx, len)); -+ aml_append(while_ctx, -+ aml_store(aml_derefof(aml_index(buf, idx)), aml_name("DBGB"))); -+ aml_append(while_ctx, aml_increment(idx)); -+ aml_append(method, while_ctx); -+ -+ aml_append(method, aml_store(aml_int(0x0A), aml_name("DBGB"))); -+ aml_append(scope, method); -+ -+ aml_append(table, scope); -+} -+ -+static Aml *build_ls7a_osc_method(void) -+{ -+ Aml *if_ctx; -+ Aml *if_ctx2; -+ Aml *else_ctx; -+ Aml *method; -+ Aml *a_cwd1 = aml_name("CDW1"); -+ Aml *a_ctrl = aml_local(0); -+ -+ method = aml_method("_OSC", 4, AML_NOTSERIALIZED); -+ aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); -+ -+ if_ctx = aml_if(aml_equal( -+ aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"))); -+ aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); -+ aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); -+ -+ aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl)); -+ -+ /* -+ * Always allow native PME, AER (no dependencies) -+ * Allow SHPC (PCI bridges can have SHPC controller) -+ */ -+ aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl)); -+ -+ if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1)))); -+ /* Unknown revision */ -+ aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1)); -+ aml_append(if_ctx, if_ctx2); -+ -+ if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); -+ /* Capabilities bits were masked */ -+ aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1)); -+ aml_append(if_ctx, if_ctx2); -+ -+ /* Update DWORD3 in the buffer */ -+ aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3"))); -+ aml_append(method, if_ctx); -+ -+ else_ctx = aml_else(); -+ /* Unrecognized UUID */ -+ aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1)); -+ aml_append(method, else_ctx); -+ -+ aml_append(method, aml_return(aml_arg(3))); -+ return method; -+} -+ -+static void build_ls7a_rtc_device_aml(Aml *table) -+{ -+ Aml *dev; -+ Aml *crs; -+ uint32_t rtc_irq = LS7A_RTC_IRQ; -+ -+ Aml *scope = aml_scope("_SB"); -+ dev = aml_device("RTC"); -+ aml_append(dev, aml_name_decl("_HID", aml_string("LOON0001"))); -+ crs = aml_resource_template(); -+ aml_append(crs, -+ aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, -+ AML_NON_CACHEABLE, AML_READ_WRITE, -+ 0, LS7A_RTC_REG_BASE, -+ LS7A_RTC_REG_BASE + LS7A_RTC_LEN - 1, 0, LS7A_RTC_LEN)); -+ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, -+ AML_EXCLUSIVE, &rtc_irq, 1)); -+ -+ aml_append(dev, aml_name_decl("_CRS", crs)); -+ aml_append(scope, dev); -+ aml_append(table, scope); -+} -+ -+static void build_ls7a_uart_device_aml(Aml *table) -+{ -+ Aml *dev; -+ Aml *crs; -+ Aml *pkg0, *pkg1, *pkg2; -+ uint32_t uart_irq = LS7A_UART_IRQ; -+ -+ Aml *scope = aml_scope("_SB"); -+ dev = aml_device("COMA"); -+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); -+ aml_append(dev, aml_name_decl("_UID", aml_int(0))); -+ aml_append(dev, aml_name_decl("_CCA", aml_int(1))); -+ crs = aml_resource_template(); -+ aml_append(crs, -+ aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, -+ AML_NON_CACHEABLE, AML_READ_WRITE, -+ 0, LS7A_UART_BASE, LS7A_UART_BASE + LS7A_UART_LEN - 1, 0, 0x8)); -+ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, -+ AML_EXCLUSIVE, &uart_irq, 1)); -+ aml_append(dev, aml_name_decl("_CRS", crs)); -+ pkg0 = aml_package(0x2); -+ aml_append(pkg0, aml_int(0x01F78A40)); -+ aml_append(pkg0, aml_string("clock-frenquency")); -+ pkg1 = aml_package(0x1); -+ aml_append(pkg1, pkg0); -+ pkg2 = aml_package(0x2); -+ aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); -+ aml_append(pkg2, pkg1); -+ -+ aml_append(dev, aml_name_decl("_DSD", pkg2)); -+ -+ aml_append(scope, dev); -+ aml_append(table, scope); -+} -+ -+static void -+build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) -+{ -+ Aml *dsdt, *sb_scope, *scope, *dev, *crs, *pkg; -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ uint32_t nr_mem = machine->ram_slots; -+ uint64_t base = LS7A_ACPI_REG_BASE; -+ int root_bus_limit = PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1); -+ AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lsms->oem_id, -+ .oem_table_id = lsms->oem_table_id}; -+ -+ acpi_table_begin(&table, table_data); -+ dsdt = init_aml_allocator(); -+ -+ build_dbg_aml(dsdt); -+ -+ sb_scope = aml_scope("_SB"); -+ dev = aml_device("PCI0"); -+ aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); -+ aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); -+ aml_append(dev, aml_name_decl("_ADR", aml_int(0))); -+ aml_append(dev, aml_name_decl("_BBN", aml_int(0))); -+ aml_append(dev, aml_name_decl("_UID", aml_int(1))); -+ aml_append(dev, build_ls7a_osc_method()); -+ aml_append(sb_scope, dev); -+ aml_append(dsdt, sb_scope); -+ -+ build_ls7a_pci0_int(dsdt); -+ build_ls7a_rtc_device_aml(dsdt); -+ build_ls7a_uart_device_aml(dsdt); -+ -+ if (lsms->acpi_dev) { -+ CPUHotplugFeatures opts = { -+ .acpi_1_compatible = true, .has_legacy_cphp = false -+ }; -+ build_cpus_aml(dsdt, machine, opts, CPU_HOTPLUG_BASE, -+ "\\_SB.PCI0", "\\_GPE._E02"); -+ -+ build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", -+ "\\_GPE._E03", AML_SYSTEM_MEMORY, -+ MEMORY_HOTPLUG_BASE); -+ } -+ -+ scope = aml_scope("_GPE"); -+ { -+ aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); -+ } -+ aml_append(dsdt, scope); -+ -+ scope = aml_scope("\\_SB.PCI0"); -+ /* build PCI0._CRS */ -+ crs = aml_resource_template(); -+ aml_append(crs, -+ aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, -+ 0x0000, 0x0, root_bus_limit, -+ 0x0000, root_bus_limit + 1)); -+ aml_append(crs, -+ aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, -+ AML_POS_DECODE, AML_ENTIRE_RANGE, -+ 0x0000, 0x4000, 0xFFFF, 0x0000, 0xC000)); -+ aml_append(crs, -+ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, -+ AML_CACHEABLE, AML_READ_WRITE, -+ 0, 0x40000000, 0x7FFFFFFF, 0, 0x40000000)); -+ aml_append(scope, aml_name_decl("_CRS", crs)); -+ -+ /* reserve GPE0 block resources */ -+ dev = aml_device("GPE0"); -+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06"))); -+ aml_append(dev, aml_name_decl("_UID", aml_string("GPE0 resources"))); -+ /* device present, functioning, decoding, not shown in UI */ -+ aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); -+ crs = aml_resource_template(); -+ aml_append(crs, -+ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, -+ AML_CACHEABLE, AML_READ_WRITE, -+ 0, base + LS7A_GPE0_STS_REG, -+ base + LS7A_GPE0_STS_REG + 0x3, 0, 0x4)); -+ aml_append(dev, aml_name_decl("_CRS", crs)); -+ aml_append(scope, dev); -+ aml_append(dsdt, scope); -+ -+ scope = aml_scope("\\"); -+ pkg = aml_package(4); -+ aml_append(pkg, aml_int(7)); /* PM1a_CNT.SLP_TYP */ -+ aml_append(pkg, aml_int(7)); /* PM1b_CNT.SLP_TYP not impl. */ -+ aml_append(pkg, aml_int(0)); /* reserved */ -+ aml_append(pkg, aml_int(0)); /* reserved */ -+ aml_append(scope, aml_name_decl("_S5", pkg)); -+ aml_append(dsdt, scope); -+ -+ /* copy AML table into ACPI tables blob and patch header there */ -+ g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); -+ acpi_table_end(linker, &table); -+ free_aml_allocator(); -+} -+ -+ -+static -+void acpi_build(AcpiBuildTables *tables, MachineState *machine) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ GArray *table_offsets; -+ AcpiFadtData fadt_data; -+ unsigned facs, rsdt, fadt, dsdt; -+ uint8_t *u; -+ size_t aml_len = 0; -+ GArray *tables_blob = tables->table_data; -+ -+ init_common_fadt_data(&fadt_data); -+ -+ table_offsets = g_array_new(false, true /* clear */, -+ sizeof(uint32_t)); -+ ACPI_BUILD_DPRINTF("init ACPI tables\n"); -+ -+ bios_linker_loader_alloc(tables->linker, -+ ACPI_BUILD_TABLE_FILE, tables_blob, -+ 64 /* Ensure FACS is aligned */, -+ false /* high memory */); -+ -+ /* -+ * FACS is pointed to by FADT. -+ * We place it first since it's the only table that has alignment -+ * requirements. -+ */ -+ facs = tables_blob->len; -+ build_facs(tables_blob); -+ -+ /* DSDT is pointed to by FADT */ -+ dsdt = tables_blob->len; -+ build_dsdt(tables_blob, tables->linker, MACHINE(qdev_get_machine())); -+ -+ /* Count the size of the DSDT and SSDT, we will need it for legacy -+ * sizing of ACPI tables. -+ */ -+ aml_len += tables_blob->len - dsdt; -+ -+ /* ACPI tables pointed to by RSDT */ -+ fadt = tables_blob->len; -+ acpi_add_table(table_offsets, tables_blob); -+ fadt_data.facs_tbl_offset = &facs; -+ fadt_data.dsdt_tbl_offset = &dsdt; -+ fadt_data.xdsdt_tbl_offset = &dsdt; -+ build_fadt(tables_blob, tables->linker, &fadt_data, -+ "LOONGS", "TP-R00"); -+ aml_len += tables_blob->len - fadt; -+ -+ acpi_add_table(table_offsets, tables_blob); -+ build_madt(tables_blob, tables->linker, lsms); -+ -+ acpi_add_table(table_offsets, tables_blob); -+ build_srat(tables_blob, tables->linker, machine); -+ if (machine->numa_state->have_numa_distance) { -+ acpi_add_table(table_offsets, tables_blob); -+ build_slit(tables_blob, tables->linker, machine, lsms->oem_id, -+ lsms->oem_table_id); -+ } -+ -+ /* Build mcfg */ -+ acpi_add_table(table_offsets, tables_blob); -+ { -+ AcpiMcfgInfo mcfg = { -+ .base = LS_PCIECFG_BASE, -+ .size = LS_PCIECFG_SIZE, -+ }; -+ build_mcfg(tables_blob, tables->linker, &mcfg, lsms->oem_id, -+ lsms->oem_table_id); -+ } -+ -+ /* Add tables supplied by user (if any) */ -+ for (u = acpi_table_first(); u; u = acpi_table_next(u)) { -+ unsigned len = acpi_table_len(u); -+ -+ acpi_add_table(table_offsets, tables_blob); -+ g_array_append_vals(tables_blob, u, len); -+ } -+ -+ /* RSDT is pointed to by RSDP */ -+ rsdt = tables_blob->len; -+ build_rsdt(tables_blob, tables->linker, table_offsets, -+ "LOONGS", "TP-R00"); -+ -+ /* RSDP is in FSEG memory, so allocate it separately */ -+ { -+ AcpiRsdpData rsdp_data = { -+ .revision = 0, -+ .oem_id = lsms->oem_id, -+ .xsdt_tbl_offset = NULL, -+ .rsdt_tbl_offset = &rsdt, -+ }; -+ build_rsdp(tables->rsdp, tables->linker, &rsdp_data); -+ } -+ acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE); -+ -+ /* Cleanup memory that's no longer used. */ -+ g_array_free(table_offsets, true); -+} -+ -+static void acpi_ram_update(MemoryRegion *mr, GArray *data) -+{ -+ uint32_t size = acpi_data_len(data); -+ -+ /* Make sure RAM size is correct - -+ in case it got changed e.g. by migration */ -+ memory_region_ram_resize(mr, size, &error_abort); -+ -+ memcpy(memory_region_get_ram_ptr(mr), data->data, size); -+ memory_region_set_dirty(mr, 0, size); -+} -+ -+static void acpi_build_update(void *build_opaque) -+{ -+ AcpiBuildState *build_state = build_opaque; -+ AcpiBuildTables tables; -+ -+ /* No state to update or already patched? Nothing to do. */ -+ if (!build_state || build_state->patched) { -+ return; -+ } -+ build_state->patched = 1; -+ -+ acpi_build_tables_init(&tables); -+ -+ acpi_build(&tables, MACHINE(qdev_get_machine())); -+ -+ acpi_ram_update(build_state->table_mr, tables.table_data); -+ -+ if (build_state->rsdp) { -+ memcpy(build_state->rsdp, tables.rsdp->data, -+ acpi_data_len(tables.rsdp)); -+ } else { -+ acpi_ram_update(build_state->rsdp_mr, tables.rsdp); -+ } -+ -+ acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); -+ acpi_build_tables_cleanup(&tables, true); -+} -+ -+static void acpi_build_reset(void *build_opaque) -+{ -+ AcpiBuildState *build_state = build_opaque; -+ build_state->patched = 0; -+} -+ -+static const VMStateDescription vmstate_acpi_build = { -+ .name = "acpi_build", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT8(patched, AcpiBuildState), -+ VMSTATE_END_OF_LIST() -+ }, -+}; -+ -+void loongarch_acpi_setup(void) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ AcpiBuildTables tables; -+ AcpiBuildState *build_state; -+ -+ if (!lsms->fw_cfg) { -+ ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); -+ return; -+ } -+ -+ if (!lsms->acpi_build_enabled) { -+ ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n"); -+ return; -+ } -+ -+ if (!loongarch_is_acpi_enabled(lsms)) { -+ ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n"); -+ return; -+ } -+ -+ build_state = g_malloc0(sizeof *build_state); -+ -+ acpi_build_tables_init(&tables); -+ acpi_build(&tables, MACHINE(lsms)); -+ -+ /* Now expose it all to Guest */ -+ build_state->table_mr = acpi_add_rom_blob(acpi_build_update, build_state, -+ tables.table_data, -+ ACPI_BUILD_TABLE_FILE); -+ assert(build_state->table_mr != NULL); -+ -+ build_state->linker_mr = -+ acpi_add_rom_blob(acpi_build_update, build_state, tables.linker->cmd_blob, -+ "etc/table-loader"); -+ -+ fw_cfg_add_file(lsms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, -+ tables.tcpalog->data, acpi_data_len(tables.tcpalog)); -+ -+ build_state->rsdp = NULL; -+ build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update, build_state, tables.rsdp, -+ ACPI_BUILD_RSDP_FILE); -+ -+ qemu_register_reset(acpi_build_reset, build_state); -+ acpi_build_reset(build_state); -+ vmstate_register(NULL, 0, &vmstate_acpi_build, build_state); -+ -+ /* Cleanup tables but don't free the memory: we track it -+ * in build_state. -+ */ -+ acpi_build_tables_cleanup(&tables, false); -+} -diff --git a/hw/loongarch/acpi-build.h b/hw/loongarch/acpi-build.h -new file mode 100644 -index 000000000..a914268bb ---- /dev/null -+++ b/hw/loongarch/acpi-build.h -@@ -0,0 +1,16 @@ -+ -+#ifndef HW_LARCH_ACPI_BUILD_H -+#define HW_LARCH_ACPI_BUILD_H -+ -+#define EFI_ACPI_OEM_ID "LARCH" -+#define EFI_ACPI_OEM_TABLE_ID "LARCH" /* OEM table id 8 bytes long */ -+#define EFI_ACPI_OEM_REVISION 0x00000002 -+#define EFI_ACPI_CREATOR_ID "LINUX" -+#define EFI_ACPI_CREATOR_REVISION 0x01000013 -+ -+#define ACPI_COMPATIBLE_1_0 0 -+#define ACPI_COMPATIBLE_2_0 1 -+ -+void loongarch_acpi_setup(void); -+ -+#endif -diff --git a/hw/loongarch/apic.c b/hw/loongarch/apic.c -new file mode 100644 -index 000000000..d6ba2a2ce ---- /dev/null -+++ b/hw/loongarch/apic.c -@@ -0,0 +1,675 @@ -+/* -+ * Loongarch 3A5000 interrupt controller emulation -+ * -+ * Copyright (C) 2020 Lu Zeng -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "hw/boards.h" -+#include "hw/irq.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/sysbus.h" -+#include "qemu/host-utils.h" -+#include "qemu/error-report.h" -+#include "sysemu/kvm.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "target/loongarch64/cpu.h" -+#include "exec/address-spaces.h" -+#include "hw/loongarch/larch.h" -+#include "migration/vmstate.h" -+ -+#define DEBUG_APIC 0 -+ -+#define DPRINTF(fmt, ...) \ -+do { \ -+ if (DEBUG_APIC) { \ -+ fprintf(stderr, "APIC: " fmt , ## __VA_ARGS__); \ -+ } \ -+} while (0) -+ -+#define APIC_OFFSET 0x400 -+#define APIC_BASE (0x1f010000ULL) -+#define EXTIOI_NODETYPE_START (0x4a0 - APIC_OFFSET) -+#define EXTIOI_NODETYPE_END (0x4c0 - APIC_OFFSET) -+#define EXTIOI_IPMAP_START (0x4c0 - APIC_OFFSET) -+#define EXTIOI_IPMAP_END (0x4c8 - APIC_OFFSET) -+#define EXTIOI_ENABLE_START (0x600 - APIC_OFFSET) -+#define EXTIOI_ENABLE_END (0x620 - APIC_OFFSET) -+#define EXTIOI_BOUNCE_START (0x680 - APIC_OFFSET) -+#define EXTIOI_BOUNCE_END (0x6a0 - APIC_OFFSET) -+#define EXTIOI_ISR_START (0x700 - APIC_OFFSET) -+#define EXTIOI_ISR_END (0x720 - APIC_OFFSET) -+#define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET) -+#define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET) -+#define EXTIOI_COREISR_START (0x10000) -+#define EXTIOI_COREISR_END (EXTIOI_COREISR_START + 0x10000) -+ -+static int ext_irq_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ apicState *apic = opaque; -+ struct loongarch_kvm_irqchip *chip; -+ struct kvm_loongarch_ls3a_extirq_state *kstate; -+ int ret, length, i, vcpuid; -+#endif -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+#ifdef CONFIG_KVM -+ length = sizeof(struct loongarch_kvm_irqchip) + -+ sizeof(struct kvm_loongarch_ls3a_extirq_state); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS3A_EXTIRQ; -+ chip->len = length; -+ -+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ -+ kstate = (struct kvm_loongarch_ls3a_extirq_state *)chip->data; -+ for (i = 0; i < EXTIOI_IRQS_BITMAP_SIZE; i++) { -+ apic->ext_en[i] = kstate->ext_en_r.reg_u8[i]; -+ apic->ext_bounce[i] = kstate->bounce_r.reg_u8[i]; -+ apic->ext_isr[i] = kstate->ext_isr_r.reg_u8[i]; -+ for (vcpuid = 0; vcpuid < MAX_CORES; vcpuid++) { -+ apic->ext_coreisr[vcpuid][i] = kstate->ext_core_isr_r.reg_u8[vcpuid][i]; -+ } -+ } -+ for (i = 0; i < EXTIOI_IRQS_IPMAP_SIZE; i++) { -+ apic->ext_ipmap[i] = kstate->ip_map_r.reg_u8[i]; -+ } -+ for (i = 0; i < EXTIOI_IRQS; i++) { -+ apic->ext_coremap[i] = kstate->core_map_r.reg_u8[i];; -+ } -+ for (i = 0; i < 16; i++) { -+ apic->ext_nodetype[i] = kstate->node_type_r.reg_u16[i]; -+ } -+ g_free(chip); -+#endif -+ return 0; -+} -+ -+static int ext_irq_post_load(void *opaque, int version) -+{ -+#ifdef CONFIG_KVM -+ apicState *apic = opaque; -+ struct loongarch_kvm_irqchip *chip; -+ struct kvm_loongarch_ls3a_extirq_state *kstate; -+ int ret, length, i, vcpuid; -+#endif -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+#ifdef CONFIG_KVM -+ length = sizeof(struct loongarch_kvm_irqchip) + -+ sizeof(struct kvm_loongarch_ls3a_extirq_state); -+ chip = g_malloc0(length); -+ -+ chip->chip_id = KVM_IRQCHIP_LS3A_EXTIRQ; -+ chip->len = length; -+ -+ kstate = (struct kvm_loongarch_ls3a_extirq_state *)chip->data; -+ for (i = 0; i < EXTIOI_IRQS_BITMAP_SIZE; i++) { -+ kstate->ext_en_r.reg_u8[i] = apic->ext_en[i]; -+ kstate->bounce_r.reg_u8[i] = apic->ext_bounce[i]; -+ kstate->ext_isr_r.reg_u8[i] = apic->ext_isr[i]; -+ for (vcpuid = 0; vcpuid < MAX_CORES; vcpuid++) { -+ kstate->ext_core_isr_r.reg_u8[vcpuid][i] = apic->ext_coreisr[vcpuid][i]; -+ } -+ } -+ for (i = 0; i < EXTIOI_IRQS_IPMAP_SIZE; i++) { -+ kstate->ip_map_r.reg_u8[i] = apic->ext_ipmap[i]; -+ } -+ for (i = 0; i < EXTIOI_IRQS; i++) { -+ kstate->core_map_r.reg_u8[i] = apic->ext_coremap[i]; -+ } -+ for (i = 0; i < 16; i++) { -+ kstate->node_type_r.reg_u16[i] = apic->ext_nodetype[i]; -+ } -+ -+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_SET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ g_free(chip); -+#endif -+ return 0; -+} -+typedef struct nodeApicState { -+ unsigned long addr; -+ int nodeid; -+ apicState *apic; -+} nodeApicState; -+ -+static void ioapic_update_irq(void *opaque, int irq, int level) -+{ -+ apicState *s = opaque; -+ uint8_t ipnum, cpu, cpu_ipnum; -+ unsigned long found1, found2; -+ uint8_t reg_count, reg_bit; -+ -+ reg_count = irq / 32; -+ reg_bit = irq % 32; -+ -+ ipnum = s->ext_sw_ipmap[irq]; -+ cpu = s->ext_sw_coremap[irq]; -+ cpu_ipnum = cpu * LS3A_INTC_IP + ipnum; -+ if (level == 1) { -+ if (test_bit(reg_bit, ((void *)s->ext_en + 0x4 * reg_count)) == false) { -+ return; -+ } -+ -+ if (test_bit(reg_bit, ((void *)s->ext_isr + 0x4 * reg_count)) == false) { -+ return; -+ } -+ bitmap_set(((void *)s->ext_coreisr[cpu] + 0x4 * reg_count), reg_bit, 1); -+ found1 = find_next_bit(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), -+ EXTIOI_IRQS, 0); -+ bitmap_set(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), reg_bit, 1); -+ if (found1 >= EXTIOI_IRQS) { -+ qemu_set_irq(s->parent_irq[cpu][ipnum], level); -+ } -+ } else { -+ bitmap_clear(((void *)s->ext_isr + 0x4 * reg_count), reg_bit, 1); -+ bitmap_clear(((void *)s->ext_coreisr[cpu] + 0x4 * reg_count), reg_bit, 1); -+ found1 = find_next_bit(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), -+ EXTIOI_IRQS, 0); -+ found1 += reg_count * 32; -+ bitmap_clear(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), reg_bit, 1); -+ found2 = find_next_bit(((void *)s->ext_ipisr[cpu_ipnum] + 0x4 * reg_count), -+ EXTIOI_IRQS, 0); -+ if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) { -+ qemu_set_irq(s->parent_irq[cpu][ipnum], level); -+ } -+ } -+} -+ -+static void ioapic_setirq(void *opaque, int irq, int level) -+{ -+ apicState *s = opaque; -+ uint8_t reg_count, reg_bit; -+ -+ reg_count = irq / 32; -+ reg_bit = irq % 32; -+ -+ if (level) { -+ bitmap_set(((void *)s->ext_isr + 0x4 * reg_count), reg_bit, 1); -+ } else { -+ bitmap_clear(((void *)s->ext_isr + 0x4 * reg_count), reg_bit, 1); -+ } -+ -+ ioapic_update_irq(s, irq, level); -+} -+ -+static uint32_t apic_readb(void *opaque, hwaddr addr) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint8_t ret; -+ int cpu; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ ret = 0; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ ret = *(uint8_t *)((void *)state->ext_en + off); -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ ret = *(uint8_t *)((void *)state->ext_bounce + off); -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ ret = *(uint8_t *)((void *)state->ext_isr + off); -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ ret = *(uint8_t *)((void *)state->ext_coreisr[cpu] + (off & 0x1f)); -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ off -= EXTIOI_IPMAP_START; -+ ret = *(uint8_t *)((void *)state->ext_ipmap + off); -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ off -= EXTIOI_COREMAP_START; -+ ret = *(uint8_t *)((void *)state->ext_coremap + off); -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ ret = *(uint8_t *)((void *)state->ext_nodetype + off); -+ } -+ -+ DPRINTF("readb reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, ret); -+ return ret; -+} -+ -+static uint32_t apic_readw(void *opaque, hwaddr addr) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint16_t ret; -+ int cpu; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ ret = 0; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ ret = *(uint16_t *)((void *)state->ext_en + off); -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ ret = *(uint16_t *)((void *)state->ext_bounce + off); -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ ret = *(uint16_t *)((void *)state->ext_isr + off); -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ ret = *(uint16_t *)((void *)state->ext_coreisr[cpu] + (off & 0x1f)); -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ off -= EXTIOI_IPMAP_START; -+ ret = *(uint16_t *)((void *)state->ext_ipmap + off); -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ off -= EXTIOI_COREMAP_START; -+ ret = *(uint16_t *)((void *)state->ext_coremap + off); -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ ret = *(uint16_t *)((void *)state->ext_nodetype + off); -+ } -+ -+ DPRINTF("readw reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, ret); -+ return ret; -+} -+ -+static uint32_t apic_readl(void *opaque, hwaddr addr) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint32_t ret; -+ int cpu; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ ret = 0; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ ret = *(uint32_t *)((void *)state->ext_en + off); -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ ret = *(uint32_t *)((void *)state->ext_bounce + off); -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ ret = *(uint32_t *)((void *)state->ext_isr + off); -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ ret = *(uint32_t *)((void *)state->ext_coreisr[cpu] + (off & 0x1f)); -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ off -= EXTIOI_IPMAP_START; -+ ret = *(uint32_t *)((void *)state->ext_ipmap + off); -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ off -= EXTIOI_COREMAP_START; -+ ret = *(uint32_t *)((void *)state->ext_coremap + off); -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ ret = *(uint32_t *)((void *)state->ext_nodetype + off); -+ } -+ -+ DPRINTF("readl reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, ret); -+ return ret; -+ -+} -+ -+static void apic_writeb(void *opaque, hwaddr addr, uint32_t val) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint8_t old; -+ int cpu, i, ipnum, level, mask; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ old = *(uint8_t *)((void *)state->ext_en + off); -+ if (old != val) { -+ *(uint8_t *)((void *)state->ext_en + off) = val; -+ old = old ^ val; -+ mask = 0x1; -+ for (i = 0; i < 8; i++) { -+ if (old & mask) { -+ level = !!(val & (0x1 << i)); -+ ioapic_update_irq(state, i + off * 8, level); -+ } -+ mask = mask << 1; -+ } -+ } -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ *(uint8_t *)((void *)state->ext_bounce + off) = val; -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ old = *(uint8_t *)((void *)state->ext_isr + off); -+ *(uint8_t *)((void *)state->ext_isr + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 8; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ off = off & 0x1f; -+ old = *(uint8_t *)((void *)state->ext_coreisr[cpu] + off); -+ *(uint8_t *)((void *)state->ext_coreisr[cpu] + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 8; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ off -= EXTIOI_IPMAP_START; -+ val = val & 0xf; -+ *(uint8_t *)((void *)state->ext_ipmap + off) = val; -+ ipnum = 0; -+ for (i = 0; i < 4; i++) { -+ if (val & (0x1 << i)) { -+ ipnum = i; -+ break; -+ } -+ } -+ if (val) { -+ for (i = 0; i < 32; i++) { -+ cpu = off * 32 + i; -+ state->ext_sw_ipmap[cpu] = ipnum; -+ } -+ } -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ off -= EXTIOI_COREMAP_START; -+ val = val & 0xff; -+ *(uint8_t *)((void *)state->ext_coremap + off) = val; -+ state->ext_sw_coremap[off] = val; -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ *(uint8_t *)((void *)state->ext_nodetype + off) = val; -+ } -+ -+ DPRINTF("writeb reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, val); -+} -+ -+static void apic_writew(void *opaque, hwaddr addr, uint32_t val) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint16_t old; -+ int cpu, i, level, mask; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ old = *(uint16_t *)((void *)state->ext_en + off); -+ if (old != val) { -+ *(uint16_t *)((void *)state->ext_en + off) = val; -+ old = old ^ val; -+ mask = 0x1; -+ for (i = 0; i < 16; i++) { -+ if (old & mask) { -+ level = !!(val & (0x1 << i)); -+ ioapic_update_irq(state, i + off * 8, level); -+ } -+ mask = mask << 1; -+ } -+ } -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ *(uint16_t *)((void *)state->ext_bounce + off) = val; -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ old = *(uint16_t *)((void *)state->ext_isr + off); -+ *(uint16_t *)((void *)state->ext_isr + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 16; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ off = off & 0x1f; -+ old = *(uint16_t *)((void *)state->ext_coreisr[cpu] + off); -+ *(uint16_t *)((void *)state->ext_coreisr[cpu] + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 16; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ apic_writeb(opaque, addr, val & 0xff); -+ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); -+ -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ apic_writeb(opaque, addr, val & 0xff); -+ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); -+ -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ *(uint16_t *)((void *)state->ext_nodetype + off) = val; -+ } -+ -+ DPRINTF("writew reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, val); -+} -+ -+static void apic_writel(void *opaque, hwaddr addr, uint32_t val) -+{ -+ nodeApicState *node; -+ apicState *state; -+ unsigned long off; -+ uint32_t old; -+ int cpu, i, level, mask; -+ -+ node = (nodeApicState *)opaque; -+ state = node->apic; -+ off = addr & 0xfffff; -+ if ((off >= EXTIOI_ENABLE_START) && (off < EXTIOI_ENABLE_END)) { -+ off -= EXTIOI_ENABLE_START; -+ old = *(uint32_t *)((void *)state->ext_en + off); -+ if (old != val) { -+ *(uint32_t *)((void *)state->ext_en + off) = val; -+ old = old ^ val; -+ mask = 0x1; -+ for (i = 0; i < 32; i++) { -+ if (old & mask) { -+ level = !!(val & (0x1 << i)); -+ ioapic_update_irq(state, i + off * 8, level); -+ } -+ mask = mask << 1; -+ } -+ } -+ } else if ((off >= EXTIOI_BOUNCE_START) && (off < EXTIOI_BOUNCE_END)) { -+ off -= EXTIOI_BOUNCE_START; -+ *(uint32_t *)((void *)state->ext_bounce + off) = val; -+ } else if ((off >= EXTIOI_ISR_START) && (off < EXTIOI_ISR_END)) { -+ off -= EXTIOI_ISR_START; -+ old = *(uint32_t *)((void *)state->ext_isr + off); -+ *(uint32_t *)((void *)state->ext_isr + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 32; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_COREISR_START) && (off < EXTIOI_COREISR_END)) { -+ off -= EXTIOI_COREISR_START; -+ cpu = (off >> 8) & 0xff; -+ off = off & 0x1f; -+ old = *(uint32_t *)((void *)state->ext_coreisr[cpu] + off); -+ *(uint32_t *)((void *)state->ext_coreisr[cpu] + off) = old & ~val; -+ mask = 0x1; -+ for (i = 0; i < 32; i++) { -+ if ((old & mask) && (val & mask)) { -+ ioapic_update_irq(state, i + off * 8, 0); -+ } -+ mask = mask << 1; -+ } -+ } else if ((off >= EXTIOI_IPMAP_START) && (off < EXTIOI_IPMAP_END)) { -+ apic_writeb(opaque, addr, val & 0xff); -+ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); -+ apic_writeb(opaque, addr + 2, (val >> 16) & 0xff); -+ apic_writeb(opaque, addr + 3, (val >> 24) & 0xff); -+ -+ } else if ((off >= EXTIOI_COREMAP_START) && (off < EXTIOI_COREMAP_END)) { -+ apic_writeb(opaque, addr, val & 0xff); -+ apic_writeb(opaque, addr + 1, (val >> 8) & 0xff); -+ apic_writeb(opaque, addr + 2, (val >> 16) & 0xff); -+ apic_writeb(opaque, addr + 3, (val >> 24) & 0xff); -+ -+ } else if ((off >= EXTIOI_NODETYPE_START) && (off < EXTIOI_NODETYPE_END)) { -+ off -= EXTIOI_NODETYPE_START; -+ *(uint32_t *)((void *)state->ext_nodetype + off) = val; -+ } -+ -+ DPRINTF("writel reg 0x" TARGET_FMT_plx " = %x\n", node->addr + addr, val); -+} -+ -+static uint64_t apic_readfn(void *opaque, hwaddr addr, -+ unsigned size) -+{ -+ switch (size) { -+ case 1: -+ return apic_readb(opaque, addr); -+ case 2: -+ return apic_readw(opaque, addr); -+ case 4: -+ return apic_readl(opaque, addr); -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void apic_writefn(void *opaque, hwaddr addr, -+ uint64_t value, unsigned size) -+{ -+ switch (size) { -+ case 1: -+ apic_writeb(opaque, addr, value); -+ break; -+ case 2: -+ apic_writew(opaque, addr, value); -+ break; -+ case 4: -+ apic_writel(opaque, addr, value); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static const VMStateDescription vmstate_apic = { -+ .name = "apic", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = ext_irq_pre_save, -+ .post_load = ext_irq_post_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT8_ARRAY(ext_en, apicState, EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_UINT8_ARRAY(ext_bounce, apicState, EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_UINT8_ARRAY(ext_isr, apicState, EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_UINT8_2DARRAY(ext_coreisr, apicState, MAX_CORES, -+ EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_UINT8_ARRAY(ext_ipmap, apicState, EXTIOI_IRQS_IPMAP_SIZE), -+ VMSTATE_UINT8_ARRAY(ext_coremap, apicState, EXTIOI_IRQS), -+ VMSTATE_UINT16_ARRAY(ext_nodetype, apicState, 16), -+ VMSTATE_UINT64(ext_control, apicState), -+ VMSTATE_UINT8_ARRAY(ext_sw_ipmap, apicState, EXTIOI_IRQS), -+ VMSTATE_UINT8_ARRAY(ext_sw_coremap, apicState, EXTIOI_IRQS), -+ VMSTATE_UINT8_2DARRAY(ext_ipisr, apicState, MAX_CORES * LS3A_INTC_IP, -+ EXTIOI_IRQS_BITMAP_SIZE), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const MemoryRegionOps apic_ops = { -+ .read = apic_readfn, -+ .write = apic_writefn, -+ .impl.min_access_size = 1, -+ .impl.max_access_size = 4, -+ .valid.min_access_size = 1, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+}; -+ -+int cpu_init_apic(LoongarchMachineState *ms, CPULOONGARCHState *env, int cpu) -+{ -+ apicState *apic; -+ nodeApicState *node; -+ MemoryRegion *iomem; -+ unsigned long base; -+ int pin; -+ char str[32]; -+ -+ if (ms->apic == NULL) { -+ apic = g_malloc0(sizeof(apicState)); -+ vmstate_register(NULL, 0, &vmstate_apic, apic); -+ apic->irq = qemu_allocate_irqs(ioapic_setirq, apic, EXTIOI_IRQS); -+ -+ for (pin = 0; pin < LS3A_INTC_IP; pin++) { -+ /* cpu_pin[9:2] <= intc_pin[7:0] */ -+ apic->parent_irq[cpu][pin] = env->irq[pin + 2]; -+ } -+ ms->apic = apic; -+ -+ if (cpu == 0) { -+ base = APIC_BASE; -+ node = g_malloc0(sizeof(nodeApicState)); -+ node->apic = ms->apic; -+ node->addr = base; -+ -+ iomem = g_new(MemoryRegion, 1); -+ sprintf(str, "apic%d", cpu); -+ /* extioi addr 0x1f010000~0x1f02ffff */ -+ memory_region_init_io(iomem, NULL, &apic_ops, node, str, 0x20000); -+ memory_region_add_subregion(get_system_memory(), base, iomem); -+ } -+ -+ } else { -+ if (cpu != 0) { -+ for (pin = 0; pin < LS3A_INTC_IP; pin++) { -+ ms->apic->parent_irq[cpu][pin] = env->irq[pin + 2]; -+ } -+ } -+ } -+ return 0; -+} -+ -diff --git a/hw/loongarch/ioapic.c b/hw/loongarch/ioapic.c -new file mode 100644 -index 000000000..3de0ed88d ---- /dev/null -+++ b/hw/loongarch/ioapic.c -@@ -0,0 +1,422 @@ -+/* -+ * LS7A1000 Northbridge IOAPIC support -+ * -+ * Copyright (c) 2019 Loongarch Technology -+ * Authors: -+ * Zhu Chen -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/sysbus.h" -+#include "hw/irq.h" -+#include "qemu/log.h" -+#include "sysemu/kvm.h" -+#include "linux/kvm.h" -+#include "migration/vmstate.h" -+ -+#define DEBUG_LS7A_APIC 0 -+ -+#define DPRINTF(fmt, ...) \ -+do { \ -+ if (DEBUG_LS7A_APIC) { \ -+ fprintf(stderr, "IOAPIC: " fmt , ## __VA_ARGS__); \ -+ } \ -+} while (0) -+ -+#define TYPE_LS7A_APIC "ioapic" -+#define LS7A_APIC(obj) OBJECT_CHECK(LS7AApicState, (obj), TYPE_LS7A_APIC) -+ -+#define LS7A_IOAPIC_ROUTE_ENTRY_OFFSET 0x100 -+#define LS7A_IOAPIC_INT_ID_OFFSET 0x00 -+#define LS7A_INT_ID_VAL 0x7000000UL -+#define LS7A_INT_ID_VER 0x1f0001UL -+#define LS7A_IOAPIC_INT_MASK_OFFSET 0x20 -+#define LS7A_IOAPIC_INT_EDGE_OFFSET 0x60 -+#define LS7A_IOAPIC_INT_CLEAR_OFFSET 0x80 -+#define LS7A_IOAPIC_INT_STATUS_OFFSET 0x3a0 -+#define LS7A_IOAPIC_INT_POL_OFFSET 0x3e0 -+#define LS7A_IOAPIC_HTMSI_EN_OFFSET 0x40 -+#define LS7A_IOAPIC_HTMSI_VEC_OFFSET 0x200 -+#define LS7A_AUTO_CTRL0_OFFSET 0xc0 -+#define LS7A_AUTO_CTRL1_OFFSET 0xe0 -+ -+typedef struct LS7AApicState { -+ SysBusDevice parent_obj; -+ qemu_irq parent_irq[257]; -+ uint64_t int_id; -+ uint64_t int_mask; /*0x020 interrupt mask register*/ -+ uint64_t htmsi_en;/*0x040 1=msi*/ -+ uint64_t intedge; /*0x060 edge=1 level =0*/ -+ uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/ -+ uint64_t auto_crtl0; /*0x0c0*/ -+ uint64_t auto_crtl1; /*0x0e0*/ -+ uint8_t route_entry[64]; /*0x100 - 0x140*/ -+ uint8_t htmsi_vector[64]; /*0x200 - 0x240*/ -+ uint64_t intisr_chip0; /*0x300*/ -+ uint64_t intisr_chip1;/*0x320*/ -+ uint64_t last_intirr; /* edge detection */ -+ uint64_t intirr; /* 0x380 interrupt request register */ -+ uint64_t intisr; /* 0x3a0 interrupt service register */ -+ uint64_t int_polarity; /*0x3e0 interrupt level polarity -+ selection register 0 for high level tirgger*/ -+ MemoryRegion iomem; -+} LS7AApicState; -+ -+static void update_irq(LS7AApicState *s) -+{ -+ int i; -+ if ((s->intirr & (~s->int_mask)) & (~s->htmsi_en)) { -+ DPRINTF("7a update irqline up\n"); -+ s->intisr = (s->intirr & (~s->int_mask) & (~s->htmsi_en)); -+ qemu_set_irq(s->parent_irq[256], 1); -+ } else { -+ DPRINTF("7a update irqline down\n"); -+ s->intisr &= (~s->htmsi_en); -+ qemu_set_irq(s->parent_irq[256], 0); -+ } -+ if (s->htmsi_en) { -+ for (i = 0; i < 64; i++) { -+ if ((((~s->intisr) & s->intirr) & s->htmsi_en) & (1ULL << i)) { -+ s->intisr |= 1ULL << i; -+ qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 1); -+ } else if (((~(s->intisr | s->intirr)) & s->htmsi_en) & -+ (1ULL << i)) { -+ qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 0); -+ } -+ } -+ } -+} -+ -+static void irq_handler(void *opaque, int irq, int level) -+{ -+ LS7AApicState *s = opaque; -+ -+ assert(irq < 64); -+ uint64_t mask = 1ULL << irq; -+ DPRINTF("------ %s irq %d %d\n", __func__, irq, level); -+ -+ if (s->intedge & mask) { -+ /* edge triggered */ -+ /*TODO*/ -+ } else { -+ /* level triggered */ -+ if (level) { -+ s->intirr |= mask; -+ } else { -+ s->intirr &= ~mask; -+ } -+ -+ } -+ update_irq(s); -+ -+} -+ -+static uint64_t ls7a_apic_reg_read(void *opaque, hwaddr addr, unsigned size) -+{ -+ LS7AApicState *a = opaque; -+ uint64_t val = 0; -+ uint64_t offset; -+ int64_t offset_tmp; -+ offset = addr & 0xfff; -+ if (8 == size) { -+ switch (offset) { -+ case LS7A_IOAPIC_INT_ID_OFFSET: -+ val = LS7A_INT_ID_VER; -+ val = (val << 32) + LS7A_INT_ID_VAL; -+ break; -+ case LS7A_IOAPIC_INT_MASK_OFFSET: -+ val = a->int_mask; -+ break; -+ case LS7A_IOAPIC_INT_STATUS_OFFSET: -+ val = a->intisr & (~a->int_mask); -+ break; -+ case LS7A_IOAPIC_INT_EDGE_OFFSET: -+ val = a->intedge; -+ break; -+ case LS7A_IOAPIC_INT_POL_OFFSET: -+ val = a->int_polarity; -+ break; -+ case LS7A_IOAPIC_HTMSI_EN_OFFSET: -+ val = a->htmsi_en; -+ break; -+ case LS7A_AUTO_CTRL0_OFFSET: -+ case LS7A_AUTO_CTRL1_OFFSET: -+ break; -+ default: -+ break; -+ } -+ } else if (1 == size) { -+ if (offset >= LS7A_IOAPIC_HTMSI_VEC_OFFSET) { -+ offset_tmp = offset - LS7A_IOAPIC_HTMSI_VEC_OFFSET; -+ if (offset_tmp >= 0 && offset_tmp < 64) { -+ val = a->htmsi_vector[offset_tmp]; -+ } -+ } else if (offset >= LS7A_IOAPIC_ROUTE_ENTRY_OFFSET) { -+ offset_tmp = offset - LS7A_IOAPIC_ROUTE_ENTRY_OFFSET; -+ if (offset_tmp >= 0 && offset_tmp < 64) { -+ val = a->route_entry[offset_tmp]; -+ DPRINTF("addr %lx val %lx\n", addr, val); -+ } -+ } -+ } -+ DPRINTF(TARGET_FMT_plx" val %lx\n", addr, val); -+ return val; -+} -+ -+static void ls7a_apic_reg_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) -+{ -+ LS7AApicState *a = opaque; -+ int64_t offset_tmp; -+ uint64_t offset; -+ offset = addr & 0xfff; -+ DPRINTF(TARGET_FMT_plx" size %d val %lx\n", addr, size, data); -+ if (8 == size) { -+ switch (offset) { -+ case LS7A_IOAPIC_INT_MASK_OFFSET: -+ a->int_mask = data; -+ update_irq(a); -+ break; -+ case LS7A_IOAPIC_INT_STATUS_OFFSET: -+ a->intisr = data; -+ break; -+ case LS7A_IOAPIC_INT_EDGE_OFFSET: -+ a->intedge = data; -+ break; -+ case LS7A_IOAPIC_INT_CLEAR_OFFSET: -+ a->intisr &= (~data); -+ update_irq(a); -+ break; -+ case LS7A_IOAPIC_INT_POL_OFFSET: -+ a->int_polarity = data; -+ break; -+ case LS7A_IOAPIC_HTMSI_EN_OFFSET: -+ a->htmsi_en = data; -+ break; -+ case LS7A_AUTO_CTRL0_OFFSET: -+ case LS7A_AUTO_CTRL1_OFFSET: -+ break; -+ default: -+ break; -+ } -+ } else if (1 == size) { -+ if (offset >= LS7A_IOAPIC_HTMSI_VEC_OFFSET) { -+ offset_tmp = offset - LS7A_IOAPIC_HTMSI_VEC_OFFSET; -+ if (offset_tmp >= 0 && offset_tmp < 64) { -+ a->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); -+ } -+ } else if (offset >= LS7A_IOAPIC_ROUTE_ENTRY_OFFSET) { -+ offset_tmp = offset - LS7A_IOAPIC_ROUTE_ENTRY_OFFSET; -+ if (offset_tmp >= 0 && offset_tmp < 64) { -+ a->route_entry[offset_tmp] = (uint8_t)(data & 0xff); -+ } -+ } -+ } -+} -+ -+static const MemoryRegionOps ls7a_apic_ops = { -+ .read = ls7a_apic_reg_read, -+ .write = ls7a_apic_reg_write, -+ .valid = { -+ .min_access_size = 1, -+ .max_access_size = 8, -+ }, -+ .impl = { -+ .min_access_size = 1, -+ .max_access_size = 8, -+ }, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+}; -+ -+static int kvm_ls7a_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ LS7AApicState *s = opaque; -+ struct loongarch_kvm_irqchip *chip; -+ struct ls7a_ioapic_state *state; -+ int ret, i, length; -+ -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+ -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct ls7a_ioapic_state); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS7A_IOAPIC; -+ chip->len = length; -+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ state = (struct ls7a_ioapic_state *)chip->data; -+ s->int_id = state->int_id; -+ s->int_mask = state->int_mask; -+ s->htmsi_en = state->htmsi_en; -+ s->intedge = state->intedge; -+ s->intclr = state->intclr; -+ s->auto_crtl0 = state->auto_crtl0; -+ s->auto_crtl1 = state->auto_crtl1; -+ for (i = 0; i < 64; i++) { -+ s->route_entry[i] = state->route_entry[i]; -+ s->htmsi_vector[i] = state->htmsi_vector[i]; -+ } -+ s->intisr_chip0 = state->intisr_chip0; -+ s->intisr_chip1 = state->intisr_chip1; -+ s->intirr = state->intirr; -+ s->intisr = state->intisr; -+ s->int_polarity = state->int_polarity; -+ g_free(chip); -+#endif -+ return 0; -+} -+ -+static int kvm_ls7a_post_load(void *opaque, int version) -+{ -+#ifdef CONFIG_KVM -+ LS7AApicState *s = opaque; -+ struct loongarch_kvm_irqchip *chip; -+ struct ls7a_ioapic_state *state; -+ int ret, i, length; -+ -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct ls7a_ioapic_state); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS7A_IOAPIC; -+ chip->len = length; -+ -+ state = (struct ls7a_ioapic_state *)chip->data; -+ state->int_id = s->int_id; -+ state->int_mask = s->int_mask; -+ state->htmsi_en = s->htmsi_en; -+ state->intedge = s->intedge; -+ state->intclr = s->intclr; -+ state->auto_crtl0 = s->auto_crtl0; -+ state->auto_crtl1 = s->auto_crtl1; -+ for (i = 0; i < 64; i++) { -+ state->route_entry[i] = s->route_entry[i]; -+ state->htmsi_vector[i] = s->htmsi_vector[i]; -+ } -+ state->intisr_chip0 = s->intisr_chip0; -+ state->intisr_chip1 = s->intisr_chip1; -+ state->last_intirr = 0; -+ state->intirr = s->intirr; -+ state->intisr = s->intisr; -+ state->int_polarity = s->int_polarity; -+ -+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ g_free(chip); -+#endif -+ return 0; -+} -+ -+static void ls7a_apic_reset(DeviceState *d) -+{ -+ LS7AApicState *s = LS7A_APIC(d); -+ int i; -+ -+ s->int_id = 0x001f000107000000; -+ s->int_mask = 0xffffffffffffffff; -+ s->htmsi_en = 0x0; -+ s->intedge = 0x0; -+ s->intclr = 0x0; -+ s->auto_crtl0 = 0x0; -+ s->auto_crtl1 = 0x0; -+ for (i = 0; i < 64; i++) { -+ s->route_entry[i] = 0x1; -+ s->htmsi_vector[i] = 0x0; -+ } -+ s->intisr_chip0 = 0x0; -+ s->intisr_chip1 = 0x0; -+ s->intirr = 0x0; -+ s->intisr = 0x0; -+ s->int_polarity = 0x0; -+ kvm_ls7a_post_load(s, 0); -+} -+ -+static void ls7a_apic_init(Object *obj) -+{ -+ DeviceState *dev = DEVICE(obj); -+ LS7AApicState *s = LS7A_APIC(obj); -+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj); -+ int tmp; -+ memory_region_init_io(&s->iomem, obj, &ls7a_apic_ops, s, TYPE_LS7A_APIC, 0x1000); -+ sysbus_init_mmio(sbd, &s->iomem); -+ for (tmp = 0; tmp < 257; tmp++) { -+ sysbus_init_irq(sbd, &s->parent_irq[tmp]); -+ } -+ qdev_init_gpio_in(dev, irq_handler, 64); -+} -+ -+static const VMStateDescription vmstate_ls7a_apic = { -+ .name = TYPE_LS7A_APIC, -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = kvm_ls7a_pre_save, -+ .post_load = kvm_ls7a_post_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT64(int_mask, LS7AApicState), -+ VMSTATE_UINT64(htmsi_en, LS7AApicState), -+ VMSTATE_UINT64(intedge, LS7AApicState), -+ VMSTATE_UINT64(intclr, LS7AApicState), -+ VMSTATE_UINT64(auto_crtl0, LS7AApicState), -+ VMSTATE_UINT64(auto_crtl1, LS7AApicState), -+ VMSTATE_UINT8_ARRAY(route_entry, LS7AApicState, 64), -+ VMSTATE_UINT8_ARRAY(htmsi_vector, LS7AApicState, 64), -+ VMSTATE_UINT64(intisr_chip0, LS7AApicState), -+ VMSTATE_UINT64(intisr_chip1, LS7AApicState), -+ VMSTATE_UINT64(last_intirr, LS7AApicState), -+ VMSTATE_UINT64(intirr, LS7AApicState), -+ VMSTATE_UINT64(intisr, LS7AApicState), -+ VMSTATE_UINT64(int_polarity, LS7AApicState), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static void ls7a_apic_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ -+ dc->reset = ls7a_apic_reset; -+ dc->vmsd = &vmstate_ls7a_apic; -+} -+ -+static const TypeInfo ls7a_apic_info = { -+ .name = TYPE_LS7A_APIC, -+ .parent = TYPE_SYS_BUS_DEVICE, -+ .instance_size = sizeof(LS7AApicState), -+ .instance_init = ls7a_apic_init, -+ .class_init = ls7a_apic_class_init, -+}; -+ -+static void ls7a_apic_register_types(void) -+{ -+ type_register_static(&ls7a_apic_info); -+} -+ -+type_init(ls7a_apic_register_types) -diff --git a/hw/loongarch/iocsr.c b/hw/loongarch/iocsr.c -new file mode 100644 -index 000000000..14521c2d5 ---- /dev/null -+++ b/hw/loongarch/iocsr.c -@@ -0,0 +1,219 @@ -+/* -+ * LOONGARCH IOCSR support -+ * -+ * Copyright (c) 2021 Loongarch Technology -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/sysbus.h" -+#include "qemu/log.h" -+#include "sysemu/kvm.h" -+#include "linux/kvm.h" -+#include "migration/vmstate.h" -+#include "hw/boards.h" -+#include "hw/loongarch/larch.h" -+ -+#define BIT_ULL(nr) (1ULL << (nr)) -+#define LOONGARCH_IOCSR_FEATURES 0x8 -+#define IOCSRF_TEMP BIT_ULL(0) -+#define IOCSRF_NODECNT BIT_ULL(1) -+#define IOCSRF_MSI BIT_ULL(2) -+#define IOCSRF_EXTIOI BIT_ULL(3) -+#define IOCSRF_CSRIPI BIT_ULL(4) -+#define IOCSRF_FREQCSR BIT_ULL(5) -+#define IOCSRF_FREQSCALE BIT_ULL(6) -+#define IOCSRF_DVFSV1 BIT_ULL(7) -+#define IOCSRF_GMOD BIT_ULL(9) -+#define IOCSRF_VM BIT_ULL(11) -+#define LOONGARCH_IOCSR_VENDOR 0x10 -+#define LOONGARCH_IOCSR_CPUNAME 0x20 -+#define LOONGARCH_IOCSR_NODECNT 0x408 -+#define LOONGARCH_IOCSR_MISC_FUNC 0x420 -+#define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21) -+#define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48) -+ -+enum { -+ IOCSR_FEATURES, -+ IOCSR_VENDOR, -+ IOCSR_CPUNAME, -+ IOCSR_NODECNT, -+ IOCSR_MISC_FUNC, -+ IOCSR_MAX -+}; -+ -+static uint32_t iocsr_array[IOCSR_MAX] = { -+ [IOCSR_FEATURES] = LOONGARCH_IOCSR_FEATURES, -+ [IOCSR_VENDOR] = LOONGARCH_IOCSR_VENDOR, -+ [IOCSR_CPUNAME] = LOONGARCH_IOCSR_CPUNAME, -+ [IOCSR_NODECNT] = LOONGARCH_IOCSR_NODECNT, -+ [IOCSR_MISC_FUNC] = LOONGARCH_IOCSR_MISC_FUNC, -+}; -+ -+ -+#define TYPE_IOCSR "iocsr" -+#define IOCSR(obj) OBJECT_CHECK(IOCSRState, (obj), TYPE_IOCSR) -+ -+typedef struct IOCSRState { -+ SysBusDevice parent_obj; -+ uint64_t iocsr_val[IOCSR_MAX]; -+} IOCSRState; -+ -+IOCSRState iocsr_init = { -+ .iocsr_val = { -+ IOCSRF_NODECNT | IOCSRF_MSI | IOCSRF_EXTIOI -+ | IOCSRF_CSRIPI | IOCSRF_GMOD | IOCSRF_VM, -+ 0x6e6f73676e6f6f4c, /* Loongson */ -+ 0x303030354133, /*3A5000*/ -+ 0x4, -+ 0x0, -+ } -+}; -+ -+static int kvm_iocsr_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ IOCSRState *s = opaque; -+ struct kvm_iocsr_entry entry; -+ int i = 0; -+ for (i = 0; i < IOCSR_MAX; i++) { -+ entry.addr = iocsr_array[i]; -+ kvm_vm_ioctl(kvm_state, KVM_LOONGARCH_GET_IOCSR, &entry); -+ s->iocsr_val[i] = entry.data; -+ } -+#endif -+ return 0; -+} -+ -+static int kvm_iocsr_post_load(void *opaque, int version) -+{ -+#ifdef CONFIG_KVM -+ IOCSRState *s = opaque; -+ struct kvm_iocsr_entry entry; -+ int i = 0; -+ -+ if (!kvm_enabled()) { -+ return 0; -+ } -+ -+ for (i = 0; i < IOCSR_MAX; i++) { -+ entry.addr = iocsr_array[i]; -+ entry.data = s->iocsr_val[i]; -+ kvm_vm_ioctl(kvm_state, KVM_LOONGARCH_SET_IOCSR, &entry); -+ } -+#endif -+ return 0; -+} -+ -+static void iocsr_reset(DeviceState *d) -+{ -+ IOCSRState *s = IOCSR(d); -+ int i; -+ -+ for (i = 0; i < IOCSR_MAX; i++) { -+ s->iocsr_val[i] = iocsr_init.iocsr_val[i]; -+ } -+ kvm_iocsr_post_load(s, 0); -+} -+static void init_vendor_cpuname(uint64_t *vendor, -+ uint64_t *cpu_name, char *cpuname) -+{ -+ int i = 0, len = 0; -+ char *index = NULL, *index_end = NULL; -+ char *vendor_c = (char *)vendor; -+ char *cpu_name_c = (char *)cpu_name; -+ -+ index = strstr(cpuname, "-"); -+ len = strlen(cpuname); -+ if ((index == NULL) || (len <= 0)) { -+ return ; -+ } -+ -+ *vendor = 0; -+ *cpu_name = 0; -+ index_end = cpuname + len; -+ -+ while (((cpuname + i) < index) && (i < sizeof(uint64_t))) { -+ vendor_c[i] = cpuname[i]; -+ i++; -+ } -+ -+ index += 1; -+ i = 0; -+ -+ while (((index + i) < index_end) && (i < sizeof(uint64_t))) { -+ cpu_name_c[i] = index[i]; -+ i++; -+ } -+ -+ return ; -+} -+ -+static void iocsr_instance_init(Object *obj) -+{ -+ IOCSRState *s = IOCSR(obj); -+ int i; -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ -+ init_vendor_cpuname((uint64_t *)&iocsr_init.iocsr_val[IOCSR_VENDOR], -+ (uint64_t *)&iocsr_init.iocsr_val[IOCSR_CPUNAME], -+ lsmc->cpu_name); -+ -+ for (i = 0; i < IOCSR_MAX; i++) { -+ s->iocsr_val[i] = iocsr_init.iocsr_val[i]; -+ } -+} -+ -+static const VMStateDescription vmstate_iocsr = { -+ .name = TYPE_IOCSR, -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = kvm_iocsr_pre_save, -+ .post_load = kvm_iocsr_post_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT64_ARRAY(iocsr_val, IOCSRState, IOCSR_MAX), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static void iocsr_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ -+ dc->reset = iocsr_reset; -+ dc->vmsd = &vmstate_iocsr; -+ -+} -+ -+static const TypeInfo iocsr_info = { -+ .name = TYPE_IOCSR, -+ .parent = TYPE_SYS_BUS_DEVICE, -+ .instance_size = sizeof(IOCSRState), -+ .instance_init = iocsr_instance_init, -+ .class_init = iocsr_class_init, -+}; -+ -+static void iocsr_register_types(void) -+{ -+ type_register_static(&iocsr_info); -+} -+ -+type_init(iocsr_register_types) -diff --git a/hw/loongarch/ipi.c b/hw/loongarch/ipi.c -new file mode 100644 -index 000000000..ade182abc ---- /dev/null -+++ b/hw/loongarch/ipi.c -@@ -0,0 +1,267 @@ -+#include "qemu/osdep.h" -+#include "qemu/units.h" -+#include "qapi/error.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/loongarch/cpudevs.h" -+#include "sysemu/sysemu.h" -+#include "sysemu/cpus.h" -+#include "sysemu/kvm.h" -+#include "hw/core/cpu.h" -+#include "qemu/log.h" -+#include "hw/loongarch/bios.h" -+#include "elf.h" -+#include "linux/kvm.h" -+#include "hw/loongarch/larch.h" -+#include "hw/loongarch/ls7a.h" -+#include "migration/vmstate.h" -+ -+static int gipi_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ gipiState *state = opaque; -+ struct loongarch_gipiState *kstate; -+ struct loongarch_kvm_irqchip *chip; -+ int ret, i, j, length; -+#endif -+ -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+ -+#ifdef CONFIG_KVM -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct loongarch_gipiState); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS3A_GIPI; -+ chip->len = length; -+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ -+ kstate = (struct loongarch_gipiState *)chip->data; -+ -+ for (i = 0; i < MAX_GIPI_CORE_NUM; i++) { -+ state->core[i].status = kstate->core[i].status; -+ state->core[i].en = kstate->core[i].en; -+ state->core[i].set = kstate->core[i].set; -+ state->core[i].clear = kstate->core[i].clear; -+ for (j = 0; j < MAX_GIPI_MBX_NUM; j++) { -+ state->core[i].buf[j] = kstate->core[i].buf[j]; -+ } -+ } -+ g_free(chip); -+#endif -+ -+ return 0; -+} -+ -+static int gipi_post_load(void *opaque, int version) -+{ -+#ifdef CONFIG_KVM -+ gipiState *state = opaque; -+ struct loongarch_gipiState *kstate; -+ struct loongarch_kvm_irqchip *chip; -+ int ret, i, j, length; -+#endif -+ -+ if (!kvm_irqchip_in_kernel()) { -+ return 0; -+ } -+ -+#ifdef CONFIG_KVM -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct loongarch_gipiState); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS3A_GIPI; -+ chip->len = length; -+ kstate = (struct loongarch_gipiState *)chip->data; -+ -+ for (i = 0; i < MAX_GIPI_CORE_NUM; i++) { -+ kstate->core[i].status = state->core[i].status; -+ kstate->core[i].en = state->core[i].en; -+ kstate->core[i].set = state->core[i].set; -+ kstate->core[i].clear = state->core[i].clear; -+ for (j = 0; j < MAX_GIPI_MBX_NUM; j++) { -+ kstate->core[i].buf[j] = state->core[i].buf[j]; -+ } -+ } -+ -+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ if (ret < 0) { -+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); -+ abort(); -+ } -+ g_free(chip); -+#endif -+ -+ return 0; -+} -+ -+static const VMStateDescription vmstate_gipi_core = { -+ .name = "gipi-single", -+ .version_id = 0, -+ .minimum_version_id = 0, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT32(status, gipi_core), -+ VMSTATE_UINT32(en, gipi_core), -+ VMSTATE_UINT32(set, gipi_core), -+ VMSTATE_UINT32(clear, gipi_core), -+ VMSTATE_UINT64_ARRAY(buf, gipi_core, MAX_GIPI_MBX_NUM), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static const VMStateDescription vmstate_gipi = { -+ .name = "gipi", -+ .pre_save = gipi_pre_save, -+ .post_load = gipi_post_load, -+ .version_id = 0, -+ .minimum_version_id = 0, -+ .fields = (VMStateField[]) { -+ VMSTATE_STRUCT_ARRAY(core, gipiState, MAX_GIPI_CORE_NUM, 0, -+ vmstate_gipi_core, gipi_core), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+static void gipi_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) -+{ -+ gipi_core *s = opaque; -+ gipi_core *ss; -+ void *pbuf; -+ uint32_t cpu, action_data, mailaddr; -+ LoongarchMachineState *ms = LoongarchMACHINE(qdev_get_machine()); -+ -+ if ((size != 4) && (size != 8)) { -+ hw_error("size not 4 and not 8"); -+ } -+ addr &= 0xff; -+ switch (addr) { -+ case CORE0_STATUS_OFF: -+ hw_error("CORE0_STATUS_OFF Can't be write\n"); -+ break; -+ case CORE0_EN_OFF: -+ s->en = val; -+ break; -+ case CORE0_IPI_SEND: -+ cpu = (val >> 16) & 0x3ff; -+ action_data = 1UL << (val & 0x1f); -+ ss = &ms->gipi->core[cpu]; -+ ss->status |= action_data; -+ if (ss->status != 0) { -+ qemu_irq_raise(ss->irq); -+ } -+ break; -+ case CORE0_MAIL_SEND: -+ cpu = (val >> 16) & 0x3ff; -+ mailaddr = (val >> 2) & 0x7; -+ ss = &ms->gipi->core[cpu]; -+ pbuf = (void *)ss->buf + mailaddr * 4; -+ *(unsigned int *)pbuf = (val >> 32); -+ break; -+ case CORE0_SET_OFF: -+ hw_error("CORE0_SET_OFF Can't be write\n"); -+ break; -+ case CORE0_CLEAR_OFF: -+ s->status ^= val; -+ if (s->status == 0) { -+ qemu_irq_lower(s->irq); -+ } -+ break; -+ case 0x20 ... 0x3c: -+ pbuf = (void *)s->buf + (addr - 0x20); -+ if (size == 1) { -+ *(unsigned char *)pbuf = (unsigned char)val; -+ } else if (size == 2) { -+ *(unsigned short *)pbuf = (unsigned short)val; -+ } else if (size == 4) { -+ *(unsigned int *)pbuf = (unsigned int)val; -+ } else if (size == 8) { -+ *(unsigned long *)pbuf = (unsigned long)val; -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static uint64_t gipi_readl(void *opaque, hwaddr addr, unsigned size) -+{ -+ gipi_core *s = opaque; -+ uint64_t ret = 0; -+ void *pbuf; -+ -+ addr &= 0xff; -+ if ((size != 4) && (size != 8)) { -+ hw_error("size not 4 and not 8 size:%d\n", size); -+ } -+ switch (addr) { -+ case CORE0_STATUS_OFF: -+ ret = s->status; -+ break; -+ case CORE0_EN_OFF: -+ ret = s->en; -+ break; -+ case CORE0_SET_OFF: -+ ret = 0; -+ break; -+ case CORE0_CLEAR_OFF: -+ ret = 0; -+ break; -+ case 0x20 ... 0x3c: -+ pbuf = (void *)s->buf + (addr - 0x20); -+ if (size == 1) { -+ ret = *(unsigned char *)pbuf; -+ } else if (size == 2) { -+ ret = *(unsigned short *)pbuf; -+ } else if (size == 4) { -+ ret = *(unsigned int *)pbuf; -+ } else if (size == 8) { -+ ret = *(unsigned long *)pbuf; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+static const MemoryRegionOps gipi_ops = { -+ .read = gipi_readl, -+ .write = gipi_writel, -+ .valid = { -+ .min_access_size = 4, -+ .max_access_size = 8, -+ }, -+ .impl = { -+ .min_access_size = 4, -+ .max_access_size = 8, -+ }, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+}; -+ -+int cpu_init_ipi(LoongarchMachineState *ms, qemu_irq parent, int cpu) -+{ -+ hwaddr addr; -+ MemoryRegion *region; -+ char str[32]; -+ -+ if (ms->gipi == NULL) { -+ ms->gipi = g_malloc0(sizeof(gipiState)); -+ vmstate_register(NULL, 0, &vmstate_gipi, ms->gipi); -+ } -+ -+ ms->gipi->core[cpu].irq = parent; -+ -+ addr = SMP_GIPI_MAILBOX | (cpu << 8); -+ region = g_new(MemoryRegion, 1); -+ sprintf(str, "gipi%d", cpu); -+ memory_region_init_io(region, NULL, &gipi_ops, &ms->gipi->core[cpu], str, 0x100); -+ memory_region_add_subregion(get_system_memory(), addr, region); -+ return 0; -+} -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -new file mode 100644 -index 000000000..3db269274 ---- /dev/null -+++ b/hw/loongarch/larch_3a.c -@@ -0,0 +1,2026 @@ -+/* -+ * QEMU loongarch 3a develop board emulation -+ * -+ * Copyright (C) 2013-2014 qiaochong -+ * Copyright (C) 2016-2017 zhangshuangshuang -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#include "qemu/osdep.h" -+#include "qemu/units.h" -+#include "qapi/error.h" -+#include "qemu/datadir.h" -+#include "hw/hw.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/i386/pc.h" -+#include "hw/char/serial.h" -+#include "hw/isa/isa.h" -+#include "hw/qdev-core.h" -+#include "sysemu/sysemu.h" -+#include "sysemu/runstate.h" -+#include "sysemu/reset.h" -+#include "migration/vmstate.h" -+#include "sysemu/cpus.h" -+#include "hw/boards.h" -+#include "qemu/log.h" -+#include "hw/loongarch/bios.h" -+#include "hw/loader.h" -+#include "elf.h" -+#include "exec/address-spaces.h" -+#include "hw/ide.h" -+#include "hw/pci/pci_host.h" -+#include "hw/pci/msi.h" -+#include "linux/kvm.h" -+#include "sysemu/kvm.h" -+#include "sysemu/numa.h" -+#include "hw/rtc/mc146818rtc.h" -+#include "hw/irq.h" -+#include "net/net.h" -+#include "hw/timer/i8254.h" -+#include "hw/loongarch/larch.h" -+#include "hw/loongarch/ls7a.h" -+#include "hw/nvram/fw_cfg.h" -+#include "hw/firmware/smbios.h" -+#include "acpi-build.h" -+#include -+#include -+#include "sysemu/block-backend.h" -+#include "hw/block/flash.h" -+#include "sysemu/device_tree.h" -+#include "qapi/visitor.h" -+#include "qapi/qapi-visit-common.h" -+ -+#include -+ -+#define DMA64_SUPPORTED 0x2 -+#define MAX_IDE_BUS 2 -+ -+#define BOOTPARAM_PHYADDR 0x0ff00000ULL -+#define BOOTPARAM_ADDR (0x9000000000000000ULL + BOOTPARAM_PHYADDR) -+#define SMBIOS_PHYSICAL_ADDRESS 0x0fe00000 -+#define SMBIOS_SIZE_LIMIT 0x200000 -+#define RESERVED_SIZE_LIMIT 0x1100000 -+#define COMMAND_LINE_SIZE 4096 -+#define FW_CONF_ADDR 0x0fff0000 -+ -+#define PHYS_TO_VIRT(x) ((x) | 0x9000000000000000ULL) -+ -+#define TARGET_REALPAGE_MASK (TARGET_PAGE_MASK << 2) -+ -+#ifdef CONFIG_KVM -+#define LS_ISA_IO_SIZE 0x02000000 -+#define LS_ISA_MEM_SIZE 0x40000000 -+#else -+#define LS_ISA_IO_SIZE 0x00010000 -+#define LS_ISA_MEM_SIZE 0x01000000 -+#endif -+ -+#ifdef CONFIG_KVM -+#define align(x) (((x) + 63) & ~63) -+#else -+#define align(x) (((x) + 15) & ~15) -+#endif -+ -+#define DEBUG_LOONGARCH3A 0 -+#define FLASH_SECTOR_SIZE 4096 -+ -+#define DPRINTF(fmt, ...) \ -+ do { if (DEBUG_LOONGARCH3A) { fprintf(stderr, fmt, ## __VA_ARGS__); } } while (0) -+ -+#define DEFINE_LS3A5K_MACHINE(suffix, name, optionfn) \ -+ static void ls3a5k_init_##suffix(MachineState *machine) \ -+ { \ -+ ls3a5k_init(machine); \ -+ } \ -+ DEFINE_LOONGARCH_MACHINE(suffix, name, ls3a5k_init_##suffix, optionfn) -+ -+struct efi_memory_map_loongarch { -+ uint16_t vers; /* version of efi_memory_map */ -+ uint32_t nr_map; /* number of memory_maps */ -+ uint32_t mem_freq; /* memory frequence */ -+ struct mem_map { -+ uint32_t node_id; /* node_id which memory attached to */ -+ uint32_t mem_type; /* system memory, pci memory, pci io, etc. */ -+ uint64_t mem_start; /* memory map start address */ -+ uint32_t mem_size; /* each memory_map size, not the total size */ -+ } map[128]; -+} __attribute__((packed)); -+ -+enum loongarch_cpu_type { -+ Loongson3 = 0x1, -+ Loongson3_comp = 0x2 -+}; -+ -+struct GlobalProperty loongarch_compat[] = { -+ { -+ .driver = "rtl8139", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "e1000", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "virtio-net-pci", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "qxl-vga", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "VGA", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "cirrus-vga", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "virtio-vga", -+ .property = "romfile", -+ .value = "", -+ },{ -+ .driver = "vmware-svga", -+ .property = "romfile", -+ .value = "", -+ }, -+}; -+const size_t loongarch_compat_len = G_N_ELEMENTS(loongarch_compat); -+ -+/* -+ * Capability and feature descriptor structure for LOONGARCH CPU -+ */ -+struct efi_cpuinfo_loongarch { -+ uint16_t vers; /* version of efi_cpuinfo_loongarch */ -+ uint32_t processor_id; /* PRID, e.g. 6305, 6306 */ -+ enum loongarch_cpu_type cputype; /* 3A, 3B, etc. */ -+ uint32_t total_node; /* num of total numa nodes */ -+ uint16_t cpu_startup_core_id; /* Core id */ -+ uint16_t reserved_cores_mask; -+ uint32_t cpu_clock_freq; /* cpu_clock */ -+ uint32_t nr_cpus; -+} __attribute__((packed)); -+ -+#define MAX_UARTS 64 -+struct uart_device { -+ uint32_t iotype; /* see include/linux/serial_core.h */ -+ uint32_t uartclk; -+ uint32_t int_offset; -+ uint64_t uart_base; -+} __attribute__((packed)); -+ -+#define MAX_SENSORS 64 -+#define SENSOR_TEMPER 0x00000001 -+#define SENSOR_VOLTAGE 0x00000002 -+#define SENSOR_FAN 0x00000004 -+struct sensor_device { -+ char name[32]; /* a formal name */ -+ char label[64]; /* a flexible description */ -+ uint32_t type; /* SENSOR_* */ -+ uint32_t id; /* instance id of a sensor-class */ -+ uint32_t fan_policy; /* see arch/loongarch/include/ -+ asm/mach-loongarch/loongarch_hwmon.h */ -+ uint32_t fan_percent;/* only for constant speed policy */ -+ uint64_t base_addr; /* base address of device registers */ -+} __attribute__((packed)); -+ -+struct system_loongarch { -+ uint16_t vers; /* version of system_loongarch */ -+ uint32_t ccnuma_smp; /* 0: no numa; 1: has numa */ -+ uint32_t sing_double_channel;/* 1:single; 2:double */ -+ uint32_t nr_uarts; -+ struct uart_device uarts[MAX_UARTS]; -+ uint32_t nr_sensors; -+ struct sensor_device sensors[MAX_SENSORS]; -+ char has_ec; -+ char ec_name[32]; -+ uint64_t ec_base_addr; -+ char has_tcm; -+ char tcm_name[32]; -+ uint64_t tcm_base_addr; -+ uint64_t workarounds; /* see workarounds.h */ -+} __attribute__((packed)); -+ -+struct irq_source_routing_table { -+ uint16_t vers; -+ uint16_t size; -+ uint16_t rtr_bus; -+ uint16_t rtr_devfn; -+ uint32_t vendor; -+ uint32_t device; -+ uint32_t PIC_type; /* conform use HT or PCI to route to CPU-PIC */ -+ uint64_t ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ -+ uint64_t ht_enable; /* irqs used in this PIC */ -+ uint32_t node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ -+ uint64_t pci_mem_start_addr; -+ uint64_t pci_mem_end_addr; -+ uint64_t pci_io_start_addr; -+ uint64_t pci_io_end_addr; -+ uint64_t pci_config_addr; -+ uint32_t dma_mask_bits; -+ uint16_t dma_noncoherent; -+} __attribute__((packed)); -+ -+struct interface_info { -+ uint16_t vers; /* version of the specificition */ -+ uint16_t size; -+ uint8_t flag; -+ char description[64]; -+} __attribute__((packed)); -+ -+#define MAX_RESOURCE_NUMBER 128 -+struct resource_loongarch { -+ uint64_t start; /* resource start address */ -+ uint64_t end; /* resource end address */ -+ char name[64]; -+ uint32_t flags; -+}; -+ -+struct archdev_data {}; /* arch specific additions */ -+ -+struct board_devices { -+ char name[64]; /* hold the device name */ -+ uint32_t num_resources; /* number of device_resource */ -+ /* for each device's resource */ -+ struct resource_loongarch resource[MAX_RESOURCE_NUMBER]; -+ /* arch specific additions */ -+ struct archdev_data archdata; -+}; -+ -+struct loongarch_special_attribute { -+ uint16_t vers; /* version of this special */ -+ char special_name[64]; /* special_atribute_name */ -+ uint32_t loongarch_special_type; /* type of special device */ -+ /* for each device's resource */ -+ struct resource_loongarch resource[MAX_RESOURCE_NUMBER]; -+}; -+ -+struct loongarch_params { -+ uint64_t memory_offset; /* efi_memory_map_loongarch struct offset */ -+ uint64_t cpu_offset; /* efi_cpuinfo_loongarch struct offset */ -+ uint64_t system_offset; /* system_loongarch struct offset */ -+ uint64_t irq_offset; /* irq_source_routing_table struct offset */ -+ uint64_t interface_offset; /* interface_info struct offset */ -+ uint64_t special_offset; /* loongarch_special_attribute struct offset */ -+ uint64_t boarddev_table_offset; /* board_devices offset */ -+}; -+ -+struct smbios_tables { -+ uint16_t vers; /* version of smbios */ -+ uint64_t vga_bios; /* vga_bios address */ -+ struct loongarch_params lp; -+}; -+ -+struct efi_reset_system_t { -+ uint64_t ResetCold; -+ uint64_t ResetWarm; -+ uint64_t ResetType; -+ uint64_t Shutdown; -+ uint64_t DoSuspend; /* NULL if not support */ -+}; -+ -+struct efi_loongarch { -+ uint64_t mps; /* MPS table */ -+ uint64_t acpi; /* ACPI table (IA64 ext 0.71) */ -+ uint64_t acpi20; /* ACPI table (ACPI 2.0) */ -+ struct smbios_tables smbios; /* SM BIOS table */ -+ uint64_t sal_systab; /* SAL system table */ -+ uint64_t boot_info; /* boot info table */ -+}; -+ -+struct boot_params { -+ struct efi_loongarch efi; -+ struct efi_reset_system_t reset_system; -+}; -+ -+static struct _loaderparams { -+ unsigned long ram_size; -+ const char *kernel_filename; -+ const char *kernel_cmdline; -+ const char *initrd_filename; -+ unsigned long a0, a1, a2; -+} loaderparams; -+ -+static struct _firmware_config { -+ unsigned long ram_size; -+ unsigned int mem_freq; -+ unsigned int cpu_nr; -+ unsigned int cpu_clock_freq; -+} fw_config; -+ -+struct la_memmap_entry { -+ uint64_t address; -+ uint64_t length; -+ uint32_t type; -+ uint32_t reserved; -+} ; -+ -+static void *boot_params_buf; -+static void *boot_params_p; -+static struct la_memmap_entry *la_memmap_table; -+static unsigned la_memmap_entries; -+ -+CPULOONGARCHState *cpu_states[LOONGARCH_MAX_VCPUS]; -+ -+struct kvm_cpucfg ls3a5k_cpucfgs = { -+ .cpucfg[LOONGARCH_CPUCFG0] = CPUCFG0_3A5000_PRID, -+ .cpucfg[LOONGARCH_CPUCFG1] = CPUCFG1_ISGR64 | CPUCFG1_PAGING | -+ CPUCFG1_IOCSR | CPUCFG1_PABITS | CPUCFG1_VABITS | CPUCFG1_UAL | -+ CPUCFG1_RI | CPUCFG1_XI | CPUCFG1_RPLV | CPUCFG1_HUGEPG | -+ CPUCFG1_IOCSRBRD, -+ .cpucfg[LOONGARCH_CPUCFG2] = CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP | -+ CPUCFG2_FPVERS | CPUCFG2_LSX | CPUCFG2_LASX | CPUCFG2_COMPLEX | -+ CPUCFG2_CRYPTO | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | CPUCFG2_LSPW | -+ CPUCFG2_LAM, -+ .cpucfg[LOONGARCH_CPUCFG3] = CPUCFG3_CCDMA | CPUCFG3_SFB | CPUCFG3_UCACC | -+ CPUCFG3_LLEXC | CPUCFG3_SCDLY | CPUCFG3_LLDBAR | CPUCFG3_ITLBT | -+ CPUCFG3_ICACHET | CPUCFG3_SPW_LVL | CPUCFG3_SPW_HG_HF | CPUCFG3_RVA | -+ CPUCFG3_RVAMAX, -+ .cpucfg[LOONGARCH_CPUCFG4] = CCFREQ_100M, -+ .cpucfg[LOONGARCH_CPUCFG5] = CPUCFG5_CCMUL | CPUCFG5_CCDIV, -+ .cpucfg[LOONGARCH_CPUCFG6] = CPUCFG6_PMP | CPUCFG6_PAMVER | CPUCFG6_PMNUM | -+ CPUCFG6_PMBITS | CPUCFG6_UPM, -+ .cpucfg[LOONGARCH_CPUCFG16] = CPUCFG16_L1_IUPRE | CPUCFG16_L1_DPRE | -+ CPUCFG16_L2_IUPRE | CPUCFG16_L2_IUUNIFY | CPUCFG16_L2_IUPRIV | -+ CPUCFG16_L3_IUPRE | CPUCFG16_L3_IUUNIFY | CPUCFG16_L3_IUINCL, -+ .cpucfg[LOONGARCH_CPUCFG17] = CPUCFG17_L1I_WAYS_M | CPUCFG17_L1I_SETS_M | -+ CPUCFG17_L1I_SIZE_M, -+ .cpucfg[LOONGARCH_CPUCFG18] = CPUCFG18_L1D_WAYS_M | CPUCFG18_L1D_SETS_M | -+ CPUCFG18_L1D_SIZE_M, -+ .cpucfg[LOONGARCH_CPUCFG19] = CPUCFG19_L2_WAYS_M | CPUCFG19_L2_SETS_M | -+ CPUCFG19_L2_SIZE_M, -+ .cpucfg[LOONGARCH_CPUCFG20] = CPUCFG20_L3_WAYS_M | CPUCFG20_L3_SETS_M | -+ CPUCFG20_L3_SIZE_M, -+}; -+ -+bool loongarch_is_acpi_enabled(LoongarchMachineState *vms) -+{ -+ if (vms->acpi == ON_OFF_AUTO_OFF) { -+ return false; -+ } -+ return true; -+} -+static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(obj); -+ OnOffAuto acpi = lsms->acpi; -+ -+ visit_type_OnOffAuto(v, name, &acpi, errp); -+} -+ -+static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(obj); -+ -+ visit_type_OnOffAuto(v, name, &lsms->acpi, errp); -+} -+int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) -+{ -+ int i; -+ -+ for (i = 0; i < la_memmap_entries; i++) { -+ if (la_memmap_table[i].address == address) { -+ fprintf(stderr, "%s address:0x%lx length:0x%lx already exists\n", -+ __func__, address, length); -+ return 0; -+ } -+ } -+ -+ la_memmap_table = g_renew(struct la_memmap_entry, la_memmap_table, -+ la_memmap_entries + 1); -+ la_memmap_table[la_memmap_entries].address = cpu_to_le64(address); -+ la_memmap_table[la_memmap_entries].length = cpu_to_le64(length); -+ la_memmap_table[la_memmap_entries].type = cpu_to_le32(type); -+ la_memmap_entries++; -+ -+ return la_memmap_entries; -+} -+ -+static ram_addr_t get_hotplug_membase(ram_addr_t ram_size) -+{ -+ ram_addr_t sstart; -+ -+ if (ram_size <= 0x10000000) { -+ sstart = 0x90000000; -+ } else { -+ sstart = 0x90000000 + ROUND_UP((ram_size - 0x10000000), -+ LOONGARCH_HOTPLUG_MEM_ALIGN); -+ } -+ return sstart; -+} -+ -+static struct efi_memory_map_loongarch *init_memory_map(void *g_map) -+{ -+ struct efi_memory_map_loongarch *emap = g_map; -+ -+ emap->nr_map = 4; -+ emap->mem_freq = 266000000; -+ -+ emap->map[0].node_id = 0; -+ emap->map[0].mem_type = 1; -+ emap->map[0].mem_start = 0x0; -+#ifdef CONFIG_KVM -+ emap->map[0].mem_size = (loaderparams.ram_size > 0x10000000 -+ ? 256 : (loaderparams.ram_size >> 20)) - 18; -+#else -+ emap->map[0].mem_size = atoi(getenv("memsize")); -+#endif -+ -+ emap->map[1].node_id = 0; -+ emap->map[1].mem_type = 2; -+ emap->map[1].mem_start = 0x90000000; -+#ifdef CONFIG_KVM -+ emap->map[1].mem_size = (loaderparams.ram_size > 0x10000000 -+ ? (loaderparams.ram_size >> 20) - 256 : 0); -+#else -+ emap->map[1].mem_size = atoi(getenv("highmemsize")); -+#endif -+ -+ /* support for smbios */ -+ emap->map[2].node_id = 0; -+ emap->map[2].mem_type = 10; -+ emap->map[2].mem_start = SMBIOS_PHYSICAL_ADDRESS; -+ emap->map[2].mem_size = SMBIOS_SIZE_LIMIT >> 20; -+ -+ emap->map[3].node_id = 0; -+ emap->map[3].mem_type = 3; -+ emap->map[3].mem_start = 0xee00000; -+ emap->map[3].mem_size = RESERVED_SIZE_LIMIT >> 20; -+ -+ return emap; -+} -+ -+static uint64_t get_host_cpu_freq(void) -+{ -+ int fd = 0; -+ char buf[1024]; -+ uint64_t freq = 0, size = 0; -+ char *buf_p; -+ -+ fd = open("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", O_RDONLY); -+ if (fd == -1) { -+ fprintf(stderr, "/sys/devices/system/cpu/cpu0/cpufreq/ \ -+ cpuinfo_max_freq not exist!\n"); -+ fprintf(stderr, "Trying /proc/cpuinfo...\n"); -+ } else { -+ size = read(fd, buf, 16); -+ if (size == -1) { -+ fprintf(stderr, "read err...\n"); -+ } -+ close(fd); -+ freq = (uint64_t)atoi(buf); -+ return freq * 1000; -+ } -+ -+ fd = open("/proc/cpuinfo", O_RDONLY); -+ if (fd == -1) { -+ fprintf(stderr, "Failed to open /proc/cpuinfo!\n"); -+ return 0; -+ } -+ -+ size = read(fd, buf, 1024); -+ if (size == -1) { -+ fprintf(stderr, "read err...\n"); -+ } -+ close(fd); -+ -+ buf_p = strstr(buf, "MHz"); -+ if (buf_p) { -+ while (*buf_p != ':') { -+ buf_p++; -+ } -+ buf_p += 2; -+ } else { -+ buf_p = strstr(buf, "name"); -+ while (*buf_p != '@') { -+ buf_p++; -+ } -+ buf_p += 2; -+ } -+ -+ memcpy(buf, buf_p, 12); -+ buf_p = buf; -+ while ((*buf_p >= '0') && (*buf_p <= '9')) { -+ buf_p++; -+ } -+ *buf_p = '\0'; -+ -+ freq = (uint64_t)atoi(buf); -+ return freq * 1000 * 1000; -+} -+ -+static char *get_host_cpu_model_name(void) -+{ -+ int fd = 0; -+ int size = 0; -+ static char buf[1024]; -+ char *buf_p; -+ -+ fd = open("/proc/cpuinfo", O_RDONLY); -+ if (fd == -1) { -+ fprintf(stderr, "Failed to open /proc/cpuinfo!\n"); -+ return 0; -+ } -+ -+ size = read(fd, buf, 1024); -+ if (size == -1) { -+ fprintf(stderr, "read err...\n"); -+ } -+ close(fd); -+ buf_p = strstr(buf, "name"); -+ -+ while (*buf_p != ':') { -+ buf_p++; -+ } -+ buf_p = buf_p + 2; -+ memcpy(buf, buf_p, 40); -+ buf_p = buf; -+ while (*buf_p != '\n') { -+ buf_p++; -+ } -+ -+ *(buf_p) = '\0'; -+ -+ return buf; -+} -+ -+static void fw_conf_init(unsigned long ramsize) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ int smp_cpus = ms->smp.cpus; -+ fw_config.ram_size = ramsize; -+ fw_config.mem_freq = 266000000; -+ fw_config.cpu_nr = smp_cpus ; -+ fw_config.cpu_clock_freq = get_host_cpu_freq(); -+} -+ -+static struct efi_cpuinfo_loongarch *init_cpu_info(void *g_cpuinfo_loongarch) -+{ -+ struct efi_cpuinfo_loongarch *c = g_cpuinfo_loongarch; -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ int smp_cpus = ms->smp.cpus; -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ -+ if (strstr(lsmc->cpu_name, "5000")) { -+ c->processor_id = 0x14c010; -+ } -+ c->cputype = Loongson3_comp; -+ c->cpu_clock_freq = get_host_cpu_freq(); -+ if (!c->cpu_clock_freq) { -+ c->cpu_clock_freq = 200000000; -+ } -+ c->total_node = 1; -+ c->nr_cpus = smp_cpus; -+ c->cpu_startup_core_id = 0; -+ c->reserved_cores_mask = 0xffff & (0xffff << smp_cpus); -+ -+ return c; -+} -+ -+static struct system_loongarch *init_system_loongarch(void *g_sysitem) -+{ -+ struct system_loongarch *s = g_sysitem; -+ -+ s->ccnuma_smp = 1; -+ s->ccnuma_smp = 0; -+ s->sing_double_channel = 1; -+ -+ return s; -+} -+ -+enum loongarch_irq_source_enum { -+ HT, I8259, UNKNOWN -+}; -+ -+static struct irq_source_routing_table *init_irq_source(void *g_irq_source) -+{ -+ struct irq_source_routing_table *irq_info = g_irq_source; -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ -+ irq_info->PIC_type = HT; -+ irq_info->ht_int_bit = 1 << 24; -+ irq_info->ht_enable = 0x0000d17b; -+ irq_info->node_id = 0; -+ -+ irq_info->pci_mem_start_addr = LS_ISA_MEM_BASE; -+ irq_info->pci_mem_end_addr = irq_info->pci_mem_start_addr + LS_ISA_MEM_SIZE - 1; -+ -+ if (strstr(lsmc->cpu_name, "5000")) { -+ irq_info->pci_io_start_addr = LS3A5K_ISA_IO_BASE; -+ } -+ irq_info->dma_noncoherent = 1; -+ return irq_info; -+} -+ -+static struct interface_info *init_interface_info(void *g_interface) -+{ -+ struct interface_info *inter = g_interface; -+ int flashsize = 0x80000; -+ -+ inter->vers = 0x0001; -+ inter->size = flashsize / 0x400; -+ inter->flag = 1; -+ -+ strcpy(inter->description, "PMON_Version_v2.1"); -+ -+ return inter; -+} -+ -+static struct board_devices *board_devices_info(void *g_board) -+{ -+ struct board_devices *bd = g_board; -+ LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ -+ if (!strcmp(lsmc->bridge_name, "ls7a")) { -+ strcpy(bd->name, "Loongarch-3A-7A-1w-V1.03-demo"); -+ } -+ bd->num_resources = 10; -+ -+ return bd; -+} -+ -+static struct loongarch_special_attribute *init_special_info(void *g_special) -+{ -+ struct loongarch_special_attribute *special = g_special; -+ char update[11] = "2013-01-01"; -+ int VRAM_SIZE = 0x20000; -+ -+ strcpy(special->special_name, update); -+ special->resource[0].flags = 0; -+ special->resource[0].start = 0; -+ special->resource[0].end = VRAM_SIZE; -+ strcpy(special->resource[0].name, "SPMODULE"); -+ special->resource[0].flags |= DMA64_SUPPORTED; -+ -+ return special; -+} -+ -+static void init_loongarch_params(struct loongarch_params *lp) -+{ -+ void *p = boot_params_p; -+ -+ lp->memory_offset = (unsigned long long)init_memory_map(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct efi_memory_map_loongarch)); -+ -+ lp->cpu_offset = (unsigned long long)init_cpu_info(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct efi_cpuinfo_loongarch)); -+ -+ lp->system_offset = (unsigned long long)init_system_loongarch(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct system_loongarch)); -+ -+ lp->irq_offset = (unsigned long long)init_irq_source(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct irq_source_routing_table)); -+ -+ lp->interface_offset = (unsigned long long)init_interface_info(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct interface_info)); -+ -+ lp->boarddev_table_offset = (unsigned long long)board_devices_info(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct board_devices)); -+ -+ lp->special_offset = (unsigned long long)init_special_info(p) -+ - (unsigned long long)lp; -+ p += align(sizeof(struct loongarch_special_attribute)); -+ -+ boot_params_p = p; -+} -+ -+static void init_smbios(struct smbios_tables *smbios) -+{ -+ smbios->vers = 1; -+ smbios->vga_bios = 1; -+ init_loongarch_params(&(smbios->lp)); -+} -+ -+static void init_efi(struct efi_loongarch *efi) -+{ -+ init_smbios(&(efi->smbios)); -+} -+ -+static int init_boot_param(struct boot_params *bp) -+{ -+ init_efi(&(bp->efi)); -+ -+ return 0; -+} -+ -+static unsigned int ls3a5k_aui_boot_code[] = { -+ 0x0380200d, /* ori $r13,$r0,0x8 */ -+ 0x0400002d, /* csrwr $r13,0x0 */ -+ 0x0401000e, /* csrrd $r14,0x40 */ -+ 0x0343fdce, /* andi $r14,$r14,0xff */ -+ 0x143fc02c, /* lu12i.w $r12,261889(0x1fe01) */ -+ 0x1600000c, /* lu32i.d $r12,0 */ -+ 0x0320018c, /* lu52i.d $r12,$r12,-1792(0x800) */ -+ 0x03400dcf, /* andi $r15,$r14,0x3 */ -+ 0x004121ef, /* slli.d $r15,$r15,0x8 */ -+ 0x00153d8c, /* or $r12,$r12,$r15 */ -+ 0x034031d0, /* andi $r16,$r14,0xc */ -+ 0x0041aa10, /* slli.d $r16,$r16,0x2a */ -+ 0x0015418c, /* or $r12,$r12,$r16 */ -+ 0x28808184, /* ld.w $r4,$r12,32(0x20) */ -+ 0x43fffc9f, /* beqz $r4,0 -4 */ -+ 0x28c08184, /* ld.d $r4,$r12,32(0x20) */ -+ 0x28c0a183, /* ld.d $r3,$r12,40(0x28) */ -+ 0x28c0c182, /* ld.d $r2,$r12,48(0x30) */ -+ 0x28c0e185, /* ld.d $r5,$r12,56(0x38) */ -+ 0x4c000080, /* jirl $r0,$r4,0 */ -+}; -+ -+static int set_bootparam_uefi(ram_addr_t initrd_offset, long initrd_size) -+{ -+ long params_size; -+ char memenv[32]; -+ char highmemenv[32]; -+ void *params_buf; -+ unsigned long *parg_env; -+ int ret = 0; -+ -+ /* Allocate params_buf for command line. */ -+ params_size = 0x100000; -+ params_buf = g_malloc0(params_size); -+ -+ /* -+ * Layout of params_buf looks like this: -+ * argv[0], argv[1], 0, env[0], env[1], ...env[i], 0, -+ * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0 -+ */ -+ parg_env = (void *)params_buf; -+ -+ ret = (3 + 1) * sizeof(target_ulong); -+ *parg_env++ = (BOOTPARAM_ADDR + ret); -+ ret += (1 + snprintf(params_buf + ret, COMMAND_LINE_SIZE - ret, "g")); -+ -+ /* argv1 */ -+ *parg_env++ = BOOTPARAM_ADDR + ret; -+ if (initrd_size > 0) -+ ret += (1 + snprintf(params_buf + ret, COMMAND_LINE_SIZE - ret, -+ "rd_start=0x%llx rd_size=%li %s", -+ PHYS_TO_VIRT((uint32_t)initrd_offset), -+ initrd_size, loaderparams.kernel_cmdline)); -+ else -+ ret += (1 + snprintf(params_buf + ret, COMMAND_LINE_SIZE - ret, "%s", -+ loaderparams.kernel_cmdline)); -+ -+ /* argv2 */ -+ *parg_env++ = 0; -+ -+ /* env */ -+ sprintf(memenv, "%lu", loaderparams.ram_size > 0x10000000 -+ ? 256 : (loaderparams.ram_size >> 20)); -+ sprintf(highmemenv, "%lu", loaderparams.ram_size > 0x10000000 -+ ? (loaderparams.ram_size >> 20) - 256 : 0); -+ -+ setenv("memsize", memenv, 1); -+ setenv("highmemsize", highmemenv, 1); -+ -+ ret = ((ret + 32) & ~31); -+ -+ boot_params_buf = (void *)(params_buf + ret); -+ boot_params_p = boot_params_buf + align(sizeof(struct boot_params)); -+ init_boot_param(boot_params_buf); -+ rom_add_blob_fixed("params", params_buf, params_size, -+ BOOTPARAM_PHYADDR); -+ loaderparams.a0 = 2; -+ loaderparams.a1 = BOOTPARAM_ADDR; -+ loaderparams.a2 = BOOTPARAM_ADDR + ret; -+ -+ return 0; -+} -+ -+static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) -+{ -+ return addr & 0x1fffffffll; -+} -+ -+static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg, -+ uint64_t highram_size, -+ uint64_t phyAddr_initrd) -+{ -+ int64_t entry, kernel_low, kernel_high; -+ long initrd_size = 0; -+ uint64_t initrd_offset = 0; -+ void *cmdline_buf; -+ int ret = 0; -+ -+ ret = load_elf(loaderparams.kernel_filename, NULL, cpu_loongarch_virt_to_phys, NULL, -+ (uint64_t *)&entry, (uint64_t *)&kernel_low, -+ (uint64_t *)&kernel_high, NULL, 0, EM_LOONGARCH, 1, 0); -+ -+ if(0 > ret) { -+ error_report("kernel image load error"); -+ exit(1); -+ } -+ -+ fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ENTRY, entry); -+ -+ if (loaderparams.initrd_filename) { -+ initrd_size = get_image_size(loaderparams.initrd_filename); -+ if (0 < initrd_size) { -+ if (initrd_size > highram_size) { -+ error_report("initrd size is too big, should below %ld MB", -+ highram_size / S_1MiB); -+ /*prevent write io memory address space*/ -+ exit(1); -+ } -+ initrd_offset = (phyAddr_initrd - initrd_size) & TARGET_REALPAGE_MASK; -+ initrd_size = load_image_targphys(loaderparams.initrd_filename, -+ initrd_offset, -+ loaderparams.ram_size - initrd_offset); -+ fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_offset); -+ fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); -+ } else { -+ error_report("initrd image size is error"); -+ } -+ } -+ -+ cmdline_buf = g_malloc0(COMMAND_LINE_SIZE); -+ if (initrd_size > 0) -+ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE, -+ "rd_start=0x%llx rd_size=%li %s", -+ PHYS_TO_VIRT(initrd_offset), -+ initrd_size, loaderparams.kernel_cmdline)); -+ else -+ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE, "%s", -+ loaderparams.kernel_cmdline)); -+ -+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, ret); -+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, (const char *)cmdline_buf); -+ -+ return ; -+} -+ -+static int64_t load_kernel(void) -+{ -+ int64_t entry, kernel_low, kernel_high; -+ long initrd_size = 0; -+ ram_addr_t initrd_offset = 0; -+ -+ load_elf(loaderparams.kernel_filename, NULL, cpu_loongarch_virt_to_phys, NULL, -+ (uint64_t *)&entry, (uint64_t *)&kernel_low, -+ (uint64_t *)&kernel_high, NULL, 0, EM_LOONGARCH, 1, 0); -+ -+ if (loaderparams.initrd_filename) { -+ initrd_size = get_image_size(loaderparams.initrd_filename); -+ -+ if (initrd_size > 0) { -+ initrd_offset = (kernel_high * 4 + ~TARGET_REALPAGE_MASK) -+ & TARGET_REALPAGE_MASK; -+ initrd_size = load_image_targphys(loaderparams.initrd_filename, -+ initrd_offset, -+ loaderparams.ram_size - initrd_offset); -+ } -+ } -+ set_bootparam_uefi(initrd_offset, initrd_size); -+ -+ return entry; -+} -+ -+static void main_cpu_reset(void *opaque) -+{ -+ ResetData *s = (ResetData *)opaque; -+ CPULOONGARCHState *env = &s->cpu->env; -+ -+ cpu_reset(CPU(s->cpu)); -+ env->active_tc.PC = s->vector; -+ env->active_tc.gpr[4] = loaderparams.a0; -+ env->active_tc.gpr[5] = loaderparams.a1; -+ env->active_tc.gpr[6] = loaderparams.a2; -+} -+ -+void slave_cpu_reset(void *opaque) -+{ -+ ResetData *s = (ResetData *)opaque; -+ -+ cpu_reset(CPU(s->cpu)); -+} -+ -+ -+/* KVM_IRQ_LINE irq field index values */ -+#define KVM_LOONGARCH_IRQ_TYPE_SHIFT 24 -+#define KVM_LOONGARCH_IRQ_TYPE_MASK 0xff -+#define KVM_LOONGARCH_IRQ_VCPU_SHIFT 16 -+#define KVM_LOONGARCH_IRQ_VCPU_MASK 0xff -+#define KVM_LOONGARCH_IRQ_NUM_SHIFT 0 -+#define KVM_LOONGARCH_IRQ_NUM_MASK 0xffff -+ -+/* irq_type field */ -+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IP 0 -+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IO 1 -+#define KVM_LOONGARCH_IRQ_TYPE_HT 2 -+#define KVM_LOONGARCH_IRQ_TYPE_MSI 3 -+#define KVM_LOONGARCH_IRQ_TYPE_IOAPIC 4 -+ -+static void legacy_set_irq(void *opaque, int irq, int level) -+{ -+ qemu_irq *pic = opaque; -+ -+ qemu_set_irq(pic[irq], level); -+} -+ -+typedef struct ls3a_intctlstate { -+ uint8_t nodecounter_reg[0x100]; -+ uint8_t pm_reg[0x100]; -+ uint8_t msi_reg[0x8]; -+ CPULOONGARCHState **env; -+ DeviceState *apicdev; -+ qemu_irq *ioapic_irq; -+#ifdef CONFIG_KVM -+ struct loongarch_kvm_irqchip chip; -+#endif -+} ls3a_intctlstate; -+ -+typedef struct ls3a_func_args { -+ ls3a_intctlstate *state; -+ uint64_t base; -+ uint32_t mask; -+ uint8_t *mem; -+} ls3a_func_args; -+ -+static uint64_t ls3a_msi_mem_read(void *opaque, hwaddr addr, unsigned size) -+{ -+ return 0; -+} -+ -+static void ls3a_msi_mem_write(void *opaque, hwaddr addr, -+ uint64_t val, unsigned size) -+{ -+ struct kvm_msi msi; -+ apicState *apic; -+ -+ apic = (apicState *)opaque; -+ msi.address_lo = 0; -+ msi.address_hi = 0; -+ msi.data = val & 0xff; -+ msi.flags = 0; -+ memset(msi.pad, 0, sizeof(msi.pad)); -+ -+ if (kvm_irqchip_in_kernel()) { -+ kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi); -+ } else { -+ qemu_set_irq(apic->irq[msi.data], 1); -+ } -+} -+ -+ -+static const MemoryRegionOps ls3a_msi_ops = { -+ .read = ls3a_msi_mem_read, -+ .write = ls3a_msi_mem_write, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+}; -+ -+ -+static const VMStateDescription vmstate_ls3a_msi = { -+ .name = "ls3a-msi", -+ .version_id = 0, -+ .minimum_version_id = 0, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT8_ARRAY(msi_reg, ls3a_intctlstate, 0x8), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static void ioapic_handler(void *opaque, int irq, int level) -+{ -+ apicState *apic; -+ int kvm_irq; -+ -+ apic = (apicState *)opaque; -+ -+ if (kvm_irqchip_in_kernel()) { -+ kvm_irq = (KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT) -+ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | irq; -+ kvm_set_irq(kvm_state, kvm_irq, !!level); -+ } else { -+ qemu_set_irq(apic->irq[irq], level); -+ } -+} -+ -+static void *ls3a_intctl_init(MachineState *machine, CPULOONGARCHState *env[]) -+{ -+ qemu_irq *irqhandler; -+ ls3a_intctlstate *s; -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LoongarchMachineClass *mc = LoongarchMACHINE_GET_CLASS(lsms); -+ DeviceState *dev; -+ SysBusDevice *busdev; -+ MemoryRegion *address_space_mem = get_system_memory(); -+ MemoryRegion *iomem = NULL; -+ int i; -+ -+ s = g_malloc0(sizeof(ls3a_intctlstate)); -+ -+ if (!s) { -+ return NULL; -+ } -+ -+ /*Add MSI mmio memory*/ -+ iomem = g_new(MemoryRegion, 1); -+ memory_region_init_io(iomem, NULL, &ls3a_msi_ops, lsms->apic, -+ "ls3a_msi", 0x8); -+ memory_region_add_subregion(address_space_mem, -+ MSI_ADDR_LOW, iomem); -+ vmstate_register(NULL, 0, &vmstate_ls3a_msi, s); -+ -+ s->env = env; -+ -+ if (!strcmp(mc->bridge_name, "ls7a")) { -+ if (lsms->apic_xrupt_override) { -+ DPRINTF("irqchip in kernel %d\n", kvm_irqchip_in_kernel()); -+#ifdef CONFIG_KVM -+ if (kvm_has_gsi_routing()) { -+ for (i = 0; i < 32; ++i) { -+ kvm_irqchip_add_irq_route(kvm_state, i, 0, i); -+ } -+ kvm_gsi_routing_allowed = true; -+ } -+ kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); -+#endif -+ } -+ -+ irqhandler = qemu_allocate_irqs(ioapic_handler, lsms->apic, 64); -+ dev = qdev_new("ioapic"); -+ busdev = SYS_BUS_DEVICE(dev); -+ sysbus_realize_and_unref(busdev, &error_fatal); -+ sysbus_mmio_map(busdev, 0, mc->ls7a_ioapic_reg_base); -+ s->ioapic_irq = irqhandler; -+ s->apicdev = dev; -+ return s->ioapic_irq; -+ } -+ return NULL; -+} -+ -+/* Network support */ -+static void network_init(PCIBus *pci_bus) -+{ -+ int i; -+ -+ for (i = 0; i < nb_nics; i++) { -+ NICInfo *nd = &nd_table[i]; -+ -+ if (!nd->model) { -+ nd->model = g_strdup("virtio-net-pci"); -+ } -+ -+ pci_nic_init_nofail(nd, pci_bus, nd->model, NULL); -+ } -+} -+ -+void loongarch_cpu_destroy(MachineState *machine, LOONGARCHCPU *cpu) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ unsigned int id; -+ int smp_cpus = machine->smp.cpus; -+ id = cpu->id; -+ qemu_unregister_reset(slave_cpu_reset, lsms->reset_info[id]); -+ g_free(lsms->reset_info[id]); -+ lsms->reset_info[id] = NULL; -+ -+ smp_cpus -= 1; -+ if (lsms->fw_cfg) { -+ fw_cfg_modify_i16(lsms->fw_cfg, FW_CFG_NB_CPUS, -+ (uint16_t)smp_cpus); -+ } -+ -+ qemu_del_vm_change_state_handler(cpu->cpuStateEntry); -+} -+ -+LOONGARCHCPU *loongarch_cpu_create(MachineState *machine, -+ LOONGARCHCPU *cpu, Error **errp) -+{ -+ CPULOONGARCHState *env; -+ unsigned int id; -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ int smp_cpus = machine->smp.cpus; -+ id = cpu->id; -+ env = &cpu->env; -+ cpu_states[id] = env; -+ env->CSR_TMID |= id; -+ -+ lsms = LoongarchMACHINE(machine); -+ lsms->reset_info[id] = g_malloc0(sizeof(ResetData)); -+ lsms->reset_info[id]->cpu = cpu; -+ lsms->reset_info[id]->vector = env->active_tc.PC; -+ qemu_register_reset(slave_cpu_reset, lsms->reset_info[id]); -+ -+ /* Init CPU internal devices */ -+ cpu_init_irq(cpu); -+ cpu_loongarch_clock_init(cpu); -+ -+ smp_cpus += 1; -+ if (lsms->fw_cfg) { -+ fw_cfg_modify_i16(lsms->fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); -+ } -+ cpu_init_ipi(lsms, env->irq[12], id); -+ cpu_init_apic(lsms, env, id); -+ -+ return cpu; -+} -+ -+static void fw_cfg_boot_set(void *opaque, const char *boot_device, -+ Error **errp) -+{ -+ fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); -+} -+ -+static FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, -+ LoongarchMachineState *lsms) -+{ -+ FWCfgState *fw_cfg; -+ uint64_t *numa_fw_cfg; -+ int i; -+ const CPUArchIdList *cpus; -+ MachineClass *mc = MACHINE_GET_CLASS(lsms); -+ MachineState *ms = MACHINE(OBJECT(lsms)); -+ int max_cpus = ms->smp.max_cpus; -+ int smp_cpus = ms->smp.cpus; -+ int nb_numa_nodes = ms->numa_state->num_nodes; -+ NodeInfo *numa_info = ms->numa_state->nodes; -+ -+ fw_cfg = fw_cfg_init_mem_wide(FW_CFG_ADDR + 8, FW_CFG_ADDR, 8, 0, NULL); -+ fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); -+ fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); -+ fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); -+ -+ /* allocate memory for the NUMA channel: one (64bit) word for the number -+ * of nodes, one word for each VCPU->node and one word for each node to -+ * hold the amount of memory. -+ */ -+ numa_fw_cfg = g_new0(uint64_t, 1 + max_cpus + nb_numa_nodes); -+ numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes); -+ cpus = mc->possible_cpu_arch_ids(MACHINE(lsms)); -+ for (i = 0; i < cpus->len; i++) { -+ unsigned int apic_id = cpus->cpus[i].arch_id; -+ assert(apic_id < max_cpus); -+ numa_fw_cfg[apic_id + 1] = cpu_to_le64(cpus->cpus[i].props.node_id); -+ } -+ for (i = 0; i < nb_numa_nodes; i++) { -+ numa_fw_cfg[max_cpus + 1 + i] = -+ cpu_to_le64(numa_info[i].node_mem); -+ } -+ fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, -+ (1 + max_cpus + nb_numa_nodes) * -+ sizeof(*numa_fw_cfg)); -+ -+ qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); -+ return fw_cfg; -+} -+ -+static void loongarch_build_smbios(LoongarchMachineState *lsms) -+{ -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ MachineState *ms = MACHINE(OBJECT(lsms)); -+ uint8_t *smbios_tables, *smbios_anchor; -+ size_t smbios_tables_len, smbios_anchor_len; -+ const char *product = "QEMU Virtual Machine"; -+ ms->smp.cores = 4; -+ -+ if (!lsms->fw_cfg) { -+ return; -+ } -+ -+ if (kvm_enabled()) { -+ if (strstr(lsmc->cpu_name, "5000")) { -+ product = "KVM"; -+ } -+ } else { -+ product = "Loongarch-3A5K-7A1000-TCG"; -+ } -+ -+ host_cpufreq = get_host_cpu_freq(); -+ -+ smbios_set_defaults("Loongson", product, lsmc->cpu_name, false, -+ true, NULL, NULL, SMBIOS_ENTRY_POINT_30); -+ -+ smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len, -+ &smbios_anchor, &smbios_anchor_len, &error_fatal); -+ -+ if (smbios_anchor) { -+ fw_cfg_add_file(lsms->fw_cfg, "etc/smbios/smbios-tables", -+ smbios_tables, smbios_tables_len); -+ fw_cfg_add_file(lsms->fw_cfg, "etc/smbios/smbios-anchor", -+ smbios_anchor, smbios_anchor_len); -+ } -+} -+ -+static -+void loongarch_machine_done(Notifier *notifier, void *data) -+{ -+ LoongarchMachineState *lsms = container_of(notifier, -+ LoongarchMachineState, machine_done); -+ loongarch_acpi_setup(); -+ loongarch_build_smbios(lsms); -+} -+ -+#ifdef CONFIG_TCG -+#define FEATURE_REG 0x1fe00008 -+#define VENDOR_REG 0x1fe00010 -+#define CPUNAME_REG 0x1fe00020 -+#define OTHER_FUNC_REG 0x1fe00420 -+#define _str(x) #x -+#define str(x) _str(x) -+#define SIMPLE_OPS(ADDR, SIZE) \ -+({\ -+ MemoryRegion *iomem = g_new(MemoryRegion, 1);\ -+ memory_region_init_io(iomem, NULL, &loongarch_qemu_ops, \ -+ (void *)ADDR, str(ADDR) , SIZE);\ -+ memory_region_add_subregion_overlap(address_space_mem, ADDR, iomem, 1);\ -+}) -+ -+static int reg180; -+ -+static void loongarch_qemu_write(void *opaque, hwaddr addr, -+ uint64_t val, unsigned size) -+{ -+ addr = ((hwaddr)(long)opaque) + addr; -+ addr = addr & 0xffffffff; -+ switch (addr) { -+ case 0x1fe00180: -+ reg180 = val; -+ break; -+ } -+} -+ -+static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size) -+{ -+ uint64_t feature = 0UL; -+ addr = ((hwaddr)(long)opaque) + addr; -+ addr = addr & 0xffffffff; -+ switch (addr) { -+ case 0x1fe00180: -+ return reg180; -+ case 0x1001041c: -+ return 0xa800; -+ case FEATURE_REG: -+ feature |= 1UL << 2 | 1UL << 3 | 1UL << 4 | 1UL << 11; -+ return feature ; -+ case VENDOR_REG: -+ return *(uint64_t *)"Loongson-3A5000"; -+ case CPUNAME_REG: -+ return *(uint64_t *)"3A5000"; -+ case 0x10013ffc: -+ return 0x80; -+ } -+ return 0; -+} -+ -+static const MemoryRegionOps loongarch_qemu_ops = { -+ .read = loongarch_qemu_read, -+ .write = loongarch_qemu_write, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+ .valid = { -+ .min_access_size = 4, -+ .max_access_size = 8, -+ }, -+ .impl = { -+ .min_access_size = 4, -+ .max_access_size = 8, -+ }, -+}; -+#endif -+ -+ -+static void loongarch_system_flash_cleanup_unused(LoongarchMachineState *lsms) -+{ -+ char *prop_name; -+ int i; -+ Object *dev_obj; -+ -+ for (i = 0; i < ARRAY_SIZE(lsms->flash); i++) { -+ dev_obj = OBJECT(lsms->flash[i]); -+ if (!object_property_get_bool(dev_obj, "realized", &error_abort)) { -+ prop_name = g_strdup_printf("pflash%d", i); -+ object_property_del(OBJECT(lsms), prop_name); -+ g_free(prop_name); -+ object_unparent(dev_obj); -+ lsms->flash[i] = NULL; -+ } -+ } -+} -+ -+ -+static bool loongarch_system_flash_init( LoongarchMachineState *lsms) -+{ -+ int i = 0; -+ int64_t size = 0; -+ PFlashCFI01 *pflash = NULL; -+ BlockBackend *pflash_blk; -+ -+ for(i = 0; i < ARRAY_SIZE(lsms->flash); i++) { -+ pflash_blk = NULL; -+ pflash = NULL; -+ -+ pflash = lsms->flash[i]; -+ pflash_cfi01_legacy_drive(pflash, -+ drive_get(IF_PFLASH, 0, i)); -+ -+ pflash_blk = pflash_cfi01_get_blk(pflash); -+ /*The pflash0 must be exist, or not support boot by pflash*/ -+ if(pflash_blk == NULL) { -+ if(i == 0) { -+ return false; -+ } else { -+ break; -+ } -+ } -+ -+ size = blk_getlength(pflash_blk); -+ if (size == 0 || size % FLASH_SECTOR_SIZE != 0) { -+ error_report("system firmware block device %s has invalid size " -+ "%" PRId64, -+ blk_name(pflash_blk), size); -+ error_report("its size must be a non-zero multiple of 0x%x", -+ FLASH_SECTOR_SIZE); -+ exit(1); -+ } -+ qdev_prop_set_uint32(DEVICE(pflash), "num-blocks", -+ size / FLASH_SECTOR_SIZE); -+ sysbus_realize_and_unref(SYS_BUS_DEVICE(pflash), &error_fatal); -+ if(i == 0) { -+ sysbus_mmio_map(SYS_BUS_DEVICE(pflash), 0, LS_BIOS_BASE); -+ } else { -+ sysbus_mmio_map_overlap(SYS_BUS_DEVICE(pflash), 0, LS_BIOS_VAR_BASE, 1); -+ } -+ } -+ -+ return true; -+} -+static void ls3a5k_bios_init(LoongarchMachineState *lsms, -+ ram_addr_t ram_size, -+ uint64_t highram_size, -+ uint64_t phyAddr_initrd, -+ const char *kernel_filename, -+ const char *kernel_cmdline, -+ const char *initrd_filename) -+{ -+ MemoryRegion *bios; -+ bool fw_cfg_used = false; -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ char *filename; -+ int bios_size; -+ const char *bios_name; -+ -+ bios_name = MACHINE(lsms)->firmware; -+ if (kernel_filename) { -+ loaderparams.ram_size = ram_size; -+ loaderparams.kernel_filename = kernel_filename; -+ loaderparams.kernel_cmdline = kernel_cmdline; -+ loaderparams.initrd_filename = initrd_filename; -+ } -+ -+ if(loongarch_system_flash_init(lsms)) { -+ fw_cfg_used = true; -+ } else { -+ bios = g_new(MemoryRegion, 1); -+ memory_region_init_ram(bios, NULL, "loongarch.bios", LS_BIOS_SIZE, &error_fatal); -+ memory_region_set_readonly(bios, true); -+ memory_region_add_subregion(get_system_memory(), LS_BIOS_BASE, bios); -+ -+ /* BIOS load */ -+ if (bios_name) { -+ if (access(bios_name, R_OK) == 0) { -+ load_image_targphys(bios_name, LS_BIOS_BASE, LS_BIOS_SIZE); -+ } else { -+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); -+ load_image_targphys(filename, LS_BIOS_BASE, LS_BIOS_SIZE); -+ g_free(filename); -+ } -+ fw_cfg_used = true; -+ } else { -+ if (strstr(lsmc->cpu_name, "5000")) { -+ bios_size = sizeof(ls3a5k_aui_boot_code); -+ rom_add_blob_fixed("bios", ls3a5k_aui_boot_code, bios_size, LS_BIOS_BASE); -+ } -+ -+ if (kernel_filename) { -+ lsms->reset_info[0]->vector = load_kernel(); -+ } else { -+ error_report("Please specify at lease one of -bios and -kernel"); -+ exit(1); -+ } -+ } -+ } -+ -+ loongarch_system_flash_cleanup_unused(lsms); -+ -+ if (fw_cfg_used) { -+ lsms->fw_cfg = loongarch_fw_cfg_init(ram_size, lsms); -+ rom_set_fw(lsms->fw_cfg); -+ fw_conf_init(ram_size); -+ rom_add_blob_fixed("fw_conf", (void *)&fw_config, -+ sizeof(fw_config), FW_CONF_ADDR); -+ -+ if (kernel_filename) { -+ fw_cfg_add_kernel_info(lsms->fw_cfg, highram_size, phyAddr_initrd); -+ } -+ } -+ -+ if (lsms->fw_cfg != NULL) { -+ fw_cfg_add_file(lsms->fw_cfg, "etc/memmap", -+ la_memmap_table, -+ sizeof(struct la_memmap_entry) * (la_memmap_entries)); -+ } -+ -+ return ; -+} -+static void create_fdt(LoongarchMachineState *lsms) -+{ -+ lsms->fdt = create_device_tree(&lsms->fdt_size); -+ if (!lsms->fdt) { -+ error_report("create_device_tree() failed"); -+ exit(1); -+ } -+ -+ /* Header */ -+ qemu_fdt_setprop_string(lsms->fdt, "/", "compatible", -+ "linux,dummy-loongson3"); -+ qemu_fdt_setprop_cell(lsms->fdt, "/", "#address-cells", 0x2); -+ qemu_fdt_setprop_cell(lsms->fdt, "/", "#size-cells", 0x2); -+} -+ -+static void fdt_add_cpu_nodes(const LoongarchMachineState *lsms) -+{ -+ int num; -+ const MachineState *ms = MACHINE(lsms); -+ int smp_cpus = ms->smp.cpus; -+ -+ qemu_fdt_add_subnode(lsms->fdt, "/cpus"); -+ qemu_fdt_setprop_cell(lsms->fdt, "/cpus", "#address-cells", 0x1); -+ qemu_fdt_setprop_cell(lsms->fdt, "/cpus", "#size-cells", 0x0); -+ -+ /* cpu nodes */ -+ for (num = smp_cpus - 1; num >= 0; num--) { -+ char *nodename = g_strdup_printf("/cpus/cpu@%d", num); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(qemu_get_cpu(num)); -+ -+ qemu_fdt_add_subnode(lsms->fdt, nodename); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, "device_type", "cpu"); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, "compatible", -+ cpu->dtb_compatible); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "reg", num); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "phandle", -+ qemu_fdt_alloc_phandle(lsms->fdt)); -+ g_free(nodename); -+ } -+ -+ /*cpu map */ -+ qemu_fdt_add_subnode(lsms->fdt, "/cpus/cpu-map"); -+ -+ for (num = smp_cpus - 1; num >= 0; num--) { -+ char *cpu_path = g_strdup_printf("/cpus/cpu@%d", num); -+ char *map_path; -+ -+ if (ms->smp.threads > 1) { -+ map_path = g_strdup_printf( -+ "/cpus/cpu-map/socket%d/core%d/thread%d", -+ num / (ms->smp.cores * ms->smp.threads), -+ (num / ms->smp.threads) % ms->smp.cores, -+ num % ms->smp.threads); -+ } else { -+ map_path = g_strdup_printf( -+ "/cpus/cpu-map/socket%d/core%d", -+ num / ms->smp.cores, -+ num % ms->smp.cores); -+ } -+ qemu_fdt_add_path(lsms->fdt, map_path); -+ qemu_fdt_setprop_phandle(lsms->fdt, map_path, "cpu", cpu_path); -+ -+ g_free(map_path); -+ g_free(cpu_path); -+ } -+} -+ -+static void fdt_add_fw_cfg_node(const LoongarchMachineState *lsms) -+{ -+ char *nodename; -+ hwaddr base = FW_CFG_ADDR; -+ -+ nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base); -+ qemu_fdt_add_subnode(lsms->fdt, nodename); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, -+ "compatible", "qemu,fw-cfg-mmio"); -+ qemu_fdt_setprop_sized_cells(lsms->fdt, nodename, "reg", -+ 2, base, 2, 0x8); -+ qemu_fdt_setprop(lsms->fdt, nodename, "dma-coherent", NULL, 0); -+ g_free(nodename); -+} -+ -+static void fdt_add_pcie_node(const LoongarchMachineState *lsms) -+{ -+ char *nodename; -+ hwaddr base_mmio = LS_ISA_MEM_BASE; -+ hwaddr size_mmio = LS_ISA_MEM_SIZE; -+ hwaddr base_pio = LS3A5K_ISA_IO_BASE; -+ hwaddr size_pio = LS_ISA_IO_SIZE; -+ hwaddr base_pcie = LS_PCIECFG_BASE; -+ hwaddr size_pcie = LS_PCIECFG_SIZE; -+ hwaddr base = base_pcie; -+ -+ nodename = g_strdup_printf("/pcie@%" PRIx64, base); -+ qemu_fdt_add_subnode(lsms->fdt, nodename); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, -+ "compatible", "pci-host-ecam-generic"); -+ qemu_fdt_setprop_string(lsms->fdt, nodename, "device_type", "pci"); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "#address-cells", 3); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "#size-cells", 2); -+ qemu_fdt_setprop_cell(lsms->fdt, nodename, "linux,pci-domain", 0); -+ qemu_fdt_setprop_cells(lsms->fdt, nodename, "bus-range", 0, -+ PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1)); -+ qemu_fdt_setprop(lsms->fdt, nodename, "dma-coherent", NULL, 0); -+ qemu_fdt_setprop_sized_cells(lsms->fdt, nodename, "reg", -+ 2, base_pcie, 2, size_pcie); -+ qemu_fdt_setprop_sized_cells(lsms->fdt, nodename, "ranges", -+ 1, FDT_PCI_RANGE_IOPORT, 2, 0, -+ 2, base_pio, 2, size_pio, -+ 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, -+ 2, base_mmio, 2, size_mmio); -+ g_free(nodename); -+ qemu_fdt_dumpdtb(lsms->fdt, lsms->fdt_size); -+} -+ -+static void ls3a5k_init(MachineState *args) -+{ -+ int i; -+ const char *cpu_model = args->cpu_type; -+ const char *kernel_filename = args->kernel_filename; -+ const char *kernel_cmdline = args->kernel_cmdline; -+ const char *initrd_filename = args->initrd_filename; -+ -+ ram_addr_t ram_size = args->ram_size; -+ MemoryRegion *address_space_mem = get_system_memory(); -+ ram_addr_t offset = 0; -+ MemoryRegion *isa_io = g_new(MemoryRegion, 1); -+ MemoryRegion *isa_mem = g_new(MemoryRegion, 1); -+ MachineState *machine = args; -+ MachineClass *mc = MACHINE_GET_CLASS(machine); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ int smp_cpus = machine->smp.cpus; -+ int nb_numa_nodes = machine->numa_state->num_nodes; -+ NodeInfo *numa_info = machine->numa_state->nodes; -+ LOONGARCHCPU *cpu; -+ CPULOONGARCHState *env; -+ qemu_irq *ls7a_apic = NULL; -+ qemu_irq *pirq = NULL; -+ PCIBus *pci_bus = NULL; -+ char *ramName = NULL; -+ uint64_t lowram_size = 0, highram_size = 0, phyAddr = 0, -+ memmap_size = 0, highram_end_addr = 0; -+ -+ CPUArchIdList *possible_cpus; -+ if (strstr(lsmc->cpu_name, "5000")) { -+ if (strcmp(cpu_model, LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000")) && -+ strcmp(cpu_model, LOONGARCH_CPU_TYPE_NAME("host"))) { -+ error_report("machine type %s does not match cpu type %s", -+ lsmc->cpu_name, cpu_model); -+ exit(1); -+ } -+ if (kvm_enabled()) { -+ kvm_vm_ioctl(kvm_state, KVM_LARCH_SET_CPUCFG, ls3a5k_cpucfgs); -+ } -+ } -+ -+ create_fdt(lsms); -+ -+ DPRINTF("isa 0x%lx\n", lsmc->isa_io_base); -+ DPRINTF("ht1lo 0x%lx\n", lsmc->ht1lo_pcicfg_base); -+ DPRINTF("cpu_name %s bridge_name %s\n", -+ lsmc->cpu_name, lsmc->bridge_name); -+ -+ /* init CPUs */ -+ mc->possible_cpu_arch_ids(machine); -+ possible_cpus = machine->possible_cpus; -+ -+ for (i = 0; i < smp_cpus; i++) { -+ Object *obj = NULL; -+ Error *local_err = NULL; -+ -+ obj = object_new(possible_cpus->cpus[i].type); -+ -+ object_property_set_uint(obj, "id", possible_cpus->cpus[i].arch_id, -+ &local_err); -+ object_property_set_bool(obj, "realized", true, &local_err); -+ -+ object_unref(obj); -+ error_propagate(&error_fatal, local_err); -+ -+ cpu = LOONGARCH_CPU(CPU(obj)); -+ if (cpu == NULL) { -+ fprintf(stderr, "Unable to find CPU definition\n"); -+ exit(1); -+ } -+ -+ env = &cpu->env; -+ cpu_states[i] = env; -+ env->CSR_TMID |= i; -+ -+ lsms->reset_info[i] = g_malloc0(sizeof(ResetData)); -+ lsms->reset_info[i]->cpu = cpu; -+ lsms->reset_info[i]->vector = env->active_tc.PC; -+ if (i == 0) { -+ qemu_register_reset(main_cpu_reset, lsms->reset_info[i]); -+ } else { -+ qemu_register_reset(slave_cpu_reset, lsms->reset_info[i]); -+ } -+ -+ /* Init CPU internal devices */ -+ cpu_init_irq(cpu); -+ cpu_loongarch_clock_init(cpu); -+ cpu_init_ipi(lsms, env->irq[12], i); -+ cpu_init_apic(lsms, env, i); -+ } -+ -+ lsms->hotpluged_cpu_num = 0; -+ fdt_add_cpu_nodes(lsms); -+ env = cpu_states[0]; -+ -+ /* node0 mem*/ -+ phyAddr = (uint64_t)0; -+ MemoryRegion *lowmem = g_new(MemoryRegion, 1); -+ ramName = g_strdup_printf("loongarch_ls3a.node%d.lowram", 0); -+ -+ lowram_size = MIN(ram_size, 256 * 0x100000); -+ memory_region_init_alias(lowmem, NULL, ramName, machine->ram, 0, lowram_size); -+ memory_region_add_subregion(address_space_mem, phyAddr, lowmem); -+ -+ offset += lowram_size; -+ if (nb_numa_nodes > 0) { -+ highram_size = numa_info[0].node_mem - S_256MiB; -+ if (numa_info[0].node_mem > S_1GiB) { -+ memmap_size = numa_info[0].node_mem - S_1GiB; -+ la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); -+ } -+ } else { -+ highram_size = ram_size - S_256MiB; -+ if (ram_size > S_1GiB) { -+ memmap_size = ram_size - S_1GiB; -+ la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); -+ } -+ } -+ -+ phyAddr = (uint64_t)0x90000000; -+ MemoryRegion *highmem = g_new(MemoryRegion, 1); -+ ramName = g_strdup_printf("loongarch_ls3a.node%d.highram", 0); -+ memory_region_init_alias(highmem, NULL, ramName, -+ machine->ram, offset, highram_size); -+ memory_region_add_subregion(address_space_mem, -+ phyAddr, highmem); -+ offset += highram_size; -+ phyAddr += highram_size; -+ -+ /* initrd address use high mem from high to low */ -+ highram_end_addr = phyAddr; -+ /* node1~ nodemax */ -+ for (i = 1; i < nb_numa_nodes; i++) { -+ MemoryRegion *nodemem = g_new(MemoryRegion, 1); -+ ramName = g_strdup_printf("loongarch_ls3a.node%d.ram", i); -+ memory_region_init_alias(nodemem, NULL, ramName, -+ machine->ram, offset, numa_info[i].node_mem); -+ memory_region_add_subregion(address_space_mem, -+ phyAddr, nodemem); -+ la_memmap_add_entry(phyAddr, numa_info[i].node_mem, SYSTEM_RAM); -+ offset += numa_info[i].node_mem; -+ phyAddr += numa_info[i].node_mem; -+ } -+ -+ fdt_add_fw_cfg_node(lsms); -+ ls3a5k_bios_init(lsms, ram_size, highram_size, highram_end_addr, -+ kernel_filename, kernel_cmdline, initrd_filename); -+ -+ lsms->machine_done.notify = loongarch_machine_done; -+ qemu_add_machine_init_done_notifier(&lsms->machine_done); -+ /*vmstate_register_ram_global(bios);*/ -+ -+ /* initialize hotplug memory address space */ -+ lsms->hotplug_memory_size = 0; -+ -+ /* always allocate the device memory information */ -+ machine->device_memory = g_malloc0(sizeof(*machine->device_memory)); -+ if (machine->ram_size < machine->maxram_size) { -+ int max_memslots; -+ -+ lsms->hotplug_memory_size = machine->maxram_size - machine->ram_size; -+ /* -+ * Limit the number of hotpluggable memory slots to half the number -+ * slots that KVM supports, leaving the other half for PCI and other -+ * devices. However ensure that number of slots doesn't drop below 32. -+ */ -+ max_memslots = LOONGARCH_MAX_RAM_SLOTS; -+ if (kvm_enabled()) { -+ max_memslots = kvm_get_max_memslots() / 2 ; -+ } -+ -+ if (machine->ram_slots == 0) -+ machine->ram_slots = lsms->hotplug_memory_size / -+ LOONGARCH_HOTPLUG_MEM_ALIGN; -+ -+ if (machine->ram_slots > max_memslots) { -+ error_report("Specified number of memory slots %" -+ PRIu64" exceeds max supported %d", -+ machine->ram_slots, max_memslots); -+ exit(1); -+ } -+ -+ lsms->ram_slots = machine->ram_slots; -+ -+ machine->device_memory->base = get_hotplug_membase(machine->ram_size); -+ memory_region_init(&machine->device_memory->mr, OBJECT(lsms), -+ "device-memory", lsms->hotplug_memory_size); -+ memory_region_add_subregion(get_system_memory(), -+ machine->device_memory->base, -+ &machine->device_memory->mr); -+ } -+ -+ memory_region_init_alias(isa_io, NULL, "isa-io", -+ get_system_io(), 0, LS_ISA_IO_SIZE); -+ memory_region_init(isa_mem, NULL, "isa-mem", LS_ISA_MEM_SIZE); -+ memory_region_add_subregion(get_system_memory(), lsmc->isa_io_base, isa_io); -+ memory_region_add_subregion(get_system_memory(), LS_ISA_MEM_BASE, isa_mem); -+ -+ if (!strcmp(lsmc->bridge_name, "ls7a")) { -+ /*Initialize the 7A IO interrupt subsystem*/ -+ DeviceState *ls7a_dev; -+ lsms->apic_xrupt_override = kvm_irqchip_in_kernel(); -+ ls7a_apic = ls3a_intctl_init(machine, cpu_states); -+ if (!ls7a_apic) { -+ perror("Init 7A APIC failed\n"); -+ exit(1); -+ } -+ pci_bus = ls7a_init(machine, ls7a_apic, &ls7a_dev); -+ -+ object_property_add_link(OBJECT(machine), -+ LOONGARCH_MACHINE_ACPI_DEVICE_PROP, -+ TYPE_HOTPLUG_HANDLER, -+ (Object **)&lsms->acpi_dev, -+ object_property_allow_set_link, -+ OBJ_PROP_LINK_STRONG); -+ object_property_set_link(OBJECT(machine), LOONGARCH_MACHINE_ACPI_DEVICE_PROP, -+ OBJECT(ls7a_dev), &error_abort); -+ -+#ifdef CONFIG_KVM -+ if (kvm_enabled()) { -+ kvm_direct_msi_allowed = (kvm_check_extension(kvm_state, -+ KVM_CAP_SIGNAL_MSI) > 0); -+ } else { -+ kvm_direct_msi_allowed = 0; -+ } -+ msi_nonbroken = kvm_direct_msi_allowed; -+#else -+ msi_nonbroken = true; -+#endif -+ sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE, -+ ls7a_apic[LS7A_RTC_IRQ - LOONGARCH_PCH_IRQ_BASE]); -+ } -+ -+ /*Initialize the CPU serial device*/ -+ -+ if (serial_hd(0)) { -+ pirq = qemu_allocate_irqs(legacy_set_irq, ls7a_apic + -+ (LS7A_UART_IRQ - LOONGARCH_PCH_IRQ_BASE), 1); -+ serial_mm_init(address_space_mem, LS7A_UART_BASE, 0, pirq[0], -+ 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); -+ } -+ -+ /*network card*/ -+ network_init(pci_bus); -+ /* VGA setup. Don't bother loading the bios. */ -+ pci_vga_init(pci_bus); -+ -+ sysbus_realize_and_unref(SYS_BUS_DEVICE(qdev_new("iocsr")), &error_fatal); -+ -+#ifdef CONFIG_TCG -+ int nb_nodes = (smp_cpus - 1) / 4; -+ for (i = 0; i <= nb_nodes; i++) { -+ uint64_t off = (uint64_t)i << 44; -+ SIMPLE_OPS(((hwaddr)0x1fe00180 | off), 0x8); -+ SIMPLE_OPS(((hwaddr)0x1fe0019c | off), 0x8); -+ SIMPLE_OPS(((hwaddr)0x1fe001d0 | off), 0x8); -+ SIMPLE_OPS(((hwaddr)FEATURE_REG | off), 0x8); -+ SIMPLE_OPS(((hwaddr)VENDOR_REG | off), 0x8); -+ SIMPLE_OPS(((hwaddr)CPUNAME_REG | off), 0x8); -+ SIMPLE_OPS(((hwaddr)OTHER_FUNC_REG | off), 0x8); -+ } -+ -+ SIMPLE_OPS(0x1001041c, 0x4); -+ SIMPLE_OPS(0x10002000, 0x14); -+ SIMPLE_OPS(0x10013ffc, 0x4); -+#endif -+ -+ fdt_add_pcie_node(lsms); -+ -+ /* load fdt */ -+ MemoryRegion *fdt_rom = g_new(MemoryRegion, 1); -+ memory_region_init_rom(fdt_rom, NULL, "fdt", LS_FDT_SIZE, &error_fatal); -+ memory_region_add_subregion(get_system_memory(), LS_FDT_BASE, fdt_rom); -+ rom_add_blob_fixed("fdt", lsms->fdt, lsms->fdt_size, LS_FDT_BASE); -+} -+ -+static const CPUArchIdList *loongarch_possible_cpu_arch_ids(MachineState *ms) -+{ -+ int i; -+ int max_cpus = ms->smp.max_cpus; -+ -+ if (ms->possible_cpus) { -+ /* -+ * make sure that max_cpus hasn't changed since the first use, i.e. -+ * -smp hasn't been parsed after it -+ */ -+ assert(ms->possible_cpus->len == max_cpus); -+ return ms->possible_cpus; -+ } -+ -+ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + -+ sizeof(CPUArchId) * max_cpus); -+ ms->possible_cpus->len = max_cpus; -+ for (i = 0; i < ms->possible_cpus->len; i++) { -+ ms->possible_cpus->cpus[i].type = ms->cpu_type; -+ ms->possible_cpus->cpus[i].vcpus_count = 1; -+ ms->possible_cpus->cpus[i].props.has_core_id = true; -+ ms->possible_cpus->cpus[i].props.core_id = i; -+ ms->possible_cpus->cpus[i].arch_id = i; -+ } -+ return ms->possible_cpus; -+ -+} -+ -+static PFlashCFI01 *loongarch_pflash_create(LoongarchMachineState *lsms, -+ const char *name, -+ const char *alias_prop_name) -+{ -+ DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); -+ -+ qdev_prop_set_uint64(dev, "sector-length", FLASH_SECTOR_SIZE); -+ qdev_prop_set_uint8(dev, "width", 1); -+ qdev_prop_set_string(dev, "name", name); -+ object_property_add_child(OBJECT(lsms), name, OBJECT(dev)); -+ object_property_add_alias(OBJECT(lsms), alias_prop_name, -+ OBJECT(dev), "drive"); -+ return PFLASH_CFI01(dev); -+} -+ -+ -+static void loongarch_system_flash_create(LoongarchMachineState *lsms) -+{ -+ lsms->flash[0] = loongarch_pflash_create(lsms, "system.flash0", -+ "pflash0"); -+ lsms->flash[1] = loongarch_pflash_create(lsms, "system.flash1", -+ "pflash1"); -+} -+ -+static void loongarch_machine_initfn(Object *obj) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(obj); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ lsms->acpi_build_enabled = lsmc->has_acpi_build; -+ loongarch_system_flash_create(lsms); -+ lsms->oem_id = g_strndup(EFI_ACPI_OEM_ID, 6); -+ lsms->oem_table_id = g_strndup(EFI_ACPI_OEM_TABLE_ID, 6); -+} -+ -+static void ls3a5k_ls7a_machine_options(MachineClass *m) -+{ -+ char *cpu_name = get_host_cpu_model_name(); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_CLASS(m); -+ m->desc = "Loongarch3a5k LS7A1000 machine"; -+ m->max_cpus = LOONGARCH_MAX_VCPUS; -+ m->alias = "loongson7a"; -+ m->is_default = 1; -+ lsmc->isa_io_base = LS3A5K_ISA_IO_BASE; -+ lsmc->ht1lo_pcicfg_base = LS3A5K_HT1LO_PCICFG_BASE; -+ lsmc->pciecfg_base = LS_PCIECFG_BASE; -+ lsmc->ls7a_ioapic_reg_base = LS3A5K_LS7A_IOAPIC_REG_BASE; -+ lsmc->node_shift = 44; -+ strncpy(lsmc->cpu_name, cpu_name, sizeof(lsmc->cpu_name) - 1); -+ lsmc->cpu_name[sizeof(lsmc->cpu_name) - 1] = 0; -+ strncpy(lsmc->bridge_name, "ls7a", sizeof(lsmc->bridge_name) - 1); -+ lsmc->bridge_name[sizeof(lsmc->bridge_name) - 1] = 0; -+ compat_props_add(m->compat_props, loongarch_compat, loongarch_compat_len); -+} -+ -+static void ls3a_board_reset(MachineState *ms) -+{ -+ qemu_devices_reset(); -+#ifdef CONFIG_KVM -+ struct loongarch_kvm_irqchip *chip; -+ int length; -+ -+ if (!kvm_enabled()) { -+ return; -+ } -+ length = sizeof(struct loongarch_kvm_irqchip) + -+ sizeof(struct loongarch_gipiState); -+ chip = g_malloc0(length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS3A_GIPI; -+ chip->len = length; -+ kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ -+ length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct ls7a_ioapic_state); -+ chip = g_realloc(chip, length); -+ memset(chip, 0, length); -+ chip->chip_id = KVM_IRQCHIP_LS7A_IOAPIC; -+ chip->len = length; -+ kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, chip); -+ -+ g_free(chip); -+#endif -+} -+ -+static CpuInstanceProperties ls3a_cpu_index_to_props(MachineState *ms, unsigned cpu_index) -+{ -+ MachineClass *mc = MACHINE_GET_CLASS(ms); -+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); -+ -+ assert(cpu_index < possible_cpus->len); -+ return possible_cpus->cpus[cpu_index].props; -+} -+ -+static int64_t ls3a_get_default_cpu_node_id(const MachineState *ms, int idx) -+{ -+ int nb_numa_nodes = ms->numa_state->num_nodes; -+ int smp_cores = ms->smp.cores; -+ return idx / smp_cores % nb_numa_nodes; -+} -+ -+static void loongarch_class_init(ObjectClass *oc, void *data) -+{ -+ MachineClass *mc = MACHINE_CLASS(oc); -+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_CLASS(oc); -+ -+ lsmc->get_hotplug_handler = mc->get_hotplug_handler; -+ lsmc->has_acpi_build = true; -+ mc->get_hotplug_handler = loongarch_get_hotpug_handler; -+ mc->has_hotpluggable_cpus = true; -+ mc->cpu_index_to_instance_props = ls3a_cpu_index_to_props; -+ mc->possible_cpu_arch_ids = loongarch_possible_cpu_arch_ids; -+ mc->get_default_cpu_node_id = ls3a_get_default_cpu_node_id; -+ mc->default_ram_size = 1 * GiB; -+ mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000"); -+ mc->default_ram_id = "loongarch_ls3a.ram"; -+ -+ mc->reset = ls3a_board_reset; -+ mc->max_cpus = LOONGARCH_MAX_VCPUS; -+ hc->pre_plug = loongarch_machine_device_pre_plug; -+ hc->plug = loongarch_machine_device_plug; -+ hc->unplug = longson_machine_device_unplug; -+ hc->unplug_request = loongarch_machine_device_unplug_request; -+ -+ object_class_property_add(oc, "acpi", "OnOffAuto", -+ loongarch_get_acpi, loongarch_set_acpi, -+ NULL, NULL); -+ object_class_property_set_description(oc, "acpi", -+ "Enable ACPI"); -+} -+ -+static const TypeInfo loongarch_info = { -+ .name = TYPE_LOONGARCH_MACHINE, -+ .parent = TYPE_MACHINE, -+ .abstract = true, -+ .instance_size = sizeof(LoongarchMachineState), -+ .instance_init = loongarch_machine_initfn, -+ .class_size = sizeof(LoongarchMachineClass), -+ .class_init = loongarch_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_HOTPLUG_HANDLER }, -+ { } -+ }, -+ -+}; -+ -+static void loongarch_machine_register_types(void) -+{ -+ type_register_static(&loongarch_info); -+} -+ -+type_init(loongarch_machine_register_types) -+ -+DEFINE_LS3A5K_MACHINE(loongson7a_v1_0, "loongson7a_v1.0", -+ ls3a5k_ls7a_machine_options); -diff --git a/hw/loongarch/larch_hotplug.c b/hw/loongarch/larch_hotplug.c -new file mode 100644 -index 000000000..7bce95712 ---- /dev/null -+++ b/hw/loongarch/larch_hotplug.c -@@ -0,0 +1,355 @@ -+/* -+ * Hotplug emulation on Loongarch system. -+ * -+ * Copyright (c) 2018 Loongarch Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "qemu-common.h" -+#include "qemu/queue.h" -+#include "qemu/units.h" -+#include "qemu/cutils.h" -+#include "qemu/bcd.h" -+#include "hw/hotplug.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/mem/memory-device.h" -+#include "sysemu/numa.h" -+#include "sysemu/cpus.h" -+#include "hw/loongarch/larch.h" -+#include "hw/cpu/core.h" -+#include "hw/nvram/fw_cfg.h" -+ -+/* find cpu slot in machine->possible_cpus by core_id */ -+static CPUArchId *loongarch_find_cpu_slot(MachineState *ms, uint32_t id, -+ int *idx) -+{ -+ int index = id; -+ -+ if (index >= ms->possible_cpus->len) { -+ return NULL; -+ } -+ if (idx) { -+ *idx = index; -+ } -+ return &ms->possible_cpus->cpus[index]; -+} -+ -+static void loongarch_memory_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ Error *local_err = NULL; -+ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); -+ HotplugHandlerClass *hhc; -+ uint64_t size; -+ -+ size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort); -+ if (size % LOONGARCH_HOTPLUG_MEM_ALIGN) { -+ error_setg(&local_err, "Hotplugged memory size must be a multiple of " -+ "%lld MB", LOONGARCH_HOTPLUG_MEM_ALIGN / MiB); -+ goto out; -+ } -+ -+ pc_dimm_plug(PC_DIMM(dev), MACHINE(lsms)); -+ -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->plug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &error_abort); -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_memory_unplug_request(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ Error *local_err = NULL; -+ HotplugHandlerClass *hhc; -+ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); -+ -+ if (!lsms->acpi_dev || !loongarch_is_acpi_enabled(lsms)) { -+ error_setg(&local_err, -+ "memory hotplug is not enabled: missing acpi device or acpi disabled"); -+ goto out; -+ } -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->unplug_request(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_cpu_unplug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ CPUArchId *found_cpu; -+ HotplugHandlerClass *hhc; -+ Error *local_err = NULL; -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->unplug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ -+ if (local_err) { -+ goto out; -+ } -+ -+ loongarch_cpu_destroy(machine, cpu); -+ -+ found_cpu = loongarch_find_cpu_slot(MACHINE(lsms), cpu->id, NULL); -+ found_cpu->cpu = NULL; -+ object_unparent(OBJECT(dev)); -+ lsms->hotpluged_cpu_num -= 1; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_memory_unplug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ Error *local_err = NULL; -+ HotplugHandlerClass *hhc; -+ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); -+ -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->unplug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ -+ if (local_err) { -+ goto out; -+ } -+ -+ pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev)); -+ object_unparent(OBJECT(dev)); -+ -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_cpu_pre_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ MachineState *ms = MACHINE(OBJECT(hotplug_dev)); -+ MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); -+ LoongarchMachineState *lsms = LoongarchMACHINE(ms); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ CPUArchId *cpu_slot; -+ Error *local_err = NULL; -+ int index; -+ int free_index = lsms->hotpluged_cpu_num + ms->smp.cpus; -+ int max_cpus = ms->smp.max_cpus; -+ -+ if (dev->hotplugged && !mc->has_hotpluggable_cpus) { -+ error_setg(&local_err, "CPU hotplug not supported for this machine"); -+ goto out; -+ } -+ -+ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { -+ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", -+ ms->cpu_type); -+ return; -+ } -+ -+ /* if ID is not set, set it based on core properties */ -+ if (cpu->id == UNASSIGNED_CPU_ID) { -+ if ((cpu->core_id) > (max_cpus - 1)) { -+ error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", -+ cpu->core_id, max_cpus - 1); -+ return; -+ } -+ -+ if (free_index > (max_cpus - 1)) { -+ error_setg(errp, "The maximum number of CPUs cannot exceed %u.", -+ max_cpus); -+ return; -+ } -+ -+ if (cpu->core_id != free_index) { -+ error_setg(errp, "Invalid CPU core-id: %u must be :%u", -+ cpu->core_id, free_index); -+ return; -+ } -+ -+ cpu->id = cpu->core_id; -+ } -+ -+ cpu_slot = loongarch_find_cpu_slot(MACHINE(hotplug_dev), cpu->id, &index); -+ if (!cpu_slot) { -+ error_setg(&local_err, "core id %d out of range", cpu->id); -+ goto out; -+ } -+ -+ if (cpu_slot->cpu) { -+ error_setg(&local_err, "core %d already populated", cpu->id); -+ goto out; -+ } -+ -+ numa_cpu_pre_plug(cpu_slot, dev, &local_err); -+ -+ return ; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, -+ Error **errp) -+{ -+ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ PCDIMMDevice *dimm = PC_DIMM(dev); -+ Error *local_err = NULL; -+ uint64_t size; -+ -+ if (!lsms->acpi_dev || !loongarch_is_acpi_enabled(lsms)) { -+ error_setg(errp, -+ "memory hotplug is not enabled: missing acpi device or acpi disabled"); -+ return; -+ } -+ -+ size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ if (size % LOONGARCH_HOTPLUG_MEM_ALIGN) { -+ error_setg(errp, "Hotplugged memory size must be a multiple of " -+ "%lld MB", LOONGARCH_HOTPLUG_MEM_ALIGN / MiB); -+ return; -+ } -+ -+ pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp); -+} -+ -+static void loongarch_cpu_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ CPUArchId *found_cpu; -+ HotplugHandlerClass *hhc; -+ Error *local_err = NULL; -+ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ -+ if (lsms->acpi_dev) { -+ loongarch_cpu_create(machine, cpu, errp); -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->plug(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ if (local_err) { -+ goto out; -+ } -+ } -+ -+ found_cpu = loongarch_find_cpu_slot(MACHINE(lsms), cpu->id, NULL); -+ found_cpu->cpu = OBJECT(dev); -+ lsms->hotpluged_cpu_num += 1; -+out: -+ error_propagate(errp, local_err); -+} -+ -+static void loongarch_cpu_unplug_request(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ MachineState *machine = MACHINE(OBJECT(hotplug_dev)); -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ Error *local_err = NULL; -+ HotplugHandlerClass *hhc; -+ int idx = -1; -+ -+ if (!lsms->acpi_dev) { -+ error_setg(&local_err, "CPU hot unplug not supported without ACPI"); -+ goto out; -+ } -+ -+ loongarch_find_cpu_slot(MACHINE(lsms), cpu->id, &idx); -+ assert(idx != -1); -+ if (idx == 0) { -+ error_setg(&local_err, "Boot CPU is unpluggable"); -+ goto out; -+ } -+ -+ hhc = HOTPLUG_HANDLER_GET_CLASS(lsms->acpi_dev); -+ hhc->unplug_request(HOTPLUG_HANDLER(lsms->acpi_dev), dev, &local_err); -+ -+ if (local_err) { -+ goto out; -+ } -+ -+ out: -+ error_propagate(errp, local_err); -+} -+ -+void longson_machine_device_unplug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); -+ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ loongarch_memory_unplug(hotplug_dev, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ if (!mc->has_hotpluggable_cpus) { -+ error_setg(errp, "CPU hot unplug not supported on this machine"); -+ return; -+ } -+ loongarch_cpu_unplug(hotplug_dev, dev, errp); -+ } else { -+ error_setg(errp, "acpi: device unplug for not supported device" -+ " type: %s", object_get_typename(OBJECT(dev))); -+ } -+ -+ return; -+} -+ -+void loongarch_machine_device_unplug_request(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ loongarch_memory_unplug_request(hotplug_dev, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ loongarch_cpu_unplug_request(hotplug_dev, dev, errp); -+ } -+} -+ -+HotplugHandler *loongarch_get_hotpug_handler(MachineState *machine, -+ DeviceState *dev) -+{ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || -+ object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ return HOTPLUG_HANDLER(machine); -+ } -+ return NULL; -+} -+ -+void loongarch_machine_device_pre_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ loongarch_memory_pre_plug(hotplug_dev, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ loongarch_cpu_pre_plug(hotplug_dev, dev, errp); -+ } -+} -+ -+void loongarch_machine_device_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp) -+{ -+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -+ loongarch_memory_plug(hotplug_dev, dev, errp); -+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ loongarch_cpu_plug(hotplug_dev, dev, errp); -+ } -+} -+ -diff --git a/hw/loongarch/larch_int.c b/hw/loongarch/larch_int.c -new file mode 100644 -index 000000000..ca073a19c ---- /dev/null -+++ b/hw/loongarch/larch_int.c -@@ -0,0 +1,91 @@ -+/* -+ * QEMU LOONGARCH interrupt support -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu/main-loop.h" -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/loongarch/cpudevs.h" -+#include "cpu.h" -+#include "sysemu/kvm.h" -+#include "kvm_larch.h" -+#ifdef CONFIG_KVM -+#include -+#endif -+ -+static void cpu_irq_request(void *opaque, int irq, int level) -+{ -+ LOONGARCHCPU *cpu = opaque; -+ CPULOONGARCHState *env = &cpu->env; -+ CPUState *cs = CPU(cpu); -+ bool locked = false; -+ -+ if (irq < 0 || irq > 13) { -+ return; -+ } -+ -+ /* Make sure locking works even if BQL is already held by the caller */ -+ if (!qemu_mutex_iothread_locked()) { -+ locked = true; -+ qemu_mutex_lock_iothread(); -+ } -+ -+ if (level) { -+ env->CSR_ESTAT |= 1 << irq; -+ } else { -+ env->CSR_ESTAT &= ~(1 << irq); -+ } -+ -+ if (kvm_enabled()) { -+ if (irq == 2) { -+ kvm_loongarch_set_interrupt(cpu, irq, level); -+ } else if (irq == 3) { -+ kvm_loongarch_set_interrupt(cpu, irq, level); -+ } else if (irq == 12) { -+ kvm_loongarch_set_ipi_interrupt(cpu, irq, level); -+ } -+ } -+ -+ if (env->CSR_ESTAT & CSR_ESTAT_IPMASK) { -+ cpu_interrupt(cs, CPU_INTERRUPT_HARD); -+ } else { -+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); -+ } -+ -+ if (locked) { -+ qemu_mutex_unlock_iothread(); -+ } -+} -+ -+void cpu_init_irq(LOONGARCHCPU *cpu) -+{ -+ CPULOONGARCHState *env = &cpu->env; -+ qemu_irq *qi; -+ int i; -+ -+ qi = qemu_allocate_irqs(cpu_irq_request, loongarch_env_get_cpu(env), N_IRQS); -+ for (i = 0; i < N_IRQS; i++) { -+ env->irq[i] = qi[i]; -+ } -+} -+ -+ -diff --git a/hw/loongarch/ls7a_nb.c b/hw/loongarch/ls7a_nb.c -new file mode 100644 -index 000000000..5a500fbd5 ---- /dev/null -+++ b/hw/loongarch/ls7a_nb.c -@@ -0,0 +1,352 @@ -+/* -+ * Loongarch 7A1000 north bridge support -+ * -+ * Copyright (c) 2019 Loongarch Technology -+ * Authors: -+ * Zhu Chen -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+ -+#include "hw/hw.h" -+#include "hw/irq.h" -+#include "hw/sysbus.h" -+#include "hw/pci/pci.h" -+#include "hw/i386/pc.h" -+#include "hw/pci/pci_host.h" -+#include "hw/pci/pcie_host.h" -+#include "sysemu/sysemu.h" -+#include "exec/address-spaces.h" -+#include "qapi/error.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/acpi/ls7a.h" -+#include "hw/i386/pc.h" -+#include "hw/isa/isa.h" -+#include "hw/boards.h" -+#include "qemu/log.h" -+#include "hw/loongarch/bios.h" -+#include "hw/loader.h" -+#include "elf.h" -+#include "exec/address-spaces.h" -+#include "exec/memory.h" -+#include "hw/pci/pci_bridge.h" -+#include "hw/pci/pci_bus.h" -+#include "linux/kvm.h" -+#include "sysemu/kvm.h" -+#include "sysemu/runstate.h" -+#include "sysemu/reset.h" -+#include "migration/vmstate.h" -+#include "hw/loongarch/larch.h" -+#include "hw/loongarch/ls7a.h" -+ -+#undef DEBUG_LS7A -+ -+#ifdef DEBUG_LS7A -+#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __func__, ##__VA_ARGS__) -+#else -+#define DPRINTF(fmt, ...) -+#endif -+ -+static void ls7a_reset(void *opaque) -+{ -+ uint64_t wmask; -+ wmask = ~(-1); -+ -+ PCIDevice *dev = opaque; -+ pci_set_word(dev->config + PCI_VENDOR_ID, 0x0014); -+ pci_set_word(dev->wmask + PCI_VENDOR_ID, wmask & 0xffff); -+ pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); -+ pci_set_word(dev->config + PCI_DEVICE_ID, 0x7a00); -+ pci_set_word(dev->wmask + PCI_DEVICE_ID, wmask & 0xffff); -+ pci_set_word(dev->cmask + PCI_DEVICE_ID, 0xffff); -+ pci_set_word(dev->config + 0x4, 0x0000); -+ pci_set_word(dev->config + PCI_STATUS, 0x0010); -+ pci_set_word(dev->wmask + PCI_STATUS, wmask & 0xffff); -+ pci_set_word(dev->cmask + PCI_STATUS, 0xffff); -+ pci_set_byte(dev->config + PCI_REVISION_ID, 0x0); -+ pci_set_byte(dev->wmask + PCI_REVISION_ID, wmask & 0xff); -+ pci_set_byte(dev->cmask + PCI_REVISION_ID, 0xff); -+ pci_set_byte(dev->config + 0x9, 0x00); -+ pci_set_byte(dev->wmask + 0x9, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0x9, 0xff); -+ pci_set_byte(dev->config + 0xa, 0x00); -+ pci_set_byte(dev->wmask + 0xa, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0xa, 0xff); -+ pci_set_byte(dev->config + 0xb, 0x06); -+ pci_set_byte(dev->wmask + 0xb, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0xb, 0xff); -+ pci_set_byte(dev->config + 0xc, 0x00); -+ pci_set_byte(dev->wmask + 0xc, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0xc, 0xff); -+ pci_set_byte(dev->config + 0xe, 0x80); -+ pci_set_byte(dev->wmask + 0xe, wmask & 0xff); -+ pci_set_byte(dev->cmask + 0xe, 0xff); -+} -+ -+static const VMStateDescription vmstate_ls7a_pcie = { -+ .name = "LS7A_PCIE", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_PCI_DEVICE(dev, LS7APCIState), -+ VMSTATE_STRUCT(pm, LS7APCIState, 0, vmstate_ls7a_pm, LS7APCIPMRegs), -+ VMSTATE_UINT32_ARRAY(regs, LS7APCIState, LS7A_REGS), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin) -+{ -+ PCIINTxRoute route; -+ -+ route.irq = pin; -+ route.mode = PCI_INTX_ENABLED; -+ return route; -+} -+ -+static int pci_ls7a_map_irq(PCIDevice *d, int irq_num) -+{ -+ int irq; -+ -+ irq = 16 + ((PCI_SLOT(d->devfn) * 4 + irq_num) & 0xf); -+ return irq; -+} -+ -+static void pci_ls7a_set_irq(void *opaque, int irq_num, int level) -+{ -+ qemu_irq *pic = opaque; -+ DPRINTF("------ %s irq %d %d\n", __func__, irq_num, level); -+ qemu_set_irq(pic[irq_num], level); -+} -+ -+/* -+static int ls7a_pciehost_initfn(SysBusDevice *dev) -+{ -+ return 0; -+}*/ -+ -+static void ls7a_pcie_realize(PCIDevice *dev, Error **errp) -+{ -+ LS7APCIState *s = PCIE_LS7A(dev); -+ /* Ls7a North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */ -+ pci_config_set_prog_interface(dev->config, 0x00); -+ -+ /* set the default value of north bridge pci config */ -+ qemu_register_reset(ls7a_reset, s); -+} -+ -+static void pci_ls7a_config_write(void *opaque, hwaddr addr, -+ uint64_t val, unsigned size) -+{ -+ hwaddr tmp_addr; -+ tmp_addr = addr & 0xffffff; -+ -+ pci_data_write(opaque, tmp_addr, val, size); -+} -+ -+static uint64_t pci_ls7a_config_read(void *opaque, -+ hwaddr addr, unsigned size) -+{ -+ uint64_t val; -+ hwaddr tmp_addr; -+ -+ tmp_addr = addr & 0xffffff; -+ val = pci_data_read(opaque, tmp_addr, size); -+ -+ if (addr & 0x3c) { -+ DPRINTF(TARGET_FMT_plx" val %lx\n", addr, val); -+ } -+ return val; -+} -+ -+static const MemoryRegionOps pci_ls7a_config_ops = { -+ .read = pci_ls7a_config_read, -+ .write = pci_ls7a_config_write, -+ /* Set to access 64bits data, because default to 32bits*/ -+ .valid = { -+ .min_access_size = 1, -+ .max_access_size = 4, -+ }, -+ /* Set to access 64bits data, because default to 32bits*/ -+ .impl = { -+ .min_access_size = 1, -+ .max_access_size = 4, -+ }, -+ .endianness = DEVICE_NATIVE_ENDIAN, -+ -+}; -+ -+static AddressSpace *ls7a_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) -+{ -+ return &address_space_memory; -+} -+ -+static PCIBus *pci_ls7a_init(MachineState *machine, DeviceState *dev, -+ qemu_irq *pic) -+{ -+ LoongarchMachineState *lsms = LoongarchMACHINE(machine); -+ LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ PCIExpressHost *e; -+ SysBusDevice *sysbus; -+ MemoryRegion *iomem = g_new(MemoryRegion, 1); -+ PCIHostState *phb; -+ -+ e = PCIE_HOST_BRIDGE(dev); -+ sysbus = SYS_BUS_DEVICE(e); -+ phb = PCI_HOST_BRIDGE(e); -+ phb->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq, -+ pci_ls7a_map_irq, pic, -+ get_system_memory(), get_system_io(), -+ (1 << 3), 128, TYPE_PCIE_BUS); -+ pcie_host_mmcfg_update(e, true, lsmc->pciecfg_base, LS_PCIECFG_SIZE); -+ DPRINTF("------ %d\n", __LINE__); -+ -+ pci_bus_set_route_irq_fn(phb->bus, ls7a_route_intx_pin_to_irq); -+ memory_region_init_io(iomem, NULL, &pci_ls7a_config_ops, phb->bus, -+ "ls7a_pci_conf", HT1LO_PCICFG_SIZE); -+ sysbus_init_mmio(sysbus, iomem); -+ sysbus_mmio_map(sysbus, 0, lsmc->ht1lo_pcicfg_base); -+ -+ return phb->bus; -+} -+ -+PCIBus *ls7a_init(MachineState *machine, qemu_irq *pic, DeviceState **ls7a_dev) -+{ -+ DeviceState *dev; -+ PCIHostState *phb; -+ LS7APCIState *pbs; -+ PCIDevice *pcid; -+ PCIBus *pci_bus; -+ PCIExpressHost *e; -+ -+ /*1. init the HT PCI CFG*/ -+ DPRINTF("------ %d\n", __LINE__); -+ dev = qdev_new(TYPE_LS7A_PCIE_HOST_BRIDGE); -+ e = PCIE_HOST_BRIDGE(dev); -+ phb = PCI_HOST_BRIDGE(e); -+ -+ DPRINTF("------ %d\n", __LINE__); -+ pci_bus = pci_ls7a_init(machine, dev, pic); -+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); -+ phb->bus = pci_bus; -+ /* set the pcihost pointer after rs780_pcihost_initfn is called */ -+ DPRINTF("------ %d\n", __LINE__); -+ pcid = pci_new(PCI_DEVFN(0, 0), TYPE_PCIE_LS7A); -+ pbs = PCIE_LS7A(pcid); -+ pbs->pciehost = LS7A_PCIE_HOST_BRIDGE(dev); -+ pbs->pciehost->pci_dev = pbs; -+ -+ if (ls7a_dev) { -+ *ls7a_dev = DEVICE(pcid); -+ } -+ -+ pci_realize_and_unref(pcid, phb->bus, &error_fatal); -+ -+ /* IOMMU */ -+ pci_setup_iommu(phb->bus, ls7a_pci_dma_iommu, NULL); -+ -+ ls7a_pm_init(&pbs->pm, pic); -+ DPRINTF("------ %d\n", __LINE__); -+ /*3. init the north bridge VGA,not do now*/ -+ return pci_bus; -+} -+ -+LS7APCIState *get_ls7a_type(Object *obj) -+{ -+ LS7APCIState *pbs; -+ -+ pbs = PCIE_LS7A(obj); -+ return pbs; -+} -+ -+static void ls7a_pcie_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); -+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); -+ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass); -+ -+ k->realize = ls7a_pcie_realize; -+ k->vendor_id = 0x0014; -+ k->device_id = 0x7a00; -+ k->revision = 0x00; -+ k->class_id = PCI_CLASS_BRIDGE_HOST; -+ dc->desc = "LS7A1000 PCIE Host bridge"; -+ dc->vmsd = &vmstate_ls7a_pcie; -+ /* -+ * PCI-facing part of the host bridge, not usable without the -+ * host-facing part, which can't be device_add'ed, yet. -+ */ -+ dc->user_creatable = false; -+ hc->plug = ls7a_pm_device_plug_cb; -+ hc->unplug_request = ls7a_pm_device_unplug_request_cb; -+ hc->unplug = ls7a_pm_device_unplug_cb; -+ adevc->ospm_status = ls7a_pm_ospm_status; -+ adevc->send_event = ls7a_send_gpe; -+ adevc->madt_cpu = ls7a_madt_cpu_entry; -+} -+ -+static void ls7a_pci_add_properties(LS7APCIState *ls7a) -+{ -+ ls7a_pm_add_properties(OBJECT(ls7a), &ls7a->pm, NULL); -+} -+ -+static void ls7a_pci_initfn(Object *obj) -+{ -+ LS7APCIState *ls7a = get_ls7a_type(obj); -+ -+ ls7a_pci_add_properties(ls7a); -+} -+ -+static const TypeInfo ls7a_pcie_device_info = { -+ .name = TYPE_PCIE_LS7A, -+ .parent = TYPE_PCI_DEVICE, -+ .instance_size = sizeof(LS7APCIState), -+ .class_init = ls7a_pcie_class_init, -+ .instance_init = ls7a_pci_initfn, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_HOTPLUG_HANDLER }, -+ { TYPE_ACPI_DEVICE_IF }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, -+}; -+ -+static void ls7a_pciehost_class_init(ObjectClass *klass, void *data) -+{ -+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); -+ k->parent_class.fw_name = "pci"; -+} -+ -+static const TypeInfo ls7a_pciehost_info = { -+ .name = TYPE_LS7A_PCIE_HOST_BRIDGE, -+ .parent = TYPE_PCIE_HOST_BRIDGE, -+ .instance_size = sizeof(LS7APCIEHost), -+ .class_init = ls7a_pciehost_class_init, -+}; -+ -+static void ls7a_register_types(void) -+{ -+ type_register_static(&ls7a_pciehost_info); -+ type_register_static(&ls7a_pcie_device_info); -+} -+ -+type_init(ls7a_register_types) -diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build -new file mode 100644 -index 000000000..81ee99a02 ---- /dev/null -+++ b/hw/loongarch/meson.build -@@ -0,0 +1,15 @@ -+loongarch_ss = ss.source_set() -+loongarch_ss.add(files('larch_3a.c'), fdt) -+loongarch_ss.add(files( -+ 'larch_int.c', -+ 'larch_hotplug.c', -+ 'ls7a_nb.c', -+ 'ioapic.c', -+ 'acpi-build.c', -+ 'ipi.c', -+ 'apic.c', -+ 'iocsr.c', -+)) -+ -+hw_arch += {'loongarch64': loongarch_ss} -+ -diff --git a/include/hw/loongarch/bios.h b/include/hw/loongarch/bios.h -new file mode 100644 -index 000000000..3677303bf ---- /dev/null -+++ b/include/hw/loongarch/bios.h -@@ -0,0 +1,5 @@ -+#include "qemu/units.h" -+#include "cpu.h" -+ -+#define BIOS_SIZE (4 * MiB) -+#define BIOS_FILENAME "loongarch_bios.bin" -diff --git a/include/hw/loongarch/cpudevs.h b/include/hw/loongarch/cpudevs.h -new file mode 100644 -index 000000000..c05ae7a7f ---- /dev/null -+++ b/include/hw/loongarch/cpudevs.h -@@ -0,0 +1,53 @@ -+#ifndef HW_LOONGARCH_CPUDEVS_H -+#define HW_LOONGARCH_CPUDEVS_H -+ -+#include "target/loongarch64/cpu-qom.h" -+ -+/* Definitions for LOONGARCH CPU internal devices. */ -+#define MAX_GIPI_CORE_NUM 256 -+#define MAX_GIPI_MBX_NUM 4 -+ -+#define LS3A_INTC_IP 8 -+#define MAX_CORES 256 -+#define EXTIOI_IRQS (256) -+#define EXTIOI_IRQS_BITMAP_SIZE (256 / 8) -+/* map to ipnum per 32 irqs */ -+#define EXTIOI_IRQS_IPMAP_SIZE (256 / 32) -+ -+typedef struct gipi_core { -+ uint32_t status; -+ uint32_t en; -+ uint32_t set; -+ uint32_t clear; -+ uint64_t buf[MAX_GIPI_MBX_NUM]; -+ qemu_irq irq; -+} gipi_core; -+ -+typedef struct gipiState { -+ gipi_core core[MAX_GIPI_CORE_NUM]; -+} gipiState; -+ -+typedef struct apicState { -+ /* hardware state */ -+ uint8_t ext_en[EXTIOI_IRQS_BITMAP_SIZE]; -+ uint8_t ext_bounce[EXTIOI_IRQS_BITMAP_SIZE]; -+ uint8_t ext_isr[EXTIOI_IRQS_BITMAP_SIZE]; -+ uint8_t ext_coreisr[MAX_CORES][EXTIOI_IRQS_BITMAP_SIZE]; -+ uint8_t ext_ipmap[EXTIOI_IRQS_IPMAP_SIZE]; -+ uint8_t ext_coremap[EXTIOI_IRQS]; -+ uint16_t ext_nodetype[16]; -+ uint64_t ext_control; -+ -+ /* software state */ -+ uint8_t ext_sw_ipmap[EXTIOI_IRQS]; -+ uint8_t ext_sw_coremap[EXTIOI_IRQS]; -+ uint8_t ext_ipisr[MAX_CORES * LS3A_INTC_IP][EXTIOI_IRQS_BITMAP_SIZE]; -+ -+ qemu_irq parent_irq[MAX_CORES][LS3A_INTC_IP]; -+ qemu_irq *irq; -+} apicState; -+ -+void cpu_init_irq(LOONGARCHCPU *cpu); -+void cpu_loongarch_clock_init(LOONGARCHCPU *cpu); -+ -+#endif -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -new file mode 100644 -index 000000000..0886ed52a ---- /dev/null -+++ b/include/hw/loongarch/larch.h -@@ -0,0 +1,163 @@ -+/* -+ * Hotplug emulation on Loongarch system. -+ * -+ * Copyright (c) 2018 Loongarch Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+ -+#ifndef HW_LOONGARCH_H -+#define HW_LOONGARCH_H -+ -+#include "target/loongarch64/cpu.h" -+#include "qemu-common.h" -+#include "exec/memory.h" -+#include "hw/mem/pc-dimm.h" -+#include "hw/hotplug.h" -+#include "hw/boards.h" -+#include "hw/acpi/acpi.h" -+#include "qemu/notify.h" -+#include "qemu/error-report.h" -+#include "qemu/queue.h" -+#include "hw/acpi/memory_hotplug.h" -+#include "hw/loongarch/cpudevs.h" -+#include "hw/block/flash.h" -+ -+#define LOONGARCH_MAX_VCPUS 256 -+#define LOONGARCH_MAX_PFLASH 2 -+/* 256MB alignment for hotplug memory region */ -+#define LOONGARCH_HOTPLUG_MEM_ALIGN (1ULL << 28) -+#define LOONGARCH_MAX_RAM_SLOTS 10 -+ -+/* Memory types: */ -+#define SYSTEM_RAM 1 -+#define SYSTEM_RAM_RESERVED 2 -+#define ACPI_TABLE 3 -+#define ACPI_NVS 4 -+#define SYSTEM_PMEM 5 -+ -+#define MAX_MEM_MAP 128 -+ -+typedef struct LoongarchMachineClass { -+ /*< private >*/ -+ MachineClass parent_class; -+ -+ /* Methods: */ -+ HotplugHandler *(*get_hotplug_handler)(MachineState *machine, -+ DeviceState *dev); -+ -+ bool has_acpi_build; -+ -+ /* save different cpu address*/ -+ uint64_t isa_io_base; -+ uint64_t ht_control_regs_base; -+ uint64_t hpet_mmio_addr; -+ uint64_t smbus_cfg_base; -+ uint64_t ht1lo_pcicfg_base; -+ uint64_t pciecfg_base; -+ uint64_t ls7a_ioapic_reg_base; -+ uint32_t node_shift; -+ char cpu_name[40]; -+ char bridge_name[16]; -+ -+} LoongarchMachineClass; -+ -+typedef struct ResetData { -+ LOONGARCHCPU *cpu; -+ uint64_t vector; -+} ResetData; -+ -+typedef struct LoongarchMachineState { -+ /*< private >*/ -+ MachineState parent_obj; -+ -+ /* */ -+ ram_addr_t hotplug_memory_size; -+ -+ /* State for other subsystems/APIs: */ -+ Notifier machine_done; -+ /* Pointers to devices and objects: */ -+ HotplugHandler *acpi_dev; -+ int ram_slots; -+ ResetData *reset_info[LOONGARCH_MAX_VCPUS]; -+ DeviceState *rtc; -+ gipiState *gipi; -+ apicState *apic; -+ -+ FWCfgState *fw_cfg; -+ bool acpi_build_enabled; -+ bool apic_xrupt_override; -+ CPUArchIdList *possible_cpus; -+ PFlashCFI01 *flash[LOONGARCH_MAX_PFLASH]; -+ void *fdt; -+ int fdt_size; -+ unsigned int hotpluged_cpu_num; -+ OnOffAuto acpi; -+ char *oem_id; -+ char *oem_table_id; -+} LoongarchMachineState; -+ -+#define LOONGARCH_MACHINE_ACPI_DEVICE_PROP "loongarch-acpi-device" -+#define TYPE_LOONGARCH_MACHINE "loongarch-machine" -+ -+#define LoongarchMACHINE(obj) \ -+ OBJECT_CHECK(LoongarchMachineState, (obj), TYPE_LOONGARCH_MACHINE) -+#define LoongarchMACHINE_GET_CLASS(obj) \ -+ OBJECT_GET_CLASS(LoongarchMachineClass, (obj), TYPE_LOONGARCH_MACHINE) -+#define LoongarchMACHINE_CLASS(klass) \ -+ OBJECT_CLASS_CHECK(LoongarchMachineClass, (klass), TYPE_LOONGARCH_MACHINE) -+ -+#define DEFINE_LOONGARCH_MACHINE(suffix, namestr, initfn, optsfn) \ -+ static void loongarch_machine_##suffix##_class_init(ObjectClass *oc, void *data) \ -+ { \ -+ MachineClass *mc = MACHINE_CLASS(oc); \ -+ optsfn(mc); \ -+ mc->init = initfn; \ -+ } \ -+ static const TypeInfo loongarch_machine_type_##suffix = { \ -+ .name = namestr TYPE_MACHINE_SUFFIX, \ -+ .parent = TYPE_LOONGARCH_MACHINE, \ -+ .class_init = loongarch_machine_##suffix##_class_init, \ -+ }; \ -+ static void loongarch_machine_init_##suffix(void) \ -+ { \ -+ type_register(&loongarch_machine_type_##suffix); \ -+ } \ -+ type_init(loongarch_machine_init_##suffix) -+ -+void loongarch_machine_device_unplug_request(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+void longson_machine_device_unplug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+HotplugHandler *loongarch_get_hotpug_handler(MachineState *machine, -+ DeviceState *dev); -+void loongarch_machine_device_pre_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+void loongarch_machine_device_plug(HotplugHandler *hotplug_dev, -+ DeviceState *dev, Error **errp); -+ -+LOONGARCHCPU *loongarch_cpu_create(MachineState *machine, LOONGARCHCPU *cpu, -+ Error **errp); -+void loongarch_cpu_destroy(MachineState *machine, LOONGARCHCPU *cpu); -+int cpu_init_ipi(LoongarchMachineState *ms, qemu_irq parent, int cpu); -+int cpu_init_apic(LoongarchMachineState *ms, CPULOONGARCHState *env, int cpu); -+int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type); -+bool loongarch_is_acpi_enabled(LoongarchMachineState *vms); -+ -+/* acpi-build.c */ -+void ls7a_madt_cpu_entry(AcpiDeviceIf *adev, int uid, -+ const CPUArchIdList *apic_ids, GArray *entry, bool force_enabled); -+void slave_cpu_reset(void *opaque); -+extern uint64_t host_cpufreq; -+#endif -diff --git a/include/hw/loongarch/ls7a.h b/include/hw/loongarch/ls7a.h -new file mode 100644 -index 000000000..686af763a ---- /dev/null -+++ b/include/hw/loongarch/ls7a.h -@@ -0,0 +1,152 @@ -+#ifndef HW_LS7A_H -+#define HW_LS7A_H -+ -+#include "hw/hw.h" -+#include "hw/isa/isa.h" -+#include "hw/sysbus.h" -+#include "hw/isa/apm.h" -+#include "hw/pci/pci.h" -+#include "hw/pci/pcie_host.h" -+#include "hw/pci/pci_bridge.h" -+#include "hw/acpi/acpi.h" -+#include "hw/acpi/ls7a.h" -+#include "hw/pci/pci_bus.h" -+ -+/* LS7A PCH Registers (Misc, Confreg) */ -+#define LS7A_PCH_REG_BASE 0x10000000UL -+#define LS3A5K_LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE) -+#define LS7A_MISC_REG_BASE (LS7A_PCH_REG_BASE + 0x00080000) -+#define LS7A_ACPI_REG_BASE (LS7A_MISC_REG_BASE + 0x00050000) -+ -+#define LOONGARCH_PCH_IRQ_BASE 64 -+#define LS7A_UART_IRQ (LOONGARCH_PCH_IRQ_BASE + 2) -+#define LS7A_RTC_IRQ (LOONGARCH_PCH_IRQ_BASE + 3) -+#define LS7A_SCI_IRQ (LOONGARCH_PCH_IRQ_BASE + 4) -+#define LS7A_ACPI_IO_BASE 0x800 -+#define LS7A_ACPI_IO_SIZE 0x100 -+#define LS7A_PM_EVT_BLK (0x0C) /* 4 bytes */ -+#define LS7A_PM_CNT_BLK (0x14) /* 2 bytes */ -+#define LS7A_GPE0_STS_REG (0x28) /* 4 bytes */ -+#define LS7A_GPE0_ENA_REG (0x2C) /* 4 bytes */ -+#define LS7A_GPE0_RESET_REG (0x30) /* 4 bytes */ -+#define LS7A_PM_TMR_BLK (0x18) /* 4 bytes */ -+#define LS7A_GPE0_LEN (8) -+#define LS7A_RTC_REG_BASE (LS7A_MISC_REG_BASE + 0x00050100) -+#define LS7A_RTC_LEN (0x100) -+ -+#define ACPI_IO_BASE (LS7A_ACPI_REG_BASE) -+#define ACPI_GPE0_LEN (LS7A_GPE0_LEN) -+#define ACPI_IO_SIZE (LS7A_ACPI_IO_SIZE) -+#define ACPI_SCI_IRQ (LS7A_SCI_IRQ) -+ -+#define LS3A5K_ISA_IO_BASE 0x18000000UL -+#define LS_ISA_MEM_BASE 0x40000000 -+#define LS3A5K_HT1LO_PCICFG_BASE 0x1a000000 -+#define HT1LO_PCICFG_SIZE 0x02000000 -+#define LS_BIOS_BASE 0x1c000000 -+#define LS_BIOS_VAR_BASE 0x1c3a0000 -+#define LS_BIOS_SIZE (4 * 1024 * 1024) -+ -+#define FW_CFG_ADDR 0x1e020000 -+#define LS7A_REG_BASE 0x1FE00000 -+#define LS7A_PCICONFIG_BASE (LS7A_REG_BASE + 0x30) -+#define LS7A_PCICONFIG_SIZE (0x100) -+#define LS7A_INTERNAL_REG_BASE (LS7A_REG_BASE + 0x100) -+#define LS7A_INTERNAL_REG_SIZE (0xE0) -+#define LS7A_REGS (0xE0 >> 2) -+#define LS7A_UART_BASE 0x1fe001e0 -+#define LS7A_UART_LEN 0x8 -+ -+#define LS_FDT_BASE 0x1c400000 -+#define LS_FDT_SIZE 0x100000 -+ -+#define LS_PCIECFG_BASE 0x20000000 -+#define LS_PCIECFG_SIZE 0x08000000 -+#define MSI_ADDR_LOW 0x2FF00000 -+#define MSI_ADDR_HI 0x0 -+ -+#define SMP_GIPI_MAILBOX 0x1f000000ULL -+#define CORE0_STATUS_OFF 0x000 -+#define CORE0_EN_OFF 0x004 -+#define CORE0_SET_OFF 0x008 -+#define CORE0_CLEAR_OFF 0x00c -+#define CORE0_BUF_20 0x020 -+#define CORE0_BUF_28 0x028 -+#define CORE0_BUF_30 0x030 -+#define CORE0_BUF_38 0x038 -+#define CORE0_IPI_SEND 0x040 -+#define CORE0_MAIL_SEND 0x048 -+ -+#define INT_ROUTER_REGS_BASE 0x1fe01400UL -+#define INT_ROUTER_REGS_SIZE 0x100 -+#define INT_ROUTER_REGS_SYS_INT0 0x00 -+#define INT_ROUTER_REGS_SYS_INT1 0x01 -+#define INT_ROUTER_REGS_SYS_INT2 0x02 -+#define INT_ROUTER_REGS_SYS_INT3 0x03 -+#define INT_ROUTER_REGS_PCI_INT0 0x04 -+#define INT_ROUTER_REGS_PCI_INT1 0x05 -+#define INT_ROUTER_REGS_PCI_INT2 0x06 -+#define INT_ROUTER_REGS_PCI_INT3 0x07 -+#define INT_ROUTER_REGS_MATRIX_INT0 0x08 -+#define INT_ROUTER_REGS_MATRIX_INT1 0x09 -+#define INT_ROUTER_REGS_LPC_INT 0x0a -+#define INT_ROUTER_REGS_MC0 0x0b -+#define INT_ROUTER_REGS_MC1 0x0c -+#define INT_ROUTER_REGS_BARRIER 0x0d -+#define INT_ROUTER_REGS_THSENS_INT 0x0e -+#define INT_ROUTER_REGS_PCI_PERR 0x0f -+#define INT_ROUTER_REGS_HT0_INT0 0x10 -+#define INT_ROUTER_REGS_HT0_INT1 0x11 -+#define INT_ROUTER_REGS_HT0_INT2 0x12 -+#define INT_ROUTER_REGS_HT0_INT3 0x13 -+#define INT_ROUTER_REGS_HT0_INT4 0x14 -+#define INT_ROUTER_REGS_HT0_INT5 0x15 -+#define INT_ROUTER_REGS_HT0_INT6 0x16 -+#define INT_ROUTER_REGS_HT0_INT7 0x17 -+#define INT_ROUTER_REGS_HT1_INT0 0x18 -+#define INT_ROUTER_REGS_HT1_INT1 0x19 -+#define INT_ROUTER_REGS_HT1_INT2 0x1a -+#define INT_ROUTER_REGS_HT1_INT3 0x1b -+#define INT_ROUTER_REGS_HT1_INT4 0x1c -+#define INT_ROUTER_REGS_HT1_INT5 0x1d -+#define INT_ROUTER_REGS_HT1_INT6 0x1e -+#define INT_ROUTER_REGS_HT1_INT7 0x1f -+#define INT_ROUTER_REGS_ISR 0x20 -+#define INT_ROUTER_REGS_EN 0x24 -+#define INT_ROUTER_REGS_EN_SET 0x28 -+#define INT_ROUTER_REGS_EN_CLR 0x2c -+#define INT_ROUTER_REGS_EDGE 0x38 -+#define INT_ROUTER_REGS_CORE0_INTISR 0x40 -+#define INT_ROUTER_REGS_CORE1_INTISR 0x48 -+#define INT_ROUTER_REGS_CORE2_INTISR 0x50 -+#define INT_ROUTER_REGS_CORE3_INTISR 0x58 -+ -+typedef struct LS7APCIState LS7APCIState; -+typedef struct LS7APCIEHost { -+ PCIExpressHost parent_obj; -+ LS7APCIState *pci_dev; -+} LS7APCIEHost; -+ -+struct LS7APCIState { -+ PCIDevice dev; -+ -+ LS7APCIEHost *pciehost; -+ uint32_t regs[LS7A_REGS]; -+ -+ /* LS7A registers */ -+ MemoryRegion iomem; -+ LS7APCIPMRegs pm; -+}; -+ -+#define TYPE_LS7A_PCIE_HOST_BRIDGE "ls7a1000-pciehost" -+#define LS7A_PCIE_HOST_BRIDGE(obj) \ -+ OBJECT_CHECK(LS7APCIEHost, (obj), TYPE_LS7A_PCIE_HOST_BRIDGE) -+ -+#define TYPE_PCIE_LS7A "ls7a1000_pcie" -+#define PCIE_LS7A(obj) \ -+ OBJECT_CHECK(LS7APCIState, (obj), TYPE_PCIE_LS7A) -+ -+PCIBus *ls7a_init(MachineState *machine, qemu_irq *irq, DeviceState **ls7a_dev); -+LS7APCIState *get_ls7a_type(Object *obj); -+ -+#endif /* HW_LS7A_H */ --- -2.43.5 - diff --git a/0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch b/0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch deleted file mode 100644 index ba1f14ad220d111531f83d92b2fc619607cb0c10..0000000000000000000000000000000000000000 --- a/0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 6dcfcd61e610da4e8d7dcfb6c3eefd7fc8a67c45 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Wed, 25 Aug 2021 09:59:16 +0800 -Subject: [PATCH 3/8] anolis: csv/i386: add command to load data to guest - memory - -The KVM_CSV_LAUNCH_ENCRYPT_DATA command is used to load data to an -encrypted guest memory in an isolated memory region that guest owns. - -Signed-off-by: Xin Jiang -Change-Id: I6d4bea4969a0afa87fb8f2e52fb7ab02ec0db2ed ---- - linux-headers/linux/kvm.h | 7 ++++ - target/i386/csv-sysemu-stub.c | 5 +++ - target/i386/csv.c | 69 +++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 2 + - target/i386/trace-events | 3 ++ - 5 files changed, 86 insertions(+) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index b15b8f5550..53f9202ffb 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1813,6 +1813,13 @@ enum csv_cmd_id { - KVM_CSV_NR_MIN = 0xc0, - - KVM_CSV_INIT = KVM_CSV_NR_MIN, -+ KVM_CSV_LAUNCH_ENCRYPT_DATA, -+}; -+ -+struct kvm_csv_launch_encrypt_data { -+ __u64 gpa; -+ __u64 uaddr; -+ __u32 len; - }; - - struct kvm_csv_init_data { -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index dbd710dc6f..236a6909d2 100644 ---- a/target/i386/csv-sysemu-stub.c -+++ b/target/i386/csv-sysemu-stub.c -@@ -19,3 +19,8 @@ int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - { - return 0; - } -+ -+int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) -+{ -+ g_assert_not_reached(); -+} -diff --git a/target/i386/csv.c b/target/i386/csv.c -index c11f59f30c..3b3dff5174 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -14,11 +14,13 @@ - #include "qemu/osdep.h" - - #include -+#include "qapi/error.h" - - #ifdef CONFIG_NUMA - #include - #endif - -+#include "trace.h" - #include "cpu.h" - #include "sev.h" - #include "csv.h" -@@ -93,3 +95,70 @@ csv_enabled(void) - - return sev_es_enabled() && (csv_guest.policy & GUEST_POLICY_CSV_BIT); - } -+ -+static bool -+csv_check_state(SevState state) -+{ -+ return *((SevState *)csv_guest.state) == state ? true : false; -+} -+ -+static int -+csv_ioctl(int cmd, void *data, int *error) -+{ -+ if (csv_guest.sev_ioctl) -+ return csv_guest.sev_ioctl(csv_guest.sev_fd, cmd, data, error); -+ else -+ return -1; -+} -+ -+static const char * -+fw_error_to_str(int code) -+{ -+ if (csv_guest.fw_error_to_str) -+ return csv_guest.fw_error_to_str(code); -+ else -+ return NULL; -+} -+ -+static int -+csv_launch_encrypt_data(uint64_t gpa, uint8_t *addr, uint64_t len) -+{ -+ int ret, fw_error; -+ struct kvm_csv_launch_encrypt_data update; -+ -+ if (!addr || !len) { -+ return 1; -+ } -+ -+ update.gpa = (__u64)gpa; -+ update.uaddr = (__u64)(unsigned long)addr; -+ update.len = len; -+ trace_kvm_csv_launch_encrypt_data(gpa, addr, len); -+ ret = csv_ioctl(KVM_CSV_LAUNCH_ENCRYPT_DATA, &update, &fw_error); -+ if (ret) { -+ error_report("%s: CSV LAUNCH_ENCRYPT_DATA ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ } -+ -+ return ret; -+} -+ -+int -+csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) -+{ -+ int ret = 0; -+ -+ if (!csv_enabled()) { -+ error_setg(errp, "%s: CSV is not enabled", __func__); -+ return -1; -+ } -+ -+ /* if CSV is in update state then load the data to secure memory */ -+ if (csv_check_state(SEV_STATE_LAUNCH_UPDATE)) { -+ ret = csv_launch_encrypt_data(gpa, ptr, len); -+ if (ret) -+ error_setg(errp, "%s: CSV fail to encrypt data", __func__); -+ } -+ -+ return ret; -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 886dbb2613..6f7b112d96 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -35,4 +35,6 @@ typedef struct CsvGuestState CsvGuestState; - extern struct CsvGuestState csv_guest; - extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); - -+int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); -+ - #endif -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 2cd8726eeb..b7da9bd748 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -11,3 +11,6 @@ kvm_sev_launch_measurement(const char *value) "data %s" - kvm_sev_launch_finish(void) "" - kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d" - kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s" -+ -+# csv.c -+kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 --- -2.17.1 - diff --git a/0004-Add-target-loongarch64.patch b/0004-Add-target-loongarch64.patch deleted file mode 100644 index bca350b4ae0f20a2cad45cb7f3ce508aacad6ecd..0000000000000000000000000000000000000000 --- a/0004-Add-target-loongarch64.patch +++ /dev/null @@ -1,15917 +0,0 @@ -From 73e64c37b5d0f8a12bad7562c4d442f95ee361b8 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:44:33 -0400 -Subject: [PATCH 04/28] Add target/loongarch64. - -Change-Id: Idd3ed114968c4a1f1be5fe19dc279028775eb89d -Signed-off-by: lixianglai ---- - target/Kconfig | 1 + - target/loongarch64/Kconfig | 2 + - target/loongarch64/arch_dump.c | 174 ++ - target/loongarch64/cpu-csr.h | 869 ++++++++ - target/loongarch64/cpu-param.h | 30 + - target/loongarch64/cpu-qom.h | 54 + - target/loongarch64/cpu.c | 576 +++++ - target/loongarch64/cpu.h | 326 +++ - target/loongarch64/csr_helper.c | 704 ++++++ - target/loongarch64/fpu.c | 28 + - target/loongarch64/fpu_helper.c | 952 ++++++++ - target/loongarch64/fpu_helper.h | 129 ++ - target/loongarch64/gdbstub.c | 109 + - target/loongarch64/helper.c | 727 +++++++ - target/loongarch64/helper.h | 168 ++ - target/loongarch64/insn.decode | 514 +++++ - target/loongarch64/instmap.h | 216 ++ - target/loongarch64/internal.h | 184 ++ - target/loongarch64/kvm.c | 1622 ++++++++++++++ - target/loongarch64/kvm_larch.h | 41 + - target/loongarch64/larch-defs.h | 27 + - target/loongarch64/machine.c | 416 ++++ - target/loongarch64/meson.build | 35 + - target/loongarch64/op_helper.c | 533 +++++ - target/loongarch64/stabletimer.c | 122 ++ - target/loongarch64/tlb_helper.c | 729 +++++++ - target/loongarch64/trace-events | 3 + - target/loongarch64/trans.inc.c | 3472 ++++++++++++++++++++++++++++++ - target/loongarch64/translate.c | 2892 +++++++++++++++++++++++++ - target/meson.build | 1 + - 30 files changed, 15656 insertions(+) - create mode 100644 target/loongarch64/Kconfig - create mode 100644 target/loongarch64/arch_dump.c - create mode 100644 target/loongarch64/cpu-csr.h - create mode 100644 target/loongarch64/cpu-param.h - create mode 100644 target/loongarch64/cpu-qom.h - create mode 100644 target/loongarch64/cpu.c - create mode 100644 target/loongarch64/cpu.h - create mode 100644 target/loongarch64/csr_helper.c - create mode 100644 target/loongarch64/fpu.c - create mode 100644 target/loongarch64/fpu_helper.c - create mode 100644 target/loongarch64/fpu_helper.h - create mode 100644 target/loongarch64/gdbstub.c - create mode 100644 target/loongarch64/helper.c - create mode 100644 target/loongarch64/helper.h - create mode 100644 target/loongarch64/insn.decode - create mode 100644 target/loongarch64/instmap.h - create mode 100644 target/loongarch64/internal.h - create mode 100644 target/loongarch64/kvm.c - create mode 100644 target/loongarch64/kvm_larch.h - create mode 100644 target/loongarch64/larch-defs.h - create mode 100644 target/loongarch64/machine.c - create mode 100644 target/loongarch64/meson.build - create mode 100644 target/loongarch64/op_helper.c - create mode 100644 target/loongarch64/stabletimer.c - create mode 100644 target/loongarch64/tlb_helper.c - create mode 100644 target/loongarch64/trace-events - create mode 100644 target/loongarch64/trans.inc.c - create mode 100644 target/loongarch64/translate.c - -diff --git a/target/Kconfig b/target/Kconfig -index ae7f24fc6..50b46d048 100644 ---- a/target/Kconfig -+++ b/target/Kconfig -@@ -4,6 +4,7 @@ source avr/Kconfig - source cris/Kconfig - source hppa/Kconfig - source i386/Kconfig -+source loongarch64/Kconfig - source m68k/Kconfig - source microblaze/Kconfig - source mips/Kconfig -diff --git a/target/loongarch64/Kconfig b/target/loongarch64/Kconfig -new file mode 100644 -index 000000000..46b26b1a8 ---- /dev/null -+++ b/target/loongarch64/Kconfig -@@ -0,0 +1,2 @@ -+config LOONGARCH64 -+ bool -diff --git a/target/loongarch64/arch_dump.c b/target/loongarch64/arch_dump.c -new file mode 100644 -index 000000000..7b8708fdf ---- /dev/null -+++ b/target/loongarch64/arch_dump.c -@@ -0,0 +1,174 @@ -+/* Support for writing ELF notes for RM architectures -+ * -+ * Copyright (C) 2015 Red Hat Inc. -+ * -+ * Author: Andrew Jones -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "cpu.h" -+#include "elf.h" -+#include "sysemu/dump.h" -+#include "internal.h" -+ -+/* struct user_pt_regs from arch/loongarch/include/uapi/asm/ptrace.h */ -+struct loongarch_user_regs { -+ uint64_t gpr[32]; -+ uint64_t lo; -+ uint64_t hi; -+ uint64_t csr_era; -+ uint64_t csr_badvaddr; -+ uint64_t csr_crmd; -+ uint64_t csr_ecfg; -+ uint64_t pad[7]; -+} QEMU_PACKED; -+ -+QEMU_BUILD_BUG_ON(sizeof(struct loongarch_user_regs) != 360); -+ -+/* struct elf_prstatus from include/uapi/linux/elfcore.h */ -+struct loongarch_elf_prstatus { -+ char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */ -+ uint32_t pr_pid; -+ char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) - -+ offsetof(struct elf_prstatus, pr_ppid) */ -+ struct loongarch_user_regs pr_reg; -+ uint32_t pr_fpvalid; -+ char pad3[4]; -+} QEMU_PACKED; -+ -+QEMU_BUILD_BUG_ON(sizeof(struct loongarch_elf_prstatus) != 480); -+ -+/* struct user_fpsimd_state from arch/arm64/include/uapi/asm/ptrace.h -+ * -+ * While the vregs member of user_fpsimd_state is of type __uint128_t, -+ * QEMU uses an array of uint64_t, where the high half of the 128-bit -+ * value is always in the 2n+1'th index. Thus we also break the 128- -+ * bit values into two halves in this reproduction of user_fpsimd_state. -+ */ -+ -+struct loongarch_fpu_struct { -+ uint64_t fpr[32]; -+ unsigned int fir; -+ unsigned int fcsr; -+} QEMU_PACKED; -+ -+QEMU_BUILD_BUG_ON(sizeof(struct loongarch_fpu_struct) != 264); -+ -+struct loongarch_note { -+ Elf64_Nhdr hdr; -+ char name[8]; /* align_up(sizeof("CORE"), 4) */ -+ union { -+ struct loongarch_elf_prstatus prstatus; -+ struct loongarch_fpu_struct fpu; -+ }; -+} QEMU_PACKED; -+ -+#define LOONGARCH_NOTE_HEADER_SIZE offsetof(struct loongarch_note, prstatus) -+#define LOONGARCH_PRSTATUS_NOTE_SIZE (LOONGARCH_NOTE_HEADER_SIZE + \ -+ sizeof(struct loongarch_elf_prstatus)) -+#define LOONGARCH_PRFPREG_NOTE_SIZE (LOONGARCH_NOTE_HEADER_SIZE + \ -+ sizeof(struct loongarch_fpu_struct)) -+ -+static void loongarch_note_init(struct loongarch_note *note, DumpState *s, -+ const char *name, Elf64_Word namesz, -+ Elf64_Word type, Elf64_Word descsz) -+{ -+ memset(note, 0, sizeof(*note)); -+ -+ note->hdr.n_namesz = cpu_to_dump32(s, namesz); -+ note->hdr.n_descsz = cpu_to_dump32(s, descsz); -+ note->hdr.n_type = cpu_to_dump32(s, type); -+ -+ memcpy(note->name, name, namesz); -+} -+ -+static int loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f, -+ CPULOONGARCHState *env, int cpuid, -+ DumpState *s) -+{ -+ struct loongarch_note note; -+ int ret, i; -+ -+ loongarch_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.fpu)); -+ -+ note.fpu.fcsr = cpu_to_dump64(s, env->active_fpu.fcsr0); -+ -+ for (i = 0; i < 32; ++i) { -+ note.fpu.fpr[i] = cpu_to_dump64(s, env->active_fpu.fpr[i].fd); -+ } -+ -+ ret = f(¬e, LOONGARCH_PRFPREG_NOTE_SIZE, s); -+ if (ret < 0) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, -+ int cpuid, DumpState *s) -+{ -+ struct loongarch_note note; -+ CPULOONGARCHState *env = &LOONGARCH_CPU(cs)->env; -+ int ret, i; -+ -+ loongarch_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus)); -+ -+ note.prstatus.pr_pid = cpu_to_dump32(s, cpuid); -+ note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1); -+ -+ for (i = 0; i < 32; ++i) { -+ note.prstatus.pr_reg.gpr[i] = cpu_to_dump64(s, env->active_tc.gpr[i]); -+ } -+ note.prstatus.pr_reg.csr_era = cpu_to_dump64(s, env->CSR_ERA); -+ note.prstatus.pr_reg.csr_badvaddr = cpu_to_dump64(s, env->CSR_BADV); -+ note.prstatus.pr_reg.csr_crmd = cpu_to_dump64(s, env->CSR_CRMD); -+ note.prstatus.pr_reg.csr_ecfg = cpu_to_dump64(s, env->CSR_ECFG); -+ -+ ret = f(¬e, LOONGARCH_PRSTATUS_NOTE_SIZE, s); -+ if (ret < 0) { -+ return -1; -+ } -+ -+ ret = loongarch_write_elf64_fprpreg(f, env, cpuid, s); -+ if (ret < 0) { -+ return -1; -+ } -+ -+ return ret; -+} -+ -+int cpu_get_dump_info(ArchDumpInfo *info, -+ const GuestPhysBlockList *guest_phys_blocks) -+{ -+ info->d_machine = EM_LOONGARCH; -+ info->d_endian = ELFDATA2LSB; -+ info->d_class = ELFCLASS64; -+ -+ return 0; -+} -+ -+ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) -+{ -+ size_t note_size = 0; -+ -+ if (class == ELFCLASS64) { -+ note_size = LOONGARCH_PRSTATUS_NOTE_SIZE + LOONGARCH_PRFPREG_NOTE_SIZE; -+ } -+ -+ return note_size * nr_cpus; -+} -+ -diff --git a/target/loongarch64/cpu-csr.h b/target/loongarch64/cpu-csr.h -new file mode 100644 -index 000000000..e549bb46b ---- /dev/null -+++ b/target/loongarch64/cpu-csr.h -@@ -0,0 +1,869 @@ -+#ifndef _CPU_CSR_H_ -+#define _CPU_CSR_H_ -+ -+/* basic CSR register */ -+#define LOONGARCH_CSR_CRMD 0x0 /* 32 current mode info */ -+#define CSR_CRMD_DACM_SHIFT 7 -+#define CSR_CRMD_DACM_WIDTH 2 -+#define CSR_CRMD_DACM (0x3UL << CSR_CRMD_DACM_SHIFT) -+#define CSR_CRMD_DACF_SHIFT 5 -+#define CSR_CRMD_DACF_WIDTH 2 -+#define CSR_CRMD_DACF (0x3UL << CSR_CRMD_DACF_SHIFT) -+#define CSR_CRMD_PG_SHIFT 4 -+#define CSR_CRMD_PG (0x1UL << CSR_CRMD_PG_SHIFT) -+#define CSR_CRMD_DA_SHIFT 3 -+#define CSR_CRMD_DA (0x1UL << CSR_CRMD_DA_SHIFT) -+#define CSR_CRMD_IE_SHIFT 2 -+#define CSR_CRMD_IE (0x1UL << CSR_CRMD_IE_SHIFT) -+#define CSR_CRMD_PLV_SHIFT 0 -+#define CSR_CRMD_PLV_WIDTH 2 -+#define CSR_CRMD_PLV (0x3UL << CSR_CRMD_PLV_SHIFT) -+ -+#define PLV_USER 3 -+#define PLV_KERN 0 -+#define PLV_MASK 0x3 -+ -+#define LOONGARCH_CSR_PRMD 0x1 /* 32 prev-exception mode info */ -+#define CSR_PRMD_PIE_SHIFT 2 -+#define CSR_PRMD_PIE (0x1UL << CSR_PRMD_PIE_SHIFT) -+#define CSR_PRMD_PPLV_SHIFT 0 -+#define CSR_PRMD_PPLV_WIDTH 2 -+#define CSR_PRMD_PPLV (0x3UL << CSR_PRMD_PPLV_SHIFT) -+ -+#define LOONGARCH_CSR_EUEN 0x2 /* 32 coprocessor enable */ -+#define CSR_EUEN_LBTEN_SHIFT 3 -+#define CSR_EUEN_LBTEN (0x1UL << CSR_EUEN_LBTEN_SHIFT) -+#define CSR_EUEN_LASXEN_SHIFT 2 -+#define CSR_EUEN_LASXEN (0x1UL << CSR_EUEN_LASXEN_SHIFT) -+#define CSR_EUEN_LSXEN_SHIFT 1 -+#define CSR_EUEN_LSXEN (0x1UL << CSR_EUEN_LSXEN_SHIFT) -+#define CSR_EUEN_FPEN_SHIFT 0 -+#define CSR_EUEN_FPEN (0x1UL << CSR_EUEN_FPEN_SHIFT) -+ -+#define LOONGARCH_CSR_MISC 0x3 /* 32 misc config */ -+ -+#define LOONGARCH_CSR_ECFG 0x4 /* 32 exception config */ -+#define CSR_ECFG_VS_SHIFT 16 -+#define CSR_ECFG_VS_WIDTH 3 -+#define CSR_ECFG_VS (0x7UL << CSR_ECFG_VS_SHIFT) -+#define CSR_ECFG_IM_SHIFT 0 -+#define CSR_ECFG_IM_WIDTH 13 -+#define CSR_ECFG_IM (0x1fffUL << CSR_ECFG_IM_SHIFT) -+ -+#define CSR_ECFG_IPMASK 0x00001fff -+ -+#define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ -+#define CSR_ESTAT_ESUBCODE_SHIFT 22 -+#define CSR_ESTAT_ESUBCODE_WIDTH 9 -+#define CSR_ESTAT_ESUBCODE (0x1ffULL << CSR_ESTAT_ESUBCODE_SHIFT) -+#define CSR_ESTAT_EXC_SH 16 -+#define CSR_ESTAT_EXC_WIDTH 5 -+#define CSR_ESTAT_EXC (0x1fULL << CSR_ESTAT_EXC_SH) -+#define CSR_ESTAT_IS_SHIFT 0 -+#define CSR_ESTAT_IS_WIDTH 15 -+#define CSR_ESTAT_IS (0x7fffULL << CSR_ESTAT_IS_SHIFT) -+ -+#define CSR_ESTAT_IPMASK 0x00001fff -+ -+#define EXCODE_IP 64 -+#define EXCCODE_RSV 0 -+#define EXCCODE_TLBL 1 -+#define EXCCODE_TLBS 2 -+#define EXCCODE_TLBI 3 -+#define EXCCODE_MOD 4 -+#define EXCCODE_TLBRI 5 -+#define EXCCODE_TLBXI 6 -+#define EXCCODE_TLBPE 7 -+#define EXCCODE_ADE 8 -+#define EXCCODE_UNALIGN 9 -+#define EXCCODE_OOB 10 -+#define EXCCODE_SYS 11 -+#define EXCCODE_BP 12 -+#define EXCCODE_RI 13 -+#define EXCCODE_IPE 14 -+#define EXCCODE_FPDIS 15 -+#define EXCCODE_LSXDIS 16 -+#define EXCCODE_LASXDIS 17 -+#define EXCCODE_FPE 18 -+#define EXCCODE_WATCH 19 -+#define EXCCODE_BTDIS 20 -+#define EXCCODE_BTE 21 -+#define EXCCODE_PSI 22 -+#define EXCCODE_HYP 23 -+#define EXCCODE_FC 24 -+#define EXCCODE_SE 25 -+ -+#define LOONGARCH_CSR_ERA 0x6 /* 64 error PC */ -+ -+#define LOONGARCH_CSR_BADV 0x7 /* 64 bad virtual address */ -+ -+#define LOONGARCH_CSR_BADI 0x8 /* 32 bad instruction */ -+ -+#define LOONGARCH_CSR_EEPN 0xc /* 64 exception enter base address */ -+#define LOONGARCH_EEPN_CPUID (0x3ffULL << 0) -+ -+#define CU_FPE 1 -+#define CU_LSXE (1 << 1) -+#define CU_LASXE (1 << 2) -+#define CU_LBTE (1 << 3) -+ -+/* TLB related CSR register : start with TLB if no pagewalk */ -+/* 32 TLB Index, EHINV, PageSize, is_gtlb */ -+#define LOONGARCH_CSR_TLBIDX 0x10 -+#define CSR_TLBIDX_EHINV_SHIFT 31 -+#define CSR_TLBIDX_EHINV (0x1ULL << CSR_TLBIDX_EHINV_SHIFT) -+#define CSR_TLBIDX_PS_SHIFT 24 -+#define CSR_TLBIDX_PS_WIDTH 6 -+#define CSR_TLBIDX_PS (0x3fULL << CSR_TLBIDX_PS_SHIFT) -+#define CSR_TLBIDX_IDX_SHIFT 0 -+#define CSR_TLBIDX_IDX_WIDTH 12 -+#define CSR_TLBIDX_IDX (0xfffULL << CSR_TLBIDX_IDX_SHIFT) -+#define CSR_TLBIDX_SIZEM 0x3f000000 -+#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT -+#define CSR_TLBIDX_IDXM 0xfff -+ -+#define LOONGARCH_CSR_TLBEHI 0x11 /* 64 TLB EntryHi without ASID */ -+ -+#define LOONGARCH_CSR_TLBELO0 0x12 /* 64 TLB EntryLo0 */ -+#define CSR_TLBLO0_RPLV_SHIFT 63 -+#define CSR_TLBLO0_RPLV (0x1ULL << CSR_TLBLO0_RPLV_SHIFT) -+#define CSR_TLBLO0_XI_SHIFT 62 -+#define CSR_TLBLO0_XI (0x1ULL << CSR_TLBLO0_XI_SHIFT) -+#define CSR_TLBLO0_RI_SHIFT 61 -+#define CSR_TLBLO0_RI (0x1ULL << CSR_TLBLO0_RI_SHIFT) -+#define CSR_TLBLO0_PPN_SHIFT 12 -+#define CSR_TLBLO0_PPN_WIDTH 36 /* ignore lower 12bits */ -+#define CSR_TLBLO0_PPN (0xfffffffffULL << CSR_TLBLO0_PPN_SHIFT) -+#define CSR_TLBLO0_GLOBAL_SHIFT 6 -+#define CSR_TLBLO0_GLOBAL (0x1ULL << CSR_TLBLO0_GLOBAL_SHIFT) -+#define CSR_TLBLO0_CCA_SHIFT 4 -+#define CSR_TLBLO0_CCA_WIDTH 2 -+#define CSR_TLBLO0_CCA (0x3ULL << CSR_TLBLO0_CCA_SHIFT) -+#define CSR_TLBLO0_PLV_SHIFT 2 -+#define CSR_TLBLO0_PLV_WIDTH 2 -+#define CSR_TLBLO0_PLV (0x3ULL << CSR_TLBLO0_PLV_SHIFT) -+#define CSR_TLBLO0_WE_SHIFT 1 -+#define CSR_TLBLO0_WE (0x1ULL << CSR_TLBLO0_WE_SHIFT) -+#define CSR_TLBLO0_V_SHIFT 0 -+#define CSR_TLBLO0_V (0x1ULL << CSR_TLBLO0_V_SHIFT) -+ -+#define LOONGARCH_CSR_TLBELO1 0x13 /* 64 TLB EntryLo1 */ -+#define CSR_TLBLO1_RPLV_SHIFT 63 -+#define CSR_TLBLO1_RPLV (0x1ULL << CSR_TLBLO1_RPLV_SHIFT) -+#define CSR_TLBLO1_XI_SHIFT 62 -+#define CSR_TLBLO1_XI (0x1ULL << CSR_TLBLO1_XI_SHIFT) -+#define CSR_TLBLO1_RI_SHIFT 61 -+#define CSR_TLBLO1_RI (0x1ULL << CSR_TLBLO1_RI_SHIFT) -+#define CSR_TLBLO1_PPN_SHIFT 12 -+#define CSR_TLBLO1_PPN_WIDTH 36 /* ignore lower 12bits */ -+#define CSR_TLBLO1_PPN (0xfffffffffULL << CSR_TLBLO1_PPN_SHIFT) -+#define CSR_TLBLO1_GLOBAL_SHIFT 6 -+#define CSR_TLBLO1_GLOBAL (0x1ULL << CSR_TLBLO1_GLOBAL_SHIFT) -+#define CSR_TLBLO1_CCA_SHIFT 4 -+#define CSR_TLBLO1_CCA_WIDTH 2 -+#define CSR_TLBLO1_CCA (0x3ULL << CSR_TLBLO1_CCA_SHIFT) -+#define CSR_TLBLO1_PLV_SHIFT 2 -+#define CSR_TLBLO1_PLV_WIDTH 2 -+#define CSR_TLBLO1_PLV (0x3ULL << CSR_TLBLO1_PLV_SHIFT) -+#define CSR_TLBLO1_WE_SHIFT 1 -+#define CSR_TLBLO1_WE (0x1ULL << CSR_TLBLO1_WE_SHIFT) -+#define CSR_TLBLO1_V_SHIFT 0 -+#define CSR_TLBLO1_V (0x1ULL << CSR_TLBLO1_V_SHIFT) -+ -+#define LOONGARCH_ENTRYLO_RI (1ULL << 61) -+#define LOONGARCH_ENTRYLO_XI (1ULL << 62) -+ -+#define LOONGARCH_CSR_TLBWIRED 0x14 /* 32 TLB wired */ -+#define LOONGARCH_CSR_GTLBC 0x15 /* guest-related TLB */ -+#define CSR_GTLBC_RID_SHIFT 16 -+#define CSR_GTLBC_RID_WIDTH 8 -+#define CSR_GTLBC_RID (0xffULL << CSR_GTLBC_RID_SHIFT) -+#define CSR_GTLBC_TOTI_SHIFT 13 -+#define CSR_GTLBC_TOTI (0x1ULL << CSR_GTLBC_TOTI_SHIFT) -+#define CSR_GTLBC_USERID_SHIFT 12 -+#define CSR_GTLBC_USERID (0x1ULL << CSR_GTLBC_USERID_SHIFT) -+#define CSR_GTLBC_GMTLBSZ_SHIFT 0 -+#define CSR_GTLBC_GMTLBSZ_WIDTH 6 -+#define CSR_GTLBC_GMTLBSZ (0x3fULL << CSR_GTLBC_GVTLBSZ_SHIFT) -+ -+#define LOONGARCH_CSR_TRGP 0x16 /* guest-related TLB */ -+#define CSR_TRGP_RID_SHIFT 16 -+#define CSR_TRGP_RID_WIDTH 8 -+#define CSR_TRGP_RID (0xffULL << CSR_TRGP_RID_SHIFT) -+#define CSR_TRGP_GTLB_SHIFT 0 -+#define CSR_TRGP_GTLB (1 << CSR_TRGP_GTLB_SHIFT) -+ -+#define LOONGARCH_CSR_ASID 0x18 /* 64 ASID */ -+#define CSR_ASID_BIT_SHIFT 16 /* ASIDBits */ -+#define CSR_ASID_BIT_WIDTH 8 -+#define CSR_ASID_BIT (0xffULL << CSR_ASID_BIT_SHIFT) -+#define CSR_ASID_ASID_SHIFT 0 -+#define CSR_ASID_ASID_WIDTH 10 -+#define CSR_ASID_ASID (0x3ffULL << CSR_ASID_ASID_SHIFT) -+ -+/* 64 page table base address when badv[47] = 0 */ -+#define LOONGARCH_CSR_PGDL 0x19 -+/* 64 page table base address when badv[47] = 1 */ -+#define LOONGARCH_CSR_PGDH 0x1a -+ -+#define LOONGARCH_CSR_PGD 0x1b /* 64 page table base */ -+ -+#define LOONGARCH_CSR_PWCTL0 0x1c /* 64 PWCtl0 */ -+#define CSR_PWCTL0_PTEW_SHIFT 30 -+#define CSR_PWCTL0_PTEW_WIDTH 2 -+#define CSR_PWCTL0_PTEW (0x3ULL << CSR_PWCTL0_PTEW_SHIFT) -+#define CSR_PWCTL0_DIR1WIDTH_SHIFT 25 -+#define CSR_PWCTL0_DIR1WIDTH_WIDTH 5 -+#define CSR_PWCTL0_DIR1WIDTH (0x1fULL << CSR_PWCTL0_DIR1WIDTH_SHIFT) -+#define CSR_PWCTL0_DIR1BASE_SHIFT 20 -+#define CSR_PWCTL0_DIR1BASE_WIDTH 5 -+#define CSR_PWCTL0_DIR1BASE (0x1fULL << CSR_PWCTL0_DIR1BASE_SHIFT) -+#define CSR_PWCTL0_DIR0WIDTH_SHIFT 15 -+#define CSR_PWCTL0_DIR0WIDTH_WIDTH 5 -+#define CSR_PWCTL0_DIR0WIDTH (0x1fULL << CSR_PWCTL0_DIR0WIDTH_SHIFT) -+#define CSR_PWCTL0_DIR0BASE_SHIFT 10 -+#define CSR_PWCTL0_DIR0BASE_WIDTH 5 -+#define CSR_PWCTL0_DIR0BASE (0x1fULL << CSR_PWCTL0_DIR0BASE_SHIFT) -+#define CSR_PWCTL0_PTWIDTH_SHIFT 5 -+#define CSR_PWCTL0_PTWIDTH_WIDTH 5 -+#define CSR_PWCTL0_PTWIDTH (0x1fULL << CSR_PWCTL0_PTWIDTH_SHIFT) -+#define CSR_PWCTL0_PTBASE_SHIFT 0 -+#define CSR_PWCTL0_PTBASE_WIDTH 5 -+#define CSR_PWCTL0_PTBASE (0x1fULL << CSR_PWCTL0_PTBASE_SHIFT) -+ -+#define LOONGARCH_CSR_PWCTL1 0x1d /* 64 PWCtl1 */ -+#define CSR_PWCTL1_DIR3WIDTH_SHIFT 18 -+#define CSR_PWCTL1_DIR3WIDTH_WIDTH 5 -+#define CSR_PWCTL1_DIR3WIDTH (0x1fULL << CSR_PWCTL1_DIR3WIDTH_SHIFT) -+#define CSR_PWCTL1_DIR3BASE_SHIFT 12 -+#define CSR_PWCTL1_DIR3BASE_WIDTH 5 -+#define CSR_PWCTL1_DIR3BASE (0x1fULL << CSR_PWCTL0_DIR3BASE_SHIFT) -+#define CSR_PWCTL1_DIR2WIDTH_SHIFT 6 -+#define CSR_PWCTL1_DIR2WIDTH_WIDTH 5 -+#define CSR_PWCTL1_DIR2WIDTH (0x1fULL << CSR_PWCTL1_DIR2WIDTH_SHIFT) -+#define CSR_PWCTL1_DIR2BASE_SHIFT 0 -+#define CSR_PWCTL1_DIR2BASE_WIDTH 5 -+#define CSR_PWCTL1_DIR2BASE (0x1fULL << CSR_PWCTL0_DIR2BASE_SHIFT) -+ -+#define LOONGARCH_CSR_STLBPGSIZE 0x1e /* 64 */ -+#define CSR_STLBPGSIZE_PS_WIDTH 6 -+#define CSR_STLBPGSIZE_PS (0x3f) -+ -+#define LOONGARCH_CSR_RVACFG 0x1f -+#define CSR_RVACFG_RDVA_WIDTH 4 -+#define CSR_RVACFG_RDVA (0xf) -+ -+/* read only CSR register : start with CPU */ -+#define LOONGARCH_CSR_CPUID 0x20 /* 32 CPU core number */ -+#define CSR_CPUID_CID_WIDTH 9 -+#define CSR_CPUID_CID (0x1ff) -+ -+#define LOONGARCH_CSR_PRCFG1 0x21 /* 32 CPU info */ -+#define CSR_CONF1_VSMAX_SHIFT 12 -+#define CSR_CONF1_VSMAX_WIDTH 3 -+#define CSR_CONF1_VSMAX (7ULL << CSR_CONF1_VSMAX_SHIFT) -+/* stable timer bits - 1, 0x2f = 47*/ -+#define CSR_CONF1_TMRBITS_SHIFT 4 -+#define CSR_CONF1_TMRBITS_WIDTH 8 -+#define CSR_CONF1_TMRBITS (0xffULL << CSR_CONF1_TMRBITS_SHIFT) -+#define CSR_CONF1_KSNUM_SHIFT 0 -+#define CSR_CONF1_KSNUM_WIDTH 4 -+#define CSR_CONF1_KSNUM (0x8) -+ -+#define LOONGARCH_CSR_PRCFG2 0x22 -+#define CSR_CONF2_PGMASK_SUPP 0x3ffff000 -+ -+#define LOONGARCH_CSR_PRCFG3 0x23 -+#define CSR_CONF3_STLBIDX_SHIFT 20 -+#define CSR_CONF3_STLBIDX_WIDTH 6 -+#define CSR_CONF3_STLBIDX (0x3fULL << CSR_CONF3_STLBIDX_SHIFT) -+#define CSR_STLB_SETS 256 -+#define CSR_CONF3_STLBWAYS_SHIFT 12 -+#define CSR_CONF3_STLBWAYS_WIDTH 8 -+#define CSR_CONF3_STLBWAYS (0xffULL << CSR_CONF3_STLBWAYS_SHIFT) -+#define CSR_STLBWAYS_SIZE 8 -+#define CSR_CONF3_MTLBSIZE_SHIFT 4 -+#define CSR_CONF3_MTLBSIZE_WIDTH 8 -+#define CSR_CONF3_MTLBSIZE (0xffULL << CSR_CONF3_MTLBSIZE_SHIFT) -+/* mean VTLB 64 index */ -+#define CSR_MTLB_SIZE 64 -+#define CSR_CONF3_TLBORG_SHIFT 0 -+#define CSR_CONF3_TLBORG_WIDTH 4 -+#define CSR_CONF3_TLBORG (0xfULL << CSR_CONF3_TLBORG_SHIFT) -+/* mean use MTLB+STLB */ -+#define TLB_ORG 2 -+ -+/* Kscratch : start with KS */ -+#define LOONGARCH_CSR_KS0 0x30 /* 64 */ -+#define LOONGARCH_CSR_KS1 0x31 /* 64 */ -+#define LOONGARCH_CSR_KS2 0x32 /* 64 */ -+#define LOONGARCH_CSR_KS3 0x33 /* 64 */ -+#define LOONGARCH_CSR_KS4 0x34 /* 64 */ -+#define LOONGARCH_CSR_KS5 0x35 /* 64 */ -+#define LOONGARCH_CSR_KS6 0x36 /* 64 */ -+#define LOONGARCH_CSR_KS7 0x37 /* 64 */ -+#define LOONGARCH_CSR_KS8 0x38 /* 64 */ -+ -+/* timer : start with TM */ -+#define LOONGARCH_CSR_TMID 0x40 /* 32 timer ID */ -+ -+#define LOONGARCH_CSR_TCFG 0x41 /* 64 timer config */ -+#define CSR_TCFG_VAL_SHIFT 2 -+#define CSR_TCFG_VAL_WIDTH 48 -+#define CSR_TCFG_VAL (0x3fffffffffffULL << CSR_TCFG_VAL_SHIFT) -+#define CSR_TCFG_PERIOD_SHIFT 1 -+#define CSR_TCFG_PERIOD (0x1ULL << CSR_TCFG_PERIOD_SHIFT) -+#define CSR_TCFG_EN (0x1) -+ -+#define LOONGARCH_CSR_TVAL 0x42 /* 64 timer ticks remain */ -+ -+#define LOONGARCH_CSR_CNTC 0x43 /* 64 timer offset */ -+ -+#define LOONGARCH_CSR_TINTCLR 0x44 /* 64 timer interrupt clear */ -+#define CSR_TINTCLR_TI_SHIFT 0 -+#define CSR_TINTCLR_TI (1 << CSR_TINTCLR_TI_SHIFT) -+ -+/* guest : start with GST */ -+#define LOONGARCH_CSR_GSTAT 0x50 /* 32 basic guest info */ -+#define CSR_GSTAT_GID_SHIFT 16 -+#define CSR_GSTAT_GID_WIDTH 8 -+#define CSR_GSTAT_GID (0xffULL << CSR_GSTAT_GID_SHIFT) -+#define CSR_GSTAT_GIDBIT_SHIFT 4 -+#define CSR_GSTAT_GIDBIT_WIDTH 6 -+#define CSR_GSTAT_GIDBIT (0x3fULL << CSR_GSTAT_GIDBIT_SHIFT) -+#define CSR_GSTAT_PVM_SHIFT 1 -+#define CSR_GSTAT_PVM (0x1ULL << CSR_GSTAT_PVM_SHIFT) -+#define CSR_GSTAT_VM_SHIFT 0 -+#define CSR_GSTAT_VM (0x1ULL << CSR_GSTAT_VM_SHIFT) -+ -+#define LOONGARCH_CSR_GCFG 0x51 /* 32 guest config */ -+#define CSR_GCFG_GPERF_SHIFT 24 -+#define CSR_GCFG_GPERF_WIDTH 3 -+#define CSR_GCFG_GPERF (0x7ULL << CSR_GCFG_GPERF_SHIFT) -+#define CSR_GCFG_GCI_SHIFT 20 -+#define CSR_GCFG_GCI_WIDTH 2 -+#define CSR_GCFG_GCI (0x3ULL << CSR_GCFG_GCI_SHIFT) -+#define CSR_GCFG_GCI_ALL (0x0ULL << CSR_GCFG_GCI_SHIFT) -+#define CSR_GCFG_GCI_HIT (0x1ULL << CSR_GCFG_GCI_SHIFT) -+#define CSR_GCFG_GCI_SECURE (0x2ULL << CSR_GCFG_GCI_SHIFT) -+#define CSR_GCFG_GCIP_SHIFT 16 -+#define CSR_GCFG_GCIP (0xfULL << CSR_GCFG_GCIP_SHIFT) -+#define CSR_GCFG_GCIP_ALL (0x1ULL << CSR_GCFG_GCIP_SHIFT) -+#define CSR_GCFG_GCIP_HIT (0x1ULL << (CSR_GCFG_GCIP_SHIFT + 1)) -+#define CSR_GCFG_GCIP_SECURE (0x1ULL << (CSR_GCFG_GCIP_SHIFT + 2)) -+#define CSR_GCFG_TORU_SHIFT 15 -+#define CSR_GCFG_TORU (0x1ULL << CSR_GCFG_TORU_SHIFT) -+#define CSR_GCFG_TORUP_SHIFT 14 -+#define CSR_GCFG_TORUP (0x1ULL << CSR_GCFG_TORUP_SHIFT) -+#define CSR_GCFG_TOP_SHIFT 13 -+#define CSR_GCFG_TOP (0x1ULL << CSR_GCFG_TOP_SHIFT) -+#define CSR_GCFG_TOPP_SHIFT 12 -+#define CSR_GCFG_TOPP (0x1ULL << CSR_GCFG_TOPP_SHIFT) -+#define CSR_GCFG_TOE_SHIFT 11 -+#define CSR_GCFG_TOE (0x1ULL << CSR_GCFG_TOE_SHIFT) -+#define CSR_GCFG_TOEP_SHIFT 10 -+#define CSR_GCFG_TOEP (0x1ULL << CSR_GCFG_TOEP_SHIFT) -+#define CSR_GCFG_TIT_SHIFT 9 -+#define CSR_GCFG_TIT (0x1ULL << CSR_GCFG_TIT_SHIFT) -+#define CSR_GCFG_TITP_SHIFT 8 -+#define CSR_GCFG_TITP (0x1ULL << CSR_GCFG_TITP_SHIFT) -+#define CSR_GCFG_SIT_SHIFT 7 -+#define CSR_GCFG_SIT (0x1ULL << CSR_GCFG_SIT_SHIFT) -+#define CSR_GCFG_SITP_SHIFT 6 -+#define CSR_GCFG_SITP (0x1ULL << CSR_GCFG_SITP_SHIFT) -+#define CSR_GCFG_CACTRL_SHIFT 4 -+#define CSR_GCFG_CACTRL_WIDTH 2 -+#define CSR_GCFG_CACTRL (0x3ULL << CSR_GCFG_CACTRL_SHIFT) -+#define CSR_GCFG_CACTRL_GUEST (0x0ULL << CSR_GCFG_CACTRL_SHIFT) -+#define CSR_GCFG_CACTRL_ROOT (0x1ULL << CSR_GCFG_CACTRL_SHIFT) -+#define CSR_GCFG_CACTRL_NEST (0x2ULL << CSR_GCFG_CACTRL_SHIFT) -+#define CSR_GCFG_CCCP_WIDTH 4 -+#define CSR_GCFG_CCCP (0xf) -+#define CSR_GCFG_CCCP_GUEST (0x1ULL << 0) -+#define CSR_GCFG_CCCP_ROOT (0x1ULL << 1) -+#define CSR_GCFG_CCCP_NEST (0x1ULL << 2) -+ -+#define LOONGARCH_CSR_GINTC 0x52 /* 64 guest exception control */ -+#define CSR_GINTC_HC_SHIFT 16 -+#define CSR_GINTC_HC_WIDTH 8 -+#define CSR_GINTC_HC (0xffULL << CSR_GINTC_HC_SHIFT) -+#define CSR_GINTC_PIP_SHIFT 8 -+#define CSR_GINTC_PIP_WIDTH 8 -+#define CSR_GINTC_PIP (0xffULL << CSR_GINTC_PIP_SHIFT) -+#define CSR_GINTC_VIP_SHIFT 0 -+#define CSR_GINTC_VIP_WIDTH 8 -+#define CSR_GINTC_VIP (0xff) -+ -+#define LOONGARCH_CSR_GCNTC 0x53 /* 64 guest timer offset */ -+ -+/* LLBCTL */ -+#define LOONGARCH_CSR_LLBCTL 0x60 /* 32 csr number to be changed */ -+#define CSR_LLBCTL_ROLLB_SHIFT 0 -+#define CSR_LLBCTL_ROLLB (1ULL << CSR_LLBCTL_ROLLB_SHIFT) -+#define CSR_LLBCTL_WCLLB_SHIFT 1 -+#define CSR_LLBCTL_WCLLB (1ULL << CSR_LLBCTL_WCLLB_SHIFT) -+#define CSR_LLBCTL_KLO_SHIFT 2 -+#define CSR_LLBCTL_KLO (1ULL << CSR_LLBCTL_KLO_SHIFT) -+ -+/* implement dependent */ -+#define LOONGARCH_CSR_IMPCTL1 0x80 /* 32 loongarch config */ -+#define CSR_MISPEC_SHIFT 20 -+#define CSR_MISPEC_WIDTH 8 -+#define CSR_MISPEC (0xffULL << CSR_MISPEC_SHIFT) -+#define CSR_SSEN_SHIFT 18 -+#define CSR_SSEN (1ULL << CSR_SSEN_SHIFT) -+#define CSR_SCRAND_SHIFT 17 -+#define CSR_SCRAND (1ULL << CSR_SCRAND_SHIFT) -+#define CSR_LLEXCL_SHIFT 16 -+#define CSR_LLEXCL (1ULL << CSR_LLEXCL_SHIFT) -+#define CSR_DISVC_SHIFT 15 -+#define CSR_DISVC (1ULL << CSR_DISVC_SHIFT) -+#define CSR_VCLRU_SHIFT 14 -+#define CSR_VCLRU (1ULL << CSR_VCLRU_SHIFT) -+#define CSR_DCLRU_SHIFT 13 -+#define CSR_DCLRU (1ULL << CSR_DCLRU_SHIFT) -+#define CSR_FASTLDQ_SHIFT 12 -+#define CSR_FASTLDQ (1ULL << CSR_FASTLDQ_SHIFT) -+#define CSR_USERCAC_SHIFT 11 -+#define CSR_USERCAC (1ULL << CSR_USERCAC_SHIFT) -+#define CSR_ANTI_MISPEC_SHIFT 10 -+#define CSR_ANTI_MISPEC (1ULL << CSR_ANTI_MISPEC_SHIFT) -+#define CSR_ANTI_FLUSHSFB_SHIFT 9 -+#define CSR_ANTI_FLUSHSFB (1ULL << CSR_ANTI_FLUSHSFB_SHIFT) -+#define CSR_STFILL_SHIFT 8 -+#define CSR_STFILL (1ULL << CSR_STFILL_SHIFT) -+#define CSR_LIFEP_SHIFT 7 -+#define CSR_LIFEP (1ULL << CSR_LIFEP_SHIFT) -+#define CSR_LLSYNC_SHIFT 6 -+#define CSR_LLSYNC (1ULL << CSR_LLSYNC_SHIFT) -+#define CSR_BRBTDIS_SHIFT 5 -+#define CSR_BRBTDIS (1ULL << CSR_BRBTDIS_SHIFT) -+#define CSR_RASDIS_SHIFT 4 -+#define CSR_RASDIS (1ULL << CSR_RASDIS_SHIFT) -+#define CSR_STPRE_SHIFT 2 -+#define CSR_STPRE_WIDTH 2 -+#define CSR_STPRE (3ULL << CSR_STPRE_SHIFT) -+#define CSR_INSTPRE_SHIFT 1 -+#define CSR_INSTPRE (1ULL << CSR_INSTPRE_SHIFT) -+#define CSR_DATAPRE_SHIFT 0 -+#define CSR_DATAPRE (1ULL << CSR_DATAPRE_SHIFT) -+ -+#define LOONGARCH_CSR_IMPCTL2 0x81 /* 32 Flush */ -+#define CSR_IMPCTL2_MTLB_SHIFT 0 -+#define CSR_IMPCTL2_MTLB (1ULL << CSR_IMPCTL2_MTLB_SHIFT) -+#define CSR_IMPCTL2_STLB_SHIFT 1 -+#define CSR_IMPCTL2_STLB (1ULL << CSR_IMPCTL2_STLB_SHIFT) -+#define CSR_IMPCTL2_DTLB_SHIFT 2 -+#define CSR_IMPCTL2_DTLB (1ULL << CSR_IMPCTL2_DTLB_SHIFT) -+#define CSR_IMPCTL2_ITLB_SHIFT 3 -+#define CSR_IMPCTL2_ITLB (1ULL << CSR_IMPCTL2_ITLB_SHIFT) -+#define CSR_IMPCTL2_BTAC_SHIFT 4 -+#define CSR_IMPCTL2_BTAC (1ULL << CSR_IMPCTL2_BTAC_SHIFT) -+ -+#define LOONGARCH_FLUSH_VTLB 1 -+#define LOONGARCH_FLUSH_FTLB (1 << 1) -+#define LOONGARCH_FLUSH_DTLB (1 << 2) -+#define LOONGARCH_FLUSH_ITLB (1 << 3) -+#define LOONGARCH_FLUSH_BTAC (1 << 4) -+ -+#define LOONGARCH_CSR_GNMI 0x82 -+ -+/* TLB Refill Only */ -+#define LOONGARCH_CSR_TLBRENT 0x88 /* 64 TLB refill exception address */ -+#define LOONGARCH_CSR_TLBRBADV 0x89 /* 64 TLB refill badvaddr */ -+#define LOONGARCH_CSR_TLBRERA 0x8a /* 64 TLB refill ERA */ -+#define LOONGARCH_CSR_TLBRSAVE 0x8b /* 64 KScratch for TLB refill */ -+#define LOONGARCH_CSR_TLBRELO0 0x8c /* 64 TLB refill entrylo0 */ -+#define LOONGARCH_CSR_TLBRELO1 0x8d /* 64 TLB refill entrylo1 */ -+#define LOONGARCH_CSR_TLBREHI 0x8e /* 64 TLB refill entryhi */ -+#define LOONGARCH_CSR_TLBRPRMD 0x8f /* 64 TLB refill mode info */ -+ -+/* error related */ -+#define LOONGARCH_CSR_ERRCTL 0x90 /* 32 ERRCTL */ -+#define LOONGARCH_CSR_ERRINFO 0x91 -+#define LOONGARCH_CSR_ERRINFO1 0x92 -+#define LOONGARCH_CSR_ERRENT 0x93 /* 64 error exception base */ -+#define LOONGARCH_CSR_ERRERA 0x94 /* 64 error exception PC */ -+#define LOONGARCH_CSR_ERRSAVE 0x95 /* 64 KScratch for error exception */ -+ -+#define LOONGARCH_CSR_CTAG 0x98 /* 64 TagLo + TagHi */ -+ -+/* direct map windows */ -+#define LOONGARCH_CSR_DMWIN0 0x180 /* 64 direct map win0: MEM & IF */ -+#define LOONGARCH_CSR_DMWIN1 0x181 /* 64 direct map win1: MEM & IF */ -+#define LOONGARCH_CSR_DMWIN2 0x182 /* 64 direct map win2: MEM */ -+#define LOONGARCH_CSR_DMWIN3 0x183 /* 64 direct map win3: MEM */ -+#define CSR_DMW_PLV0 0x1 -+#define CSR_DMW_PLV1 0x2 -+#define CSR_DMW_PLV2 0x4 -+#define CSR_DMW_PLV3 0x8 -+#define CSR_DMW_BASE_SH 48 -+#define dmwin_va2pa(va) \ -+ (va & (((unsigned long)1 << CSR_DMW_BASE_SH) - 1)) -+ -+/* performance counter */ -+#define LOONGARCH_CSR_PERFCTRL0 0x200 /* 32 perf event 0 config */ -+#define LOONGARCH_CSR_PERFCNTR0 0x201 /* 64 perf event 0 count value */ -+#define LOONGARCH_CSR_PERFCTRL1 0x202 /* 32 perf event 1 config */ -+#define LOONGARCH_CSR_PERFCNTR1 0x203 /* 64 perf event 1 count value */ -+#define LOONGARCH_CSR_PERFCTRL2 0x204 /* 32 perf event 2 config */ -+#define LOONGARCH_CSR_PERFCNTR2 0x205 /* 64 perf event 2 count value */ -+#define LOONGARCH_CSR_PERFCTRL3 0x206 /* 32 perf event 3 config */ -+#define LOONGARCH_CSR_PERFCNTR3 0x207 /* 64 perf event 3 count value */ -+#define CSR_PERFCTRL_PLV0 (1ULL << 16) -+#define CSR_PERFCTRL_PLV1 (1ULL << 17) -+#define CSR_PERFCTRL_PLV2 (1ULL << 18) -+#define CSR_PERFCTRL_PLV3 (1ULL << 19) -+#define CSR_PERFCTRL_IE (1ULL << 20) -+#define CSR_PERFCTRL_EVENT 0x3ff -+ -+/* debug */ -+#define LOONGARCH_CSR_MWPC 0x300 /* data breakpoint config */ -+#define LOONGARCH_CSR_MWPS 0x301 /* data breakpoint status */ -+ -+#define LOONGARCH_CSR_DB0ADDR 0x310 /* data breakpoint 0 address */ -+#define LOONGARCH_CSR_DB0MASK 0x311 /* data breakpoint 0 mask */ -+#define LOONGARCH_CSR_DB0CTL 0x312 /* data breakpoint 0 control */ -+#define LOONGARCH_CSR_DB0ASID 0x313 /* data breakpoint 0 asid */ -+ -+#define LOONGARCH_CSR_DB1ADDR 0x318 /* data breakpoint 1 address */ -+#define LOONGARCH_CSR_DB1MASK 0x319 /* data breakpoint 1 mask */ -+#define LOONGARCH_CSR_DB1CTL 0x31a /* data breakpoint 1 control */ -+#define LOONGARCH_CSR_DB1ASID 0x31b /* data breakpoint 1 asid */ -+ -+#define LOONGARCH_CSR_DB2ADDR 0x320 /* data breakpoint 2 address */ -+#define LOONGARCH_CSR_DB2MASK 0x321 /* data breakpoint 2 mask */ -+#define LOONGARCH_CSR_DB2CTL 0x322 /* data breakpoint 2 control */ -+#define LOONGARCH_CSR_DB2ASID 0x323 /* data breakpoint 2 asid */ -+ -+#define LOONGARCH_CSR_DB3ADDR 0x328 /* data breakpoint 3 address */ -+#define LOONGARCH_CSR_DB3MASK 0x329 /* data breakpoint 3 mask */ -+#define LOONGARCH_CSR_DB3CTL 0x32a /* data breakpoint 3 control */ -+#define LOONGARCH_CSR_DB3ASID 0x32b /* data breakpoint 3 asid */ -+ -+#define LOONGARCH_CSR_FWPC 0x380 /* instruction breakpoint config */ -+#define LOONGARCH_CSR_FWPS 0x381 /* instruction breakpoint status */ -+ -+#define LOONGARCH_CSR_IB0ADDR 0x390 /* inst breakpoint 0 address */ -+#define LOONGARCH_CSR_IB0MASK 0x391 /* inst breakpoint 0 mask */ -+#define LOONGARCH_CSR_IB0CTL 0x392 /* inst breakpoint 0 control */ -+#define LOONGARCH_CSR_IB0ASID 0x393 /* inst breakpoint 0 asid */ -+#define LOONGARCH_CSR_IB1ADDR 0x398 /* inst breakpoint 1 address */ -+#define LOONGARCH_CSR_IB1MASK 0x399 /* inst breakpoint 1 mask */ -+#define LOONGARCH_CSR_IB1CTL 0x39a /* inst breakpoint 1 control */ -+#define LOONGARCH_CSR_IB1ASID 0x39b /* inst breakpoint 1 asid */ -+ -+#define LOONGARCH_CSR_IB2ADDR 0x3a0 /* inst breakpoint 2 address */ -+#define LOONGARCH_CSR_IB2MASK 0x3a1 /* inst breakpoint 2 mask */ -+#define LOONGARCH_CSR_IB2CTL 0x3a2 /* inst breakpoint 2 control */ -+#define LOONGARCH_CSR_IB2ASID 0x3a3 /* inst breakpoint 2 asid */ -+ -+#define LOONGARCH_CSR_IB3ADDR 0x3a8 /* inst breakpoint 3 address */ -+#define LOONGARCH_CSR_IB3MASK 0x3a9 /* inst breakpoint 3 mask */ -+#define LOONGARCH_CSR_IB3CTL 0x3aa /* inst breakpoint 3 control */ -+#define LOONGARCH_CSR_IB3ASID 0x3ab /* inst breakpoint 3 asid */ -+ -+#define LOONGARCH_CSR_IB4ADDR 0x3b0 /* inst breakpoint 4 address */ -+#define LOONGARCH_CSR_IB4MASK 0x3b1 /* inst breakpoint 4 mask */ -+#define LOONGARCH_CSR_IB4CTL 0x3b2 /* inst breakpoint 4 control */ -+#define LOONGARCH_CSR_IB4ASID 0x3b3 /* inst breakpoint 4 asid */ -+ -+#define LOONGARCH_CSR_IB5ADDR 0x3b8 /* inst breakpoint 5 address */ -+#define LOONGARCH_CSR_IB5MASK 0x3b9 /* inst breakpoint 5 mask */ -+#define LOONGARCH_CSR_IB5CTL 0x3ba /* inst breakpoint 5 control */ -+#define LOONGARCH_CSR_IB5ASID 0x3bb /* inst breakpoint 5 asid */ -+ -+#define LOONGARCH_CSR_IB6ADDR 0x3c0 /* inst breakpoint 6 address */ -+#define LOONGARCH_CSR_IB6MASK 0x3c1 /* inst breakpoint 6 mask */ -+#define LOONGARCH_CSR_IB6CTL 0x3c2 /* inst breakpoint 6 control */ -+#define LOONGARCH_CSR_IB6ASID 0x3c3 /* inst breakpoint 6 asid */ -+ -+#define LOONGARCH_CSR_IB7ADDR 0x3c8 /* inst breakpoint 7 address */ -+#define LOONGARCH_CSR_IB7MASK 0x3c9 /* inst breakpoint 7 mask */ -+#define LOONGARCH_CSR_IB7CTL 0x3ca /* inst breakpoint 7 control */ -+#define LOONGARCH_CSR_IB7ASID 0x3cb /* inst breakpoint 7 asid */ -+ -+#define LOONGARCH_CSR_DEBUG 0x500 /* debug config */ -+#define CSR_DEBUG_DM 0 -+#define CSR_DEBUG_DMVER 1 -+#define CSR_DEBUG_DINT 8 -+#define CSR_DEBUG_DBP 9 -+#define CSR_DEBUG_DIB 10 -+#define CSR_DEBUG_DDB 11 -+ -+#define LOONGARCH_CSR_DERA 0x501 /* debug era */ -+#define LOONGARCH_CSR_DESAVE 0x502 /* debug save */ -+ -+#define LOONGARCH_CSR_PRID 0xc0 /* 32 LOONGARCH CP0 PRID */ -+ -+#define LOONGARCH_CPUCFG0 0x0 -+#define CPUCFG0_3A5000_PRID 0x0014c010 -+ -+#define LOONGARCH_CPUCFG1 0x1 -+#define CPUCFG1_ISGR32 BIT(0) -+#define CPUCFG1_ISGR64 BIT(1) -+#define CPUCFG1_PAGING BIT(2) -+#define CPUCFG1_IOCSR BIT(3) -+#define CPUCFG1_PABITS (47 << 4) -+#define CPUCFG1_VABITS (47 << 12) -+#define CPUCFG1_UAL BIT(20) -+#define CPUCFG1_RI BIT(21) -+#define CPUCFG1_XI BIT(22) -+#define CPUCFG1_RPLV BIT(23) -+#define CPUCFG1_HUGEPG BIT(24) -+#define CPUCFG1_IOCSRBRD BIT(25) -+#define CPUCFG1_MSGINT BIT(26) -+ -+#define LOONGARCH_CPUCFG2 0x2 -+#define CPUCFG2_FP BIT(0) -+#define CPUCFG2_FPSP BIT(1) -+#define CPUCFG2_FPDP BIT(2) -+#define CPUCFG2_FPVERS (0 << 3) -+#define CPUCFG2_LSX BIT(6) -+#define CPUCFG2_LASX BIT(7) -+#define CPUCFG2_COMPLEX BIT(8) -+#define CPUCFG2_CRYPTO BIT(9) -+#define CPUCFG2_LVZP BIT(10) -+#define CPUCFG2_LVZVER (0 << 11) -+#define CPUCFG2_LLFTP BIT(14) -+#define CPUCFG2_LLFTPREV (1 << 15) -+#define CPUCFG2_X86BT BIT(18) -+#define CPUCFG2_ARMBT BIT(19) -+#define CPUCFG2_MIPSBT BIT(20) -+#define CPUCFG2_LSPW BIT(21) -+#define CPUCFG2_LAM BIT(22) -+ -+#define LOONGARCH_CPUCFG3 0x3 -+#define CPUCFG3_CCDMA BIT(0) -+#define CPUCFG3_SFB BIT(1) -+#define CPUCFG3_UCACC BIT(2) -+#define CPUCFG3_LLEXC BIT(3) -+#define CPUCFG3_SCDLY BIT(4) -+#define CPUCFG3_LLDBAR BIT(5) -+#define CPUCFG3_ITLBT BIT(6) -+#define CPUCFG3_ICACHET BIT(7) -+#define CPUCFG3_SPW_LVL (4 << 8) -+#define CPUCFG3_SPW_HG_HF BIT(11) -+#define CPUCFG3_RVA BIT(12) -+#define CPUCFG3_RVAMAX (7 << 13) -+ -+#define LOONGARCH_CPUCFG4 0x4 -+#define CCFREQ_100M 100000000 /* 100M */ -+ -+#define LOONGARCH_CPUCFG5 0x5 -+#define CPUCFG5_CCMUL 1 -+#define CPUCFG5_CCDIV (1 << 16) -+ -+#define LOONGARCH_CPUCFG6 0x6 -+#define CPUCFG6_PMP BIT(0) -+#define CPUCFG6_PAMVER (1 << 1) -+#define CPUCFG6_PMNUM (3 << 4) -+#define CPUCFG6_PMBITS (63 << 8) -+#define CPUCFG6_UPM BIT(14) -+ -+#define LOONGARCH_CPUCFG16 0x10 -+#define CPUCFG16_L1_IUPRE BIT(0) -+#define CPUCFG16_L1_UNIFY BIT(1) -+#define CPUCFG16_L1_DPRE BIT(2) -+#define CPUCFG16_L2_IUPRE BIT(3) -+#define CPUCFG16_L2_IUUNIFY BIT(4) -+#define CPUCFG16_L2_IUPRIV BIT(5) -+#define CPUCFG16_L2_IUINCL BIT(6) -+#define CPUCFG16_L2_DPRE BIT(7) -+#define CPUCFG16_L2_DPRIV BIT(8) -+#define CPUCFG16_L2_DINCL BIT(9) -+#define CPUCFG16_L3_IUPRE BIT(10) -+#define CPUCFG16_L3_IUUNIFY BIT(11) -+#define CPUCFG16_L3_IUPRIV BIT(12) -+#define CPUCFG16_L3_IUINCL BIT(13) -+#define CPUCFG16_L3_DPRE BIT(14) -+#define CPUCFG16_L3_DPRIV BIT(15) -+#define CPUCFG16_L3_DINCL BIT(16) -+ -+#define LOONGARCH_CPUCFG17 0x11 -+#define CPUCFG17_L1I_WAYS_M (3 << 0) -+#define CPUCFG17_L1I_SETS_M (8 << 16) -+#define CPUCFG17_L1I_SIZE_M (6 << 24) -+ -+#define LOONGARCH_CPUCFG18 0x12 -+#define CPUCFG18_L1D_WAYS_M (3 << 0) -+#define CPUCFG18_L1D_SETS_M (8 << 16) -+#define CPUCFG18_L1D_SIZE_M (6 << 24) -+ -+#define LOONGARCH_CPUCFG19 0x13 -+#define CPUCFG19_L2_WAYS_M (0xf << 0) -+#define CPUCFG19_L2_SETS_M (8 << 16) -+#define CPUCFG19_L2_SIZE_M (6 << 24) -+ -+#define LOONGARCH_CPUCFG20 0x14 -+#define CPUCFG20_L3_WAYS_M (0xf << 0) -+#define CPUCFG20_L3_SETS_M (0xe << 16) -+#define CPUCFG20_L3_SIZE_M (0x6 << 24) -+ -+#define LOONGARCH_PAGE_HUGE 0x40 -+#define LOONGARCH_HUGE_GLOBAL 0x1000 -+#define LOONGARCH_HUGE_GLOBAL_SH 12 -+ -+/* All CSR register -+ * -+ * default value in target/loongarch/cpu.c -+ * reset function in target/loongarch/translate.c:cpu_state_reset() -+ * -+ * This macro will be used only twice. -+ * > In target/loongarch/cpu.h:CPULOONGARCHState -+ * > In target/loongarch/internal.h:loongarch_def_t -+ * -+ * helper_function to rd/wr: -+ * > declare in target/loongarch/helper.h -+ * > realize in target/loongarch/op_helper.c -+ * -+ * during translate: -+ * > gen_csr_rdl() -+ * > gen_csr_wrl() -+ * > gen_csr_rdq() -+ * > gen_csr_wrq() -+ */ -+#define CPU_LOONGARCH_CSR \ -+ uint64_t CSR_CRMD; \ -+ uint64_t CSR_PRMD; \ -+ uint64_t CSR_EUEN; \ -+ uint64_t CSR_MISC; \ -+ uint64_t CSR_ECFG; \ -+ uint64_t CSR_ESTAT; \ -+ uint64_t CSR_ERA; \ -+ uint64_t CSR_BADV; \ -+ uint64_t CSR_BADI; \ -+ uint64_t CSR_EEPN; \ -+ uint64_t CSR_TLBIDX; \ -+ uint64_t CSR_TLBEHI; \ -+ uint64_t CSR_TLBELO0; \ -+ uint64_t CSR_TLBELO1; \ -+ uint64_t CSR_TLBWIRED; \ -+ uint64_t CSR_GTLBC; \ -+ uint64_t CSR_TRGP; \ -+ uint64_t CSR_ASID; \ -+ uint64_t CSR_PGDL; \ -+ uint64_t CSR_PGDH; \ -+ uint64_t CSR_PGD; \ -+ uint64_t CSR_PWCTL0; \ -+ uint64_t CSR_PWCTL1; \ -+ uint64_t CSR_STLBPGSIZE; \ -+ uint64_t CSR_RVACFG; \ -+ uint64_t CSR_CPUID; \ -+ uint64_t CSR_PRCFG1; \ -+ uint64_t CSR_PRCFG2; \ -+ uint64_t CSR_PRCFG3; \ -+ uint64_t CSR_KS0; \ -+ uint64_t CSR_KS1; \ -+ uint64_t CSR_KS2; \ -+ uint64_t CSR_KS3; \ -+ uint64_t CSR_KS4; \ -+ uint64_t CSR_KS5; \ -+ uint64_t CSR_KS6; \ -+ uint64_t CSR_KS7; \ -+ uint64_t CSR_KS8; \ -+ uint64_t CSR_TMID; \ -+ uint64_t CSR_TCFG; \ -+ uint64_t CSR_TVAL; \ -+ uint64_t CSR_CNTC; \ -+ uint64_t CSR_TINTCLR; \ -+ uint64_t CSR_GSTAT; \ -+ uint64_t CSR_GCFG; \ -+ uint64_t CSR_GINTC; \ -+ uint64_t CSR_GCNTC; \ -+ uint64_t CSR_LLBCTL; \ -+ uint64_t CSR_IMPCTL1; \ -+ uint64_t CSR_IMPCTL2; \ -+ uint64_t CSR_GNMI; \ -+ uint64_t CSR_TLBRENT; \ -+ uint64_t CSR_TLBRBADV; \ -+ uint64_t CSR_TLBRERA; \ -+ uint64_t CSR_TLBRSAVE; \ -+ uint64_t CSR_TLBRELO0; \ -+ uint64_t CSR_TLBRELO1; \ -+ uint64_t CSR_TLBREHI; \ -+ uint64_t CSR_TLBRPRMD; \ -+ uint64_t CSR_ERRCTL; \ -+ uint64_t CSR_ERRINFO; \ -+ uint64_t CSR_ERRINFO1; \ -+ uint64_t CSR_ERRENT; \ -+ uint64_t CSR_ERRERA; \ -+ uint64_t CSR_ERRSAVE; \ -+ uint64_t CSR_CTAG; \ -+ uint64_t CSR_DMWIN0; \ -+ uint64_t CSR_DMWIN1; \ -+ uint64_t CSR_DMWIN2; \ -+ uint64_t CSR_DMWIN3; \ -+ uint64_t CSR_PERFCTRL0; \ -+ uint64_t CSR_PERFCNTR0; \ -+ uint64_t CSR_PERFCTRL1; \ -+ uint64_t CSR_PERFCNTR1; \ -+ uint64_t CSR_PERFCTRL2; \ -+ uint64_t CSR_PERFCNTR2; \ -+ uint64_t CSR_PERFCTRL3; \ -+ uint64_t CSR_PERFCNTR3; \ -+ uint64_t CSR_MWPC; \ -+ uint64_t CSR_MWPS; \ -+ uint64_t CSR_DB0ADDR; \ -+ uint64_t CSR_DB0MASK; \ -+ uint64_t CSR_DB0CTL; \ -+ uint64_t CSR_DB0ASID; \ -+ uint64_t CSR_DB1ADDR; \ -+ uint64_t CSR_DB1MASK; \ -+ uint64_t CSR_DB1CTL; \ -+ uint64_t CSR_DB1ASID; \ -+ uint64_t CSR_DB2ADDR; \ -+ uint64_t CSR_DB2MASK; \ -+ uint64_t CSR_DB2CTL; \ -+ uint64_t CSR_DB2ASID; \ -+ uint64_t CSR_DB3ADDR; \ -+ uint64_t CSR_DB3MASK; \ -+ uint64_t CSR_DB3CTL; \ -+ uint64_t CSR_DB3ASID; \ -+ uint64_t CSR_FWPC; \ -+ uint64_t CSR_FWPS; \ -+ uint64_t CSR_IB0ADDR; \ -+ uint64_t CSR_IB0MASK; \ -+ uint64_t CSR_IB0CTL; \ -+ uint64_t CSR_IB0ASID; \ -+ uint64_t CSR_IB1ADDR; \ -+ uint64_t CSR_IB1MASK; \ -+ uint64_t CSR_IB1CTL; \ -+ uint64_t CSR_IB1ASID; \ -+ uint64_t CSR_IB2ADDR; \ -+ uint64_t CSR_IB2MASK; \ -+ uint64_t CSR_IB2CTL; \ -+ uint64_t CSR_IB2ASID; \ -+ uint64_t CSR_IB3ADDR; \ -+ uint64_t CSR_IB3MASK; \ -+ uint64_t CSR_IB3CTL; \ -+ uint64_t CSR_IB3ASID; \ -+ uint64_t CSR_IB4ADDR; \ -+ uint64_t CSR_IB4MASK; \ -+ uint64_t CSR_IB4CTL; \ -+ uint64_t CSR_IB4ASID; \ -+ uint64_t CSR_IB5ADDR; \ -+ uint64_t CSR_IB5MASK; \ -+ uint64_t CSR_IB5CTL; \ -+ uint64_t CSR_IB5ASID; \ -+ uint64_t CSR_IB6ADDR; \ -+ uint64_t CSR_IB6MASK; \ -+ uint64_t CSR_IB6CTL; \ -+ uint64_t CSR_IB6ASID; \ -+ uint64_t CSR_IB7ADDR; \ -+ uint64_t CSR_IB7MASK; \ -+ uint64_t CSR_IB7CTL; \ -+ uint64_t CSR_IB7ASID; \ -+ uint64_t CSR_DEBUG; \ -+ uint64_t CSR_DERA; \ -+ uint64_t CSR_DESAVE; \ -+ -+#define LOONGARCH_CSR_32(_R, _S) \ -+ (KVM_REG_LOONGARCH_CSR | KVM_REG_SIZE_U32 | (8 * (_R) + (_S))) -+ -+#define LOONGARCH_CSR_64(_R, _S) \ -+ (KVM_REG_LOONGARCH_CSR | KVM_REG_SIZE_U64 | (8 * (_R) + (_S))) -+ -+#define KVM_IOC_CSRID(id) LOONGARCH_CSR_64(id, 0) -+ -+#endif -diff --git a/target/loongarch64/cpu-param.h b/target/loongarch64/cpu-param.h -new file mode 100644 -index 000000000..24ca458af ---- /dev/null -+++ b/target/loongarch64/cpu-param.h -@@ -0,0 +1,30 @@ -+#ifndef CPU_PARAM_H -+#define CPU_PARAM_H -+ -+/* If we want to use host float regs... */ -+/* #define USE_HOST_FLOAT_REGS */ -+ -+/* Real pages are variable size... */ -+#define TARGET_PAGE_BITS 14 -+ -+#define LOONGARCH_TLB_MAX 2112 -+ -+#define TARGET_LONG_BITS 64 -+#define TARGET_PHYS_ADDR_SPACE_BITS 48 -+#define TARGET_VIRT_ADDR_SPACE_BITS 48 -+ -+/* -+ * bit definitions for insn_flags (ISAs/ASEs flags) -+ * ------------------------------------------------ -+ */ -+#define ISA_LARCH32 0x00000001ULL -+#define ISA_LARCH64 0x00000002ULL -+#define INSN_LOONGARCH 0x00010000ULL -+ -+#define CPU_LARCH32 (ISA_LARCH32) -+#define CPU_LARCH64 (ISA_LARCH32 | ISA_LARCH64) -+ -+#define NB_MMU_MODES 4 -+ -+#endif /* QEMU_LOONGARCH_DEFS_H */ -+ -diff --git a/target/loongarch64/cpu-qom.h b/target/loongarch64/cpu-qom.h -new file mode 100644 -index 000000000..ee9c1de57 ---- /dev/null -+++ b/target/loongarch64/cpu-qom.h -@@ -0,0 +1,54 @@ -+/* -+ * QEMU LOONGARCH CPU -+ * -+ * Copyright (c) 2012 SUSE LINUX Products GmbH -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see -+ * -+ */ -+#ifndef QEMU_LOONGARCH_CPU_QOM_H -+#define QEMU_LOONGARCH_CPU_QOM_H -+ -+#include "hw/core/cpu.h" -+ -+#define TYPE_LOONGARCH_CPU "loongarch-cpu" -+ -+#define LOONGARCH_CPU_CLASS(klass) \ -+ OBJECT_CLASS_CHECK(LOONGARCHCPUClass, (klass), TYPE_LOONGARCH_CPU) -+#define LOONGARCH_CPU(obj) \ -+ OBJECT_CHECK(LOONGARCHCPU, (obj), TYPE_LOONGARCH_CPU) -+#define LOONGARCH_CPU_GET_CLASS(obj) \ -+ OBJECT_GET_CLASS(LOONGARCHCPUClass, (obj), TYPE_LOONGARCH_CPU) -+ -+/** -+ * LOONGARCHCPUClass: -+ * @parent_realize: The parent class' realize handler. -+ * @parent_reset: The parent class' reset handler. -+ * -+ * A LOONGARCH CPU model. -+ */ -+typedef struct LOONGARCHCPUClass { -+ /*< private >*/ -+ CPUClass parent_class; -+ /*< public >*/ -+ -+ DeviceRealize parent_realize; -+ DeviceUnrealize parent_unrealize; -+ DeviceReset parent_reset; -+ const struct loongarch_def_t *cpu_def; -+} LOONGARCHCPUClass; -+ -+typedef struct LOONGARCHCPU LOONGARCHCPU; -+ -+#endif -diff --git a/target/loongarch64/cpu.c b/target/loongarch64/cpu.c -new file mode 100644 -index 000000000..a4535d34a ---- /dev/null -+++ b/target/loongarch64/cpu.c -@@ -0,0 +1,576 @@ -+/* -+ * QEMU LOONGARCH CPU -+ * -+ * Copyright (c) 2012 SUSE LINUX Products GmbH -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "qapi/visitor.h" -+#include "cpu.h" -+#include "internal.h" -+#include "kvm_larch.h" -+#include "qemu-common.h" -+#include "hw/qdev-properties.h" -+#include "sysemu/kvm.h" -+#include "exec/exec-all.h" -+#include "sysemu/arch_init.h" -+#include "cpu-csr.h" -+#include "qemu/qemu-print.h" -+#include "qapi/qapi-commands-machine-target.h" -+#ifdef CONFIG_TCG -+#include "hw/core/tcg-cpu-ops.h" -+#endif /* CONFIG_TCG */ -+ -+#define LOONGARCH_CONFIG1 \ -+((0x8 << CSR_CONF1_KSNUM_SHIFT) | (0x2f << CSR_CONF1_TMRBITS_SHIFT) | \ -+ (0x7 << CSR_CONF1_VSMAX_SHIFT)) -+ -+#define LOONGARCH_CONFIG3 \ -+((0x2 << CSR_CONF3_TLBORG_SHIFT) | (0x3f << CSR_CONF3_MTLBSIZE_SHIFT) | \ -+ (0x7 << CSR_CONF3_STLBWAYS_SHIFT) | (0x8 << CSR_CONF3_STLBIDX_SHIFT)) -+ -+/*****************************************************************************/ -+/* LOONGARCH CPU definitions */ -+const loongarch_def_t loongarch_defs[] = { -+ { -+ .name = "Loongson-3A5000", -+ -+ /* for LoongISA CSR */ -+ .CSR_PRCFG1 = LOONGARCH_CONFIG1, -+ .CSR_PRCFG2 = 0x3ffff000, -+ .CSR_PRCFG3 = LOONGARCH_CONFIG3, -+ .CSR_CRMD = (0 << CSR_CRMD_PLV_SHIFT) | (0 << CSR_CRMD_IE_SHIFT) | -+ (1 << CSR_CRMD_DA_SHIFT) | (0 << CSR_CRMD_PG_SHIFT) | -+ (1 << CSR_CRMD_DACF_SHIFT) | (1 << CSR_CRMD_DACM_SHIFT) , -+ .CSR_ECFG = 0x7 << 16, -+ .CSR_STLBPGSIZE = 0xe, -+ .CSR_RVACFG = 0x0, -+ .CSR_ASID = 0xa0000, -+ .FCSR0 = 0x0, -+ .FCSR0_rw_bitmask = 0x1f1f03df, -+ .PABITS = 48, -+ .insn_flags = CPU_LARCH64 | INSN_LOONGARCH, -+ .mmu_type = MMU_TYPE_LS3A5K, -+ }, -+ { -+ .name = "host", -+ -+ /* for LoongISA CSR */ -+ .CSR_PRCFG1 = LOONGARCH_CONFIG1, -+ .CSR_PRCFG2 = 0x3ffff000, -+ .CSR_PRCFG3 = LOONGARCH_CONFIG3, -+ .CSR_CRMD = (0 << CSR_CRMD_PLV_SHIFT) | (0 << CSR_CRMD_IE_SHIFT) | -+ (1 << CSR_CRMD_DA_SHIFT) | (0 << CSR_CRMD_PG_SHIFT) | -+ (1 << CSR_CRMD_DACF_SHIFT) | (1 << CSR_CRMD_DACM_SHIFT) , -+ .CSR_ECFG = 0x7 << 16, -+ .CSR_STLBPGSIZE = 0xe, -+ .CSR_RVACFG = 0x0, -+ .FCSR0 = 0x0, -+ .FCSR0_rw_bitmask = 0x1f1f03df, -+ .PABITS = 48, -+ .insn_flags = CPU_LARCH64 | INSN_LOONGARCH, -+ .mmu_type = MMU_TYPE_LS3A5K, -+ }, -+}; -+const int loongarch_defs_number = ARRAY_SIZE(loongarch_defs); -+ -+void loongarch_cpu_list(void) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(loongarch_defs); i++) { -+ qemu_printf("LOONGARCH '%s'\n", -+ loongarch_defs[i].name); -+ } -+} -+ -+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) -+{ -+ CpuDefinitionInfoList *cpu_list = NULL; -+ const loongarch_def_t *def; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(loongarch_defs); i++) { -+ CpuDefinitionInfoList *entry; -+ CpuDefinitionInfo *info; -+ -+ def = &loongarch_defs[i]; -+ info = g_malloc0(sizeof(*info)); -+ info->name = g_strdup(def->name); -+ -+ entry = g_malloc0(sizeof(*entry)); -+ entry->value = info; -+ entry->next = cpu_list; -+ cpu_list = entry; -+ } -+ -+ return cpu_list; -+} -+ -+static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ env->active_tc.PC = value & ~(target_ulong)1; -+} -+ -+static bool loongarch_cpu_has_work(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ bool has_work = false; -+ -+ /* It is implementation dependent if non-enabled -+ interrupts wake-up the CPU, however most of the implementations only -+ check for interrupts that can be taken. */ -+ if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && -+ cpu_loongarch_hw_interrupts_pending(env)) { -+ has_work = true; -+ } -+ -+ return has_work; -+} -+ -+const char * const regnames[] = { -+ "r0", "ra", "tp", "sp", "a0", "a1", "a2", "a3", -+ "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", -+ "t4", "t5", "t6", "t7", "t8", "x0", "fp", "s0", -+ "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", -+}; -+ -+const char * const fregnames[] = { -+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", -+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", -+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", -+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", -+}; -+ -+static void fpu_dump_state(CPULOONGARCHState *env, FILE *f, -+ fprintf_function fpu_fprintf, int flags) -+{ -+ int i; -+ int is_fpu64 = 1; -+ -+#define printfpr(fp) \ -+ do { \ -+ if (is_fpu64) \ -+ fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ -+ " fd:%13g fs:%13g psu: %13g\n", \ -+ (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ -+ (double)(fp)->fd, \ -+ (double)(fp)->fs[FP_ENDIAN_IDX], \ -+ (double)(fp)->fs[!FP_ENDIAN_IDX]); \ -+ else { \ -+ fpr_t tmp; \ -+ tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ -+ tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ -+ fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ -+ " fd:%13g fs:%13g psu:%13g\n", \ -+ tmp.w[FP_ENDIAN_IDX], tmp.d, \ -+ (double)tmp.fd, \ -+ (double)tmp.fs[FP_ENDIAN_IDX], \ -+ (double)tmp.fs[!FP_ENDIAN_IDX]); \ -+ } \ -+ } while (0) -+ -+ -+ fpu_fprintf(f, "FCSR0 0x%08x SR.FR %d fp_status 0x%02x\n", -+ env->active_fpu.fcsr0, is_fpu64, -+ get_float_exception_flags(&env->active_fpu.fp_status)); -+ for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { -+ fpu_fprintf(f, "%3s: ", fregnames[i]); -+ printfpr(&env->active_fpu.fpr[i]); -+ } -+ -+#undef printfpr -+} -+ -+void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int i; -+ -+ qemu_fprintf(f, "pc:\t %lx\n", env->active_tc.PC); -+ for (i = 0; i < 32; i++) { -+ if ((i & 3) == 0) { -+ qemu_fprintf(f, "GPR%02d:", i); -+ } -+ qemu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], -+ env->active_tc.gpr[i]); -+ if ((i & 3) == 3) { -+ qemu_fprintf(f, "\n"); -+ } -+ } -+ qemu_fprintf(f, "EUEN 0x%lx\n", env->CSR_EUEN); -+ qemu_fprintf(f, "ESTAT 0x%lx\n", env->CSR_ESTAT); -+ qemu_fprintf(f, "ERA 0x%lx\n", env->CSR_ERA); -+ qemu_fprintf(f, "CRMD 0x%lx\n", env->CSR_CRMD); -+ qemu_fprintf(f, "PRMD 0x%lx\n", env->CSR_PRMD); -+ qemu_fprintf(f, "BadVAddr 0x%lx\n", env->CSR_BADV); -+ qemu_fprintf(f, "TLB refill ERA 0x%lx\n", env->CSR_TLBRERA); -+ qemu_fprintf(f, "TLB refill BadV 0x%lx\n", env->CSR_TLBRBADV); -+ qemu_fprintf(f, "EEPN 0x%lx\n", env->CSR_EEPN); -+ qemu_fprintf(f, "BadInstr 0x%lx\n", env->CSR_BADI); -+ qemu_fprintf(f, "PRCFG1 0x%lx\nPRCFG2 0x%lx\nPRCFG3 0x%lx\n", -+ env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); -+ if ((flags & CPU_DUMP_FPU) && (env->hflags & LARCH_HFLAG_FPU)) { -+ fpu_dump_state(env, f, qemu_fprintf, flags); -+ } -+} -+ -+void cpu_state_reset(CPULOONGARCHState *env) -+{ -+ LOONGARCHCPU *cpu = loongarch_env_get_cpu(env); -+ CPUState *cs = CPU(cpu); -+ -+ /* Reset registers to their default values */ -+ env->CSR_PRCFG1 = env->cpu_model->CSR_PRCFG1; -+ env->CSR_PRCFG2 = env->cpu_model->CSR_PRCFG2; -+ env->CSR_PRCFG3 = env->cpu_model->CSR_PRCFG3; -+ env->CSR_CRMD = env->cpu_model->CSR_CRMD; -+ env->CSR_ECFG = env->cpu_model->CSR_ECFG; -+ env->CSR_STLBPGSIZE = env->cpu_model->CSR_STLBPGSIZE; -+ env->CSR_RVACFG = env->cpu_model->CSR_RVACFG; -+ env->CSR_ASID = env->cpu_model->CSR_ASID; -+ -+ env->current_tc = 0; -+ env->active_fpu.fcsr0_rw_bitmask = env->cpu_model->FCSR0_rw_bitmask; -+ env->active_fpu.fcsr0 = env->cpu_model->FCSR0; -+ env->insn_flags = env->cpu_model->insn_flags; -+ -+#if !defined(CONFIG_USER_ONLY) -+ env->CSR_ERA = env->active_tc.PC; -+ env->active_tc.PC = env->exception_base; -+#ifdef CONFIG_TCG -+ env->tlb->tlb_in_use = env->tlb->nb_tlb; -+#endif -+ env->CSR_TLBWIRED = 0; -+ env->CSR_TMID = cs->cpu_index; -+ env->CSR_CPUID = (cs->cpu_index & 0x1ff); -+ env->CSR_EEPN |= (uint64_t)0x80000000; -+ env->CSR_TLBRENT |= (uint64_t)0x80000000; -+#endif -+ -+ /* Count register increments in debug mode, EJTAG version 1 */ -+ env->CSR_DEBUG = (1 << CSR_DEBUG_DINT) | (0x1 << CSR_DEBUG_DMVER); -+ -+ compute_hflags(env); -+ restore_fp_status(env); -+ cs->exception_index = EXCP_NONE; -+} -+ -+/* CPUClass::reset() */ -+static void loongarch_cpu_reset(DeviceState *dev) -+{ -+ CPUState *s = CPU(dev); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(s); -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(cpu); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ mcc->parent_reset(dev); -+ -+ memset(env, 0, offsetof(CPULOONGARCHState, end_reset_fields)); -+ -+ cpu_state_reset(env); -+ -+#ifndef CONFIG_USER_ONLY -+ if (kvm_enabled()) { -+ kvm_loongarch_reset_vcpu(cpu); -+ } -+#endif -+} -+ -+static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) -+{ -+ info->print_insn = print_insn_loongarch; -+} -+ -+static void fpu_init(CPULOONGARCHState *env, const loongarch_def_t *def) -+{ -+ memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu)); -+} -+ -+void cpu_loongarch_realize_env(CPULOONGARCHState *env) -+{ -+ env->exception_base = 0x1C000000; -+ -+#ifdef CONFIG_TCG -+#ifndef CONFIG_USER_ONLY -+ mmu_init(env, env->cpu_model); -+#endif -+#endif -+ fpu_init(env, env->cpu_model); -+} -+ -+static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) -+{ -+ CPUState *cs = CPU(dev); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(dev); -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(dev); -+ Error *local_err = NULL; -+ -+ cpu_exec_realizefn(cs, &local_err); -+ if (local_err != NULL) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ cpu_loongarch_realize_env(&cpu->env); -+ -+ loongarch_cpu_register_gdb_regs_for_features(cs); -+ -+ cpu_reset(cs); -+ qemu_init_vcpu(cs); -+ -+ mcc->parent_realize(dev, errp); -+ cpu->hotplugged = 1; -+} -+ -+static void loongarch_cpu_unrealizefn(DeviceState *dev) -+{ -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(dev); -+ -+#ifndef CONFIG_USER_ONLY -+ cpu_remove_sync(CPU(dev)); -+#endif -+ -+ mcc->parent_unrealize(dev); -+} -+static void loongarch_cpu_initfn(Object *obj) -+{ -+ CPUState *cs = CPU(obj); -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(obj); -+ CPULOONGARCHState *env = &cpu->env; -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(obj); -+ cpu_set_cpustate_pointers(cpu); -+ cs->env_ptr = env; -+ env->cpu_model = mcc->cpu_def; -+ cs->halted = 1; -+ cpu->dtb_compatible = "loongarch,Loongson-3A5000"; -+} -+ -+static char *loongarch_cpu_type_name(const char *cpu_model) -+{ -+ return g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model); -+} -+ -+static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) -+{ -+ ObjectClass *oc; -+ char *typename; -+ -+ typename = loongarch_cpu_type_name(cpu_model); -+ oc = object_class_by_name(typename); -+ g_free(typename); -+ return oc; -+} -+ -+static int64_t loongarch_cpu_get_arch_id(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ -+ return cpu->id; -+} -+ -+static Property loongarch_cpu_properties[] = { -+ DEFINE_PROP_INT32("core-id", LOONGARCHCPU, core_id, -1), -+ DEFINE_PROP_INT32("id", LOONGARCHCPU, id, UNASSIGNED_CPU_ID), -+ DEFINE_PROP_INT32("node-id", LOONGARCHCPU, node_id, CPU_UNSET_NUMA_NODE_ID), -+ -+ DEFINE_PROP_END_OF_LIST() -+}; -+ -+#ifdef CONFIG_TCG -+static void loongarch_cpu_synchronize_from_tb(CPUState *cs,const TranslationBlock *tb) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ env->active_tc.PC = tb->pc; -+ env->hflags &= ~LARCH_HFLAG_BMASK; -+ env->hflags |= tb->flags & LARCH_HFLAG_BMASK; -+} -+ -+static const struct TCGCPUOps loongarch_tcg_ops = { -+ .initialize = loongarch_tcg_init, -+ .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, -+ -+ .tlb_fill = loongarch_cpu_tlb_fill, -+ .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, -+ .do_interrupt = loongarch_cpu_do_interrupt, -+ -+#ifndef CONFIG_USER_ONLY -+ .do_unaligned_access = loongarch_cpu_do_unaligned_access, -+#endif /* !CONFIG_USER_ONLY */ -+}; -+#endif /* CONFIG_TCG */ -+ -+ -+#if !defined(CONFIG_USER_ONLY) -+static int get_physical_address(CPULOONGARCHState *env, hwaddr *physical, -+ int *prot, target_ulong real_address, -+ int rw, int access_type, int mmu_idx) -+{ -+ int user_mode = mmu_idx == LARCH_HFLAG_UM; -+ int kernel_mode = !user_mode; -+ unsigned plv, base_c, base_v, tmp; -+ -+ /* effective address (modified for KVM T&E kernel segments) */ -+ target_ulong address = real_address; -+ -+ /* Check PG */ -+ if (!(env->CSR_CRMD & CSR_CRMD_PG)) { -+ /* DA mode */ -+ *physical = address & 0xffffffffffffUL; -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ -+ plv = kernel_mode | (user_mode << 3); -+ base_v = address >> CSR_DMW_BASE_SH; -+ /* Check direct map window 0 */ -+ base_c = env->CSR_DMWIN0 >> CSR_DMW_BASE_SH; -+ if ((plv & env->CSR_DMWIN0) && (base_c == base_v)) { -+ *physical = dmwin_va2pa(address); -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ /* Check direct map window 1 */ -+ base_c = env->CSR_DMWIN1 >> CSR_DMW_BASE_SH; -+ if ((plv & env->CSR_DMWIN1) && (base_c == base_v)) { -+ *physical = dmwin_va2pa(address); -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ /* Check valid extension */ -+ tmp = address >> 47; -+ if (!(tmp == 0 || tmp == 0x1ffff)) { -+ return TLBRET_BADADDR; -+ } -+ /* mapped address */ -+ return env->tlb->map_address(env, physical, prot, real_address, rw, -+ access_type); -+} -+ -+hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ hwaddr phys_addr; -+ int prot; -+ -+ if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT, -+ cpu_mmu_index(env, false)) != 0) { -+ return -1; -+ } -+ return phys_addr; -+} -+#endif -+ -+ -+#ifndef CONFIG_USER_ONLY -+#include "hw/core/sysemu-cpu-ops.h" -+ -+static const struct SysemuCPUOps loongarch_sysemu_ops = { -+ .write_elf64_note = loongarch_cpu_write_elf64_note, -+ .get_phys_page_debug = loongarch_cpu_get_phys_page_debug, -+ .legacy_vmsd = &vmstate_loongarch_cpu, -+}; -+#endif -+ -+ -+static void loongarch_cpu_class_init(ObjectClass *c, void *data) -+{ -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_CLASS(c); -+ CPUClass *cc = CPU_CLASS(c); -+ DeviceClass *dc = DEVICE_CLASS(c); -+ -+ device_class_set_props(dc, loongarch_cpu_properties); -+ device_class_set_parent_realize(dc, loongarch_cpu_realizefn, -+ &mcc->parent_realize); -+ -+ device_class_set_parent_unrealize(dc, loongarch_cpu_unrealizefn, -+ &mcc->parent_unrealize); -+ -+ device_class_set_parent_reset(dc, loongarch_cpu_reset, &mcc->parent_reset); -+ cc->get_arch_id = loongarch_cpu_get_arch_id; -+ -+ cc->class_by_name = loongarch_cpu_class_by_name; -+ cc->has_work = loongarch_cpu_has_work; -+ cc->dump_state = loongarch_cpu_dump_state; -+ cc->set_pc = loongarch_cpu_set_pc; -+ cc->gdb_read_register = loongarch_cpu_gdb_read_register; -+ cc->gdb_write_register = loongarch_cpu_gdb_write_register; -+ cc->disas_set_info = loongarch_cpu_disas_set_info; -+#ifndef CONFIG_USER_ONLY -+ cc->sysemu_ops = &loongarch_sysemu_ops; -+#endif /* !CONFIG_USER_ONLY */ -+ -+ cc->gdb_num_core_regs = 33; -+ cc->gdb_core_xml_file = "loongarch-base64.xml"; -+ cc->gdb_stop_before_watchpoint = true; -+ -+ dc->user_creatable = true; -+#ifdef CONFIG_TCG -+ cc->tcg_ops = &loongarch_tcg_ops; -+#endif /* CONFIG_TCG */ -+} -+ -+static const TypeInfo loongarch_cpu_type_info = { -+ .name = TYPE_LOONGARCH_CPU, -+ .parent = TYPE_CPU, -+ .instance_size = sizeof(LOONGARCHCPU), -+ .instance_init = loongarch_cpu_initfn, -+ .abstract = true, -+ .class_size = sizeof(LOONGARCHCPUClass), -+ .class_init = loongarch_cpu_class_init, -+}; -+ -+static void loongarch_cpu_cpudef_class_init(ObjectClass *oc, void *data) -+{ -+ LOONGARCHCPUClass *mcc = LOONGARCH_CPU_CLASS(oc); -+ mcc->cpu_def = data; -+} -+ -+static void loongarch_register_cpudef_type(const struct loongarch_def_t *def) -+{ -+ char *typename = loongarch_cpu_type_name(def->name); -+ TypeInfo ti = { -+ .name = typename, -+ .parent = TYPE_LOONGARCH_CPU, -+ .class_init = loongarch_cpu_cpudef_class_init, -+ .class_data = (void *)def, -+ }; -+ -+ type_register(&ti); -+ g_free(typename); -+} -+ -+static void loongarch_cpu_register_types(void) -+{ -+ int i; -+ -+ type_register_static(&loongarch_cpu_type_info); -+ for (i = 0; i < loongarch_defs_number; i++) { -+ loongarch_register_cpudef_type(&loongarch_defs[i]); -+ } -+} -+ -+type_init(loongarch_cpu_register_types) -diff --git a/target/loongarch64/cpu.h b/target/loongarch64/cpu.h -new file mode 100644 -index 000000000..10facb3b7 ---- /dev/null -+++ b/target/loongarch64/cpu.h -@@ -0,0 +1,326 @@ -+#ifndef LOONGARCH_CPU_H -+#define LOONGARCH_CPU_H -+ -+ -+#define CPUArchState struct CPULOONGARCHState -+ -+#include "qemu-common.h" -+#include "cpu-qom.h" -+#include "larch-defs.h" -+#include "exec/cpu-defs.h" -+#include "fpu/softfloat.h" -+#include "sysemu/sysemu.h" -+#include "cpu-csr.h" -+ -+#define TCG_GUEST_DEFAULT_MO (0) -+ -+struct CPULOONGARCHState; -+typedef LOONGARCHCPU ArchCPU; -+typedef struct CPULOONGARCHTLBContext CPULOONGARCHTLBContext; -+ -+#define LASX_REG_WIDTH (256) -+typedef union lasx_reg_t lasx_reg_t; -+union lasx_reg_t { -+ int64_t val64[LASX_REG_WIDTH / 64]; -+}; -+ -+typedef union fpr_t fpr_t; -+union fpr_t { -+ float64 fd; /* ieee double precision */ -+ float32 fs[2];/* ieee single precision */ -+ uint64_t d; /* binary double fixed-point */ -+ uint32_t w[2]; /* binary single fixed-point */ -+/* FPU/LASX register mapping is not tested on big-endian hosts. */ -+ lasx_reg_t lasx; /* vector data */ -+}; -+/* define FP_ENDIAN_IDX to access the same location -+ * in the fpr_t union regardless of the host endianness -+ */ -+#if defined(HOST_WORDS_BIGENDIAN) -+# define FP_ENDIAN_IDX 1 -+#else -+# define FP_ENDIAN_IDX 0 -+#endif -+ -+typedef struct CPULOONGARCHFPUContext { -+ /* Floating point registers */ -+ fpr_t fpr[32]; -+ float_status fp_status; -+ -+ bool cf[8]; -+ /* fcsr0 -+ * 31:29 |28:24 |23:21 |20:16 |15:10 |9:8 |7 |6 |5 |4:0 -+ * Cause Flags RM DAE TM Enables -+ */ -+ uint32_t fcsr0; -+ uint32_t fcsr0_rw_bitmask; -+ uint32_t vcsr16; -+} CPULOONGARCHFPUContext; -+ -+/* fp control and status register definition */ -+#define FCSR0_M1 0xdf /* DAE, TM and Enables */ -+#define FCSR0_M2 0x1f1f0000 /* Cause and Flags */ -+#define FCSR0_M3 0x300 /* Round Mode */ -+#define FCSR0_RM 8 /* Round Mode bit num on fcsr0 */ -+#define GET_FP_CAUSE(reg) (((reg) >> 24) & 0x1f) -+#define GET_FP_ENABLE(reg) (((reg) >> 0) & 0x1f) -+#define GET_FP_FLAGS(reg) (((reg) >> 16) & 0x1f) -+#define SET_FP_CAUSE(reg, v) do { (reg) = ((reg) & ~(0x1f << 24)) | \ -+ ((v & 0x1f) << 24); \ -+ } while (0) -+#define SET_FP_ENABLE(reg, v) do { (reg) = ((reg) & ~(0x1f << 0)) | \ -+ ((v & 0x1f) << 0); \ -+ } while (0) -+#define SET_FP_FLAGS(reg, v) do { (reg) = ((reg) & ~(0x1f << 16)) | \ -+ ((v & 0x1f) << 16); \ -+ } while (0) -+#define UPDATE_FP_FLAGS(reg, v) do { (reg) |= ((v & 0x1f) << 16); } while (0) -+#define FP_INEXACT 1 -+#define FP_UNDERFLOW 2 -+#define FP_OVERFLOW 4 -+#define FP_DIV0 8 -+#define FP_INVALID 16 -+ -+#define TARGET_INSN_START_EXTRA_WORDS 2 -+ -+typedef struct loongarch_def_t loongarch_def_t; -+ -+#define LOONGARCH_FPU_MAX 1 -+#define LOONGARCH_KSCRATCH_NUM 8 -+ -+typedef struct TCState TCState; -+struct TCState { -+ target_ulong gpr[32]; -+ target_ulong PC; -+}; -+ -+#define N_IRQS 14 -+#define IRQ_TIMER 11 -+#define IRQ_IPI 12 -+#define IRQ_UART 2 -+ -+typedef struct CPULOONGARCHState CPULOONGARCHState; -+struct CPULOONGARCHState { -+ TCState active_tc; -+ CPULOONGARCHFPUContext active_fpu; -+ -+ uint32_t current_tc; -+ uint64_t scr[4]; -+ uint32_t PABITS; -+ -+ /* LoongISA CSR register */ -+ CPU_LOONGARCH_CSR -+ uint64_t lladdr; -+ target_ulong llval; -+ uint64_t llval_wp; -+ uint32_t llnewval_wp; -+ -+ CPULOONGARCHFPUContext fpus[LOONGARCH_FPU_MAX]; -+ /* QEMU */ -+ int error_code; -+#define EXCP_TLB_NOMATCH 0x1 -+#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ -+ uint32_t hflags; /* CPU State */ -+ /* TMASK defines different execution modes */ -+#define LARCH_HFLAG_TMASK 0x5F5807FF -+ /* -+ * The KSU flags must be the lowest bits in hflags. The flag order -+ * must be the same as defined for CP0 Status. This allows to use -+ * the bits as the value of mmu_idx. -+ */ -+#define LARCH_HFLAG_KSU 0x00003 /* kernel/user mode mask */ -+#define LARCH_HFLAG_UM 0x00003 /* user mode flag */ -+#define LARCH_HFLAG_KM 0x00000 /* kernel mode flag */ -+#define LARCH_HFLAG_64 0x00008 /* 64-bit instructions enabled */ -+#define LARCH_HFLAG_FPU 0x00020 /* FPU enabled */ -+#define LARCH_HFLAG_AWRAP 0x00200 /* 32-bit compatibility address wrapping */ -+ /* If translation is interrupted between the branch instruction and -+ * the delay slot, record what type of branch it is so that we can -+ * resume translation properly. It might be possible to reduce -+ * this from three bits to two. */ -+#define LARCH_HFLAG_BMASK 0x03800 -+#define LARCH_HFLAG_B 0x00800 /* Unconditional branch */ -+#define LARCH_HFLAG_BC 0x01000 /* Conditional branch */ -+#define LARCH_HFLAG_BR 0x02000 /* branch to register (can't link TB) */ -+#define LARCH_HFLAG_LSX 0x1000000 -+#define LARCH_HFLAG_LASX 0x2000000 -+#define LARCH_HFLAG_LBT 0x40000000 -+ target_ulong btarget; /* Jump / branch target */ -+ target_ulong bcond; /* Branch condition (if needed) */ -+ -+ uint64_t insn_flags; /* Supported instruction set */ -+ int cpu_cfg[64]; -+ -+ /* Fields up to this point are cleared by a CPU reset */ -+ struct {} end_reset_fields; -+ -+ /* Fields from here on are preserved across CPU reset. */ -+#if !defined(CONFIG_USER_ONLY) -+ CPULOONGARCHTLBContext *tlb; -+#endif -+ -+ const loongarch_def_t *cpu_model; -+ void *irq[N_IRQS]; -+ QEMUTimer *timer; /* Internal timer */ -+ MemoryRegion *itc_tag; /* ITC Configuration Tags */ -+ target_ulong exception_base; /* ExceptionBase input to the core */ -+ struct { -+ uint64_t guest_addr; -+ } st; -+}; -+ -+ -+/* CPU can't have 0xFFFFFFFF APIC ID, use that value to distinguish -+ * that ID hasn't been set yet -+ */ -+#define UNASSIGNED_CPU_ID 0xFFFFFFFF -+ -+/** -+ * LOONGARCHCPU: -+ * @env: #CPULOONGARCHState -+ * -+ * A LOONGARCH CPU. -+ */ -+struct LOONGARCHCPU { -+ /*< private >*/ -+ CPUState parent_obj; -+ /*< public >*/ -+ CPUNegativeOffsetState neg; -+ CPULOONGARCHState env; -+ int32_t id; -+ int hotplugged; -+ uint8_t online_vcpus; -+ uint8_t is_migrate; -+ uint64_t counter_value; -+ uint32_t cpu_freq; -+ uint32_t count_ctl; -+ uint64_t pending_exceptions; -+ uint64_t pending_exceptions_clr; -+ uint64_t core_ext_ioisr[4]; -+ VMChangeStateEntry *cpuStateEntry; -+ int32_t node_id; /* NUMA node this CPU belongs to */ -+ int32_t core_id; -+ struct kvm_msrs *kvm_msr_buf; -+ /* 'compatible' string for this CPU for Linux device trees */ -+ const char *dtb_compatible; -+}; -+ -+static inline LOONGARCHCPU *loongarch_env_get_cpu(CPULOONGARCHState *env) -+{ -+ return container_of(env, LOONGARCHCPU, env); -+} -+ -+#define ENV_GET_CPU(e) CPU(loongarch_env_get_cpu(e)) -+ -+#define ENV_OFFSET offsetof(LOONGARCHCPU, env) -+ -+void loongarch_cpu_list(void); -+ -+#define cpu_signal_handler cpu_loongarch_signal_handler -+#define cpu_list loongarch_cpu_list -+ -+/* MMU modes definitions. We carefully match the indices with our -+ hflags layout. */ -+#define MMU_MODE0_SUFFIX _kernel -+#define MMU_MODE1_SUFFIX _super -+#define MMU_MODE2_SUFFIX _user -+#define MMU_MODE3_SUFFIX _error -+#define MMU_USER_IDX 3 -+ -+static inline int hflags_mmu_index(uint32_t hflags) -+{ -+ return hflags & LARCH_HFLAG_KSU; -+} -+ -+static inline int cpu_mmu_index(CPULOONGARCHState *env, bool ifetch) -+{ -+ return hflags_mmu_index(env->hflags); -+} -+ -+#include "exec/cpu-all.h" -+ -+/* Memory access type : -+ * may be needed for precise access rights control and precise exceptions. -+ */ -+enum { -+ /* 1 bit to define user level / supervisor access */ -+ ACCESS_USER = 0x00, -+ ACCESS_SUPER = 0x01, -+ /* 1 bit to indicate direction */ -+ ACCESS_STORE = 0x02, -+ /* Type of instruction that generated the access */ -+ ACCESS_CODE = 0x10, /* Code fetch access */ -+ ACCESS_INT = 0x20, /* Integer load/store access */ -+ ACCESS_FLOAT = 0x30, /* floating point load/store access */ -+}; -+ -+/* Exceptions */ -+enum { -+ EXCP_NONE = -1, -+ EXCP_RESET = 0, -+ EXCP_SRESET, -+ EXCP_DINT, -+ EXCP_NMI, -+ EXCP_EXT_INTERRUPT, /* 7 */ -+ EXCP_AdEL, -+ EXCP_AdES, -+ EXCP_TLBF, -+ EXCP_IBE, -+ EXCP_SYSCALL, -+ EXCP_BREAK, -+ EXCP_FPDIS, -+ EXCP_LSXDIS, -+ EXCP_LASXDIS, -+ EXCP_RI, -+ EXCP_OVERFLOW, -+ EXCP_TRAP, -+ EXCP_FPE, -+ EXCP_LTLBL, -+ EXCP_TLBL, -+ EXCP_TLBS, -+ EXCP_DBE, -+ EXCP_TLBXI, -+ EXCP_TLBRI, -+ EXCP_TLBPE, -+ EXCP_BTDIS, -+ -+ EXCP_LAST = EXCP_BTDIS, -+}; -+ -+/* -+ * This is an internally generated WAKE request line. -+ * It is driven by the CPU itself. Raised when the MT -+ * block wants to wake a VPE from an inactive state and -+ * cleared when VPE goes from active to inactive. -+ */ -+#define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 -+ -+int cpu_loongarch_signal_handler(int host_signum, void *pinfo, void *puc); -+ -+#define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU -+#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX -+#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU -+ -+/* helper.c */ -+target_ulong exception_resume_pc(CPULOONGARCHState *env); -+ -+/* gdbstub.c */ -+void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs); -+void mmu_init(CPULOONGARCHState *env, const loongarch_def_t *def); -+ -+static inline void cpu_get_tb_cpu_state(CPULOONGARCHState *env, target_ulong *pc, -+ target_ulong *cs_base, uint32_t *flags) -+{ -+ *pc = env->active_tc.PC; -+ *cs_base = 0; -+ *flags = env->hflags & (LARCH_HFLAG_TMASK | LARCH_HFLAG_BMASK); -+} -+ -+static inline bool cpu_refill_state(CPULOONGARCHState *env) -+{ -+ return env->CSR_TLBRERA & 0x1; -+} -+ -+extern const char * const regnames[]; -+extern const char * const fregnames[]; -+#endif /* LOONGARCH_CPU_H */ -diff --git a/target/loongarch64/csr_helper.c b/target/loongarch64/csr_helper.c -new file mode 100644 -index 000000000..182e59e92 ---- /dev/null -+++ b/target/loongarch64/csr_helper.c -@@ -0,0 +1,704 @@ -+/* -+ * loongarch tlb emulation helpers for qemu. -+ * -+ * Copyright (c) 2020 - 2021 -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu/main-loop.h" -+#include "cpu.h" -+#include "internal.h" -+#include "qemu/host-utils.h" -+#include "exec/helper-proto.h" -+#include "exec/exec-all.h" -+#include "exec/cpu_ldst.h" -+#include "sysemu/kvm.h" -+#include "hw/irq.h" -+#include "cpu-csr.h" -+#include "instmap.h" -+ -+#ifndef CONFIG_USER_ONLY -+target_ulong helper_csr_rdq(CPULOONGARCHState *env, uint64_t csr) -+{ -+ int64_t v; -+ -+#define CASE_CSR_RDQ(csr) \ -+ case LOONGARCH_CSR_ ## csr: \ -+ { \ -+ v = env->CSR_ ## csr; \ -+ break; \ -+ }; \ -+ -+ switch (csr) { -+ CASE_CSR_RDQ(CRMD) -+ CASE_CSR_RDQ(PRMD) -+ CASE_CSR_RDQ(EUEN) -+ CASE_CSR_RDQ(MISC) -+ CASE_CSR_RDQ(ECFG) -+ CASE_CSR_RDQ(ESTAT) -+ CASE_CSR_RDQ(ERA) -+ CASE_CSR_RDQ(BADV) -+ CASE_CSR_RDQ(BADI) -+ CASE_CSR_RDQ(EEPN) -+ CASE_CSR_RDQ(TLBIDX) -+ CASE_CSR_RDQ(TLBEHI) -+ CASE_CSR_RDQ(TLBELO0) -+ CASE_CSR_RDQ(TLBELO1) -+ CASE_CSR_RDQ(TLBWIRED) -+ CASE_CSR_RDQ(GTLBC) -+ CASE_CSR_RDQ(TRGP) -+ CASE_CSR_RDQ(ASID) -+ CASE_CSR_RDQ(PGDL) -+ CASE_CSR_RDQ(PGDH) -+ CASE_CSR_RDQ(PGD) -+ CASE_CSR_RDQ(PWCTL0) -+ CASE_CSR_RDQ(PWCTL1) -+ CASE_CSR_RDQ(STLBPGSIZE) -+ CASE_CSR_RDQ(RVACFG) -+ CASE_CSR_RDQ(CPUID) -+ CASE_CSR_RDQ(PRCFG1) -+ CASE_CSR_RDQ(PRCFG2) -+ CASE_CSR_RDQ(PRCFG3) -+ CASE_CSR_RDQ(KS0) -+ CASE_CSR_RDQ(KS1) -+ CASE_CSR_RDQ(KS2) -+ CASE_CSR_RDQ(KS3) -+ CASE_CSR_RDQ(KS4) -+ CASE_CSR_RDQ(KS5) -+ CASE_CSR_RDQ(KS6) -+ CASE_CSR_RDQ(KS7) -+ CASE_CSR_RDQ(KS8) -+ CASE_CSR_RDQ(TMID) -+ CASE_CSR_RDQ(TCFG) -+ case LOONGARCH_CSR_TVAL: -+ v = cpu_loongarch_get_stable_timer_ticks(env); -+ break; -+ CASE_CSR_RDQ(CNTC) -+ CASE_CSR_RDQ(TINTCLR) -+ CASE_CSR_RDQ(GSTAT) -+ CASE_CSR_RDQ(GCFG) -+ CASE_CSR_RDQ(GINTC) -+ CASE_CSR_RDQ(GCNTC) -+ CASE_CSR_RDQ(LLBCTL) -+ CASE_CSR_RDQ(IMPCTL1) -+ CASE_CSR_RDQ(IMPCTL2) -+ CASE_CSR_RDQ(GNMI) -+ CASE_CSR_RDQ(TLBRENT) -+ CASE_CSR_RDQ(TLBRBADV) -+ CASE_CSR_RDQ(TLBRERA) -+ CASE_CSR_RDQ(TLBRSAVE) -+ CASE_CSR_RDQ(TLBRELO0) -+ CASE_CSR_RDQ(TLBRELO1) -+ CASE_CSR_RDQ(TLBREHI) -+ CASE_CSR_RDQ(TLBRPRMD) -+ CASE_CSR_RDQ(ERRCTL) -+ CASE_CSR_RDQ(ERRINFO) -+ CASE_CSR_RDQ(ERRINFO1) -+ CASE_CSR_RDQ(ERRENT) -+ CASE_CSR_RDQ(ERRERA) -+ CASE_CSR_RDQ(ERRSAVE) -+ CASE_CSR_RDQ(CTAG) -+ CASE_CSR_RDQ(DMWIN0) -+ CASE_CSR_RDQ(DMWIN1) -+ CASE_CSR_RDQ(DMWIN2) -+ CASE_CSR_RDQ(DMWIN3) -+ CASE_CSR_RDQ(PERFCTRL0) -+ CASE_CSR_RDQ(PERFCNTR0) -+ CASE_CSR_RDQ(PERFCTRL1) -+ CASE_CSR_RDQ(PERFCNTR1) -+ CASE_CSR_RDQ(PERFCTRL2) -+ CASE_CSR_RDQ(PERFCNTR2) -+ CASE_CSR_RDQ(PERFCTRL3) -+ CASE_CSR_RDQ(PERFCNTR3) -+ /* debug */ -+ CASE_CSR_RDQ(MWPC) -+ CASE_CSR_RDQ(MWPS) -+ CASE_CSR_RDQ(DB0ADDR) -+ CASE_CSR_RDQ(DB0MASK) -+ CASE_CSR_RDQ(DB0CTL) -+ CASE_CSR_RDQ(DB0ASID) -+ CASE_CSR_RDQ(DB1ADDR) -+ CASE_CSR_RDQ(DB1MASK) -+ CASE_CSR_RDQ(DB1CTL) -+ CASE_CSR_RDQ(DB1ASID) -+ CASE_CSR_RDQ(DB2ADDR) -+ CASE_CSR_RDQ(DB2MASK) -+ CASE_CSR_RDQ(DB2CTL) -+ CASE_CSR_RDQ(DB2ASID) -+ CASE_CSR_RDQ(DB3ADDR) -+ CASE_CSR_RDQ(DB3MASK) -+ CASE_CSR_RDQ(DB3CTL) -+ CASE_CSR_RDQ(DB3ASID) -+ CASE_CSR_RDQ(FWPC) -+ CASE_CSR_RDQ(FWPS) -+ CASE_CSR_RDQ(IB0ADDR) -+ CASE_CSR_RDQ(IB0MASK) -+ CASE_CSR_RDQ(IB0CTL) -+ CASE_CSR_RDQ(IB0ASID) -+ CASE_CSR_RDQ(IB1ADDR) -+ CASE_CSR_RDQ(IB1MASK) -+ CASE_CSR_RDQ(IB1CTL) -+ CASE_CSR_RDQ(IB1ASID) -+ CASE_CSR_RDQ(IB2ADDR) -+ CASE_CSR_RDQ(IB2MASK) -+ CASE_CSR_RDQ(IB2CTL) -+ CASE_CSR_RDQ(IB2ASID) -+ CASE_CSR_RDQ(IB3ADDR) -+ CASE_CSR_RDQ(IB3MASK) -+ CASE_CSR_RDQ(IB3CTL) -+ CASE_CSR_RDQ(IB3ASID) -+ CASE_CSR_RDQ(IB4ADDR) -+ CASE_CSR_RDQ(IB4MASK) -+ CASE_CSR_RDQ(IB4CTL) -+ CASE_CSR_RDQ(IB4ASID) -+ CASE_CSR_RDQ(IB5ADDR) -+ CASE_CSR_RDQ(IB5MASK) -+ CASE_CSR_RDQ(IB5CTL) -+ CASE_CSR_RDQ(IB5ASID) -+ CASE_CSR_RDQ(IB6ADDR) -+ CASE_CSR_RDQ(IB6MASK) -+ CASE_CSR_RDQ(IB6CTL) -+ CASE_CSR_RDQ(IB6ASID) -+ CASE_CSR_RDQ(IB7ADDR) -+ CASE_CSR_RDQ(IB7MASK) -+ CASE_CSR_RDQ(IB7CTL) -+ CASE_CSR_RDQ(IB7ASID) -+ CASE_CSR_RDQ(DEBUG) -+ CASE_CSR_RDQ(DERA) -+ CASE_CSR_RDQ(DESAVE) -+ default : -+ assert(0); -+ } -+ -+#undef CASE_CSR_RDQ -+ compute_hflags(env); -+ return v; -+} -+ -+target_ulong helper_csr_wrq(CPULOONGARCHState *env, target_ulong val, -+ uint64_t csr) -+{ -+ int64_t old_v, v; -+ old_v = -1; -+ v = val; -+ -+#define CASE_CSR_WRQ(csr) \ -+ case LOONGARCH_CSR_ ## csr: \ -+ { \ -+ old_v = env->CSR_ ## csr; \ -+ env->CSR_ ## csr = v; \ -+ break; \ -+ }; \ -+ -+ switch (csr) { -+ CASE_CSR_WRQ(CRMD) -+ CASE_CSR_WRQ(PRMD) -+ CASE_CSR_WRQ(EUEN) -+ CASE_CSR_WRQ(MISC) -+ CASE_CSR_WRQ(ECFG) -+ CASE_CSR_WRQ(ESTAT) -+ CASE_CSR_WRQ(ERA) -+ CASE_CSR_WRQ(BADV) -+ CASE_CSR_WRQ(BADI) -+ CASE_CSR_WRQ(EEPN) -+ CASE_CSR_WRQ(TLBIDX) -+ CASE_CSR_WRQ(TLBEHI) -+ CASE_CSR_WRQ(TLBELO0) -+ CASE_CSR_WRQ(TLBELO1) -+ CASE_CSR_WRQ(TLBWIRED) -+ CASE_CSR_WRQ(GTLBC) -+ CASE_CSR_WRQ(TRGP) -+ CASE_CSR_WRQ(ASID) -+ CASE_CSR_WRQ(PGDL) -+ CASE_CSR_WRQ(PGDH) -+ CASE_CSR_WRQ(PGD) -+ CASE_CSR_WRQ(PWCTL0) -+ CASE_CSR_WRQ(PWCTL1) -+ CASE_CSR_WRQ(STLBPGSIZE) -+ CASE_CSR_WRQ(RVACFG) -+ CASE_CSR_WRQ(CPUID) -+ CASE_CSR_WRQ(PRCFG1) -+ CASE_CSR_WRQ(PRCFG2) -+ CASE_CSR_WRQ(PRCFG3) -+ CASE_CSR_WRQ(KS0) -+ CASE_CSR_WRQ(KS1) -+ CASE_CSR_WRQ(KS2) -+ CASE_CSR_WRQ(KS3) -+ CASE_CSR_WRQ(KS4) -+ CASE_CSR_WRQ(KS5) -+ CASE_CSR_WRQ(KS6) -+ CASE_CSR_WRQ(KS7) -+ CASE_CSR_WRQ(KS8) -+ CASE_CSR_WRQ(TMID) -+ case LOONGARCH_CSR_TCFG: -+ old_v = env->CSR_TCFG; -+ cpu_loongarch_store_stable_timer_config(env, v); -+ break; -+ CASE_CSR_WRQ(TVAL) -+ CASE_CSR_WRQ(CNTC) -+ case LOONGARCH_CSR_TINTCLR: -+ old_v = 0; -+ qemu_irq_lower(env->irq[IRQ_TIMER]); -+ break; -+ CASE_CSR_WRQ(GSTAT) -+ CASE_CSR_WRQ(GCFG) -+ CASE_CSR_WRQ(GINTC) -+ CASE_CSR_WRQ(GCNTC) -+ CASE_CSR_WRQ(LLBCTL) -+ CASE_CSR_WRQ(IMPCTL1) -+ case LOONGARCH_CSR_IMPCTL2: -+ if (v & CSR_IMPCTL2_MTLB) { -+ ls3a5k_flush_vtlb(env); -+ } -+ if (v & CSR_IMPCTL2_STLB) { -+ ls3a5k_flush_ftlb(env); -+ } -+ break; -+ CASE_CSR_WRQ(GNMI) -+ CASE_CSR_WRQ(TLBRENT) -+ CASE_CSR_WRQ(TLBRBADV) -+ CASE_CSR_WRQ(TLBRERA) -+ CASE_CSR_WRQ(TLBRSAVE) -+ CASE_CSR_WRQ(TLBRELO0) -+ CASE_CSR_WRQ(TLBRELO1) -+ CASE_CSR_WRQ(TLBREHI) -+ CASE_CSR_WRQ(TLBRPRMD) -+ CASE_CSR_WRQ(ERRCTL) -+ CASE_CSR_WRQ(ERRINFO) -+ CASE_CSR_WRQ(ERRINFO1) -+ CASE_CSR_WRQ(ERRENT) -+ CASE_CSR_WRQ(ERRERA) -+ CASE_CSR_WRQ(ERRSAVE) -+ CASE_CSR_WRQ(CTAG) -+ CASE_CSR_WRQ(DMWIN0) -+ CASE_CSR_WRQ(DMWIN1) -+ CASE_CSR_WRQ(DMWIN2) -+ CASE_CSR_WRQ(DMWIN3) -+ CASE_CSR_WRQ(PERFCTRL0) -+ CASE_CSR_WRQ(PERFCNTR0) -+ CASE_CSR_WRQ(PERFCTRL1) -+ CASE_CSR_WRQ(PERFCNTR1) -+ CASE_CSR_WRQ(PERFCTRL2) -+ CASE_CSR_WRQ(PERFCNTR2) -+ CASE_CSR_WRQ(PERFCTRL3) -+ CASE_CSR_WRQ(PERFCNTR3) -+ /* debug */ -+ CASE_CSR_WRQ(MWPC) -+ CASE_CSR_WRQ(MWPS) -+ CASE_CSR_WRQ(DB0ADDR) -+ CASE_CSR_WRQ(DB0MASK) -+ CASE_CSR_WRQ(DB0CTL) -+ CASE_CSR_WRQ(DB0ASID) -+ CASE_CSR_WRQ(DB1ADDR) -+ CASE_CSR_WRQ(DB1MASK) -+ CASE_CSR_WRQ(DB1CTL) -+ CASE_CSR_WRQ(DB1ASID) -+ CASE_CSR_WRQ(DB2ADDR) -+ CASE_CSR_WRQ(DB2MASK) -+ CASE_CSR_WRQ(DB2CTL) -+ CASE_CSR_WRQ(DB2ASID) -+ CASE_CSR_WRQ(DB3ADDR) -+ CASE_CSR_WRQ(DB3MASK) -+ CASE_CSR_WRQ(DB3CTL) -+ CASE_CSR_WRQ(DB3ASID) -+ CASE_CSR_WRQ(FWPC) -+ CASE_CSR_WRQ(FWPS) -+ CASE_CSR_WRQ(IB0ADDR) -+ CASE_CSR_WRQ(IB0MASK) -+ CASE_CSR_WRQ(IB0CTL) -+ CASE_CSR_WRQ(IB0ASID) -+ CASE_CSR_WRQ(IB1ADDR) -+ CASE_CSR_WRQ(IB1MASK) -+ CASE_CSR_WRQ(IB1CTL) -+ CASE_CSR_WRQ(IB1ASID) -+ CASE_CSR_WRQ(IB2ADDR) -+ CASE_CSR_WRQ(IB2MASK) -+ CASE_CSR_WRQ(IB2CTL) -+ CASE_CSR_WRQ(IB2ASID) -+ CASE_CSR_WRQ(IB3ADDR) -+ CASE_CSR_WRQ(IB3MASK) -+ CASE_CSR_WRQ(IB3CTL) -+ CASE_CSR_WRQ(IB3ASID) -+ CASE_CSR_WRQ(IB4ADDR) -+ CASE_CSR_WRQ(IB4MASK) -+ CASE_CSR_WRQ(IB4CTL) -+ CASE_CSR_WRQ(IB4ASID) -+ CASE_CSR_WRQ(IB5ADDR) -+ CASE_CSR_WRQ(IB5MASK) -+ CASE_CSR_WRQ(IB5CTL) -+ CASE_CSR_WRQ(IB5ASID) -+ CASE_CSR_WRQ(IB6ADDR) -+ CASE_CSR_WRQ(IB6MASK) -+ CASE_CSR_WRQ(IB6CTL) -+ CASE_CSR_WRQ(IB6ASID) -+ CASE_CSR_WRQ(IB7ADDR) -+ CASE_CSR_WRQ(IB7MASK) -+ CASE_CSR_WRQ(IB7CTL) -+ CASE_CSR_WRQ(IB7ASID) -+ CASE_CSR_WRQ(DEBUG) -+ CASE_CSR_WRQ(DERA) -+ CASE_CSR_WRQ(DESAVE) -+ default : -+ assert(0); -+ } -+ -+ if (csr == LOONGARCH_CSR_ASID) { -+ if (old_v != v) { -+ tlb_flush(CPU(loongarch_env_get_cpu(env))); -+ } -+ } -+ -+#undef CASE_CSR_WRQ -+ compute_hflags(env); -+ return old_v; -+} -+ -+target_ulong helper_csr_xchgq(CPULOONGARCHState *env, target_ulong val, -+ target_ulong mask, uint64_t csr) -+{ -+ target_ulong v, tmp; -+ v = val & mask; -+ -+#define CASE_CSR_XCHGQ(csr) \ -+ case LOONGARCH_CSR_ ## csr: \ -+ { \ -+ val = env->CSR_ ## csr; \ -+ env->CSR_ ## csr = (env->CSR_ ## csr) & (~mask); \ -+ env->CSR_ ## csr = (env->CSR_ ## csr) | v; \ -+ break; \ -+ }; \ -+ -+ switch (csr) { -+ CASE_CSR_XCHGQ(CRMD) -+ CASE_CSR_XCHGQ(PRMD) -+ CASE_CSR_XCHGQ(EUEN) -+ CASE_CSR_XCHGQ(MISC) -+ CASE_CSR_XCHGQ(ECFG) -+ case LOONGARCH_CSR_ESTAT: -+ val = env->CSR_ESTAT; -+ qatomic_and(&env->CSR_ESTAT, ~mask); -+ qatomic_or(&env->CSR_ESTAT, v); -+ break; -+ CASE_CSR_XCHGQ(ERA) -+ CASE_CSR_XCHGQ(BADV) -+ CASE_CSR_XCHGQ(BADI) -+ CASE_CSR_XCHGQ(EEPN) -+ CASE_CSR_XCHGQ(TLBIDX) -+ CASE_CSR_XCHGQ(TLBEHI) -+ CASE_CSR_XCHGQ(TLBELO0) -+ CASE_CSR_XCHGQ(TLBELO1) -+ CASE_CSR_XCHGQ(TLBWIRED) -+ CASE_CSR_XCHGQ(GTLBC) -+ CASE_CSR_XCHGQ(TRGP) -+ CASE_CSR_XCHGQ(ASID) -+ CASE_CSR_XCHGQ(PGDL) -+ CASE_CSR_XCHGQ(PGDH) -+ CASE_CSR_XCHGQ(PGD) -+ CASE_CSR_XCHGQ(PWCTL0) -+ CASE_CSR_XCHGQ(PWCTL1) -+ CASE_CSR_XCHGQ(STLBPGSIZE) -+ CASE_CSR_XCHGQ(RVACFG) -+ CASE_CSR_XCHGQ(CPUID) -+ CASE_CSR_XCHGQ(PRCFG1) -+ CASE_CSR_XCHGQ(PRCFG2) -+ CASE_CSR_XCHGQ(PRCFG3) -+ CASE_CSR_XCHGQ(KS0) -+ CASE_CSR_XCHGQ(KS1) -+ CASE_CSR_XCHGQ(KS2) -+ CASE_CSR_XCHGQ(KS3) -+ CASE_CSR_XCHGQ(KS4) -+ CASE_CSR_XCHGQ(KS5) -+ CASE_CSR_XCHGQ(KS6) -+ CASE_CSR_XCHGQ(KS7) -+ CASE_CSR_XCHGQ(KS8) -+ CASE_CSR_XCHGQ(TMID) -+ case LOONGARCH_CSR_TCFG: -+ val = env->CSR_TCFG; -+ tmp = val & ~mask; -+ tmp |= v; -+ cpu_loongarch_store_stable_timer_config(env, tmp); -+ break; -+ CASE_CSR_XCHGQ(TVAL) -+ CASE_CSR_XCHGQ(CNTC) -+ CASE_CSR_XCHGQ(TINTCLR) -+ CASE_CSR_XCHGQ(GSTAT) -+ CASE_CSR_XCHGQ(GCFG) -+ CASE_CSR_XCHGQ(GINTC) -+ CASE_CSR_XCHGQ(GCNTC) -+ CASE_CSR_XCHGQ(LLBCTL) -+ CASE_CSR_XCHGQ(IMPCTL1) -+ CASE_CSR_XCHGQ(IMPCTL2) -+ CASE_CSR_XCHGQ(GNMI) -+ CASE_CSR_XCHGQ(TLBRENT) -+ CASE_CSR_XCHGQ(TLBRBADV) -+ CASE_CSR_XCHGQ(TLBRERA) -+ CASE_CSR_XCHGQ(TLBRSAVE) -+ CASE_CSR_XCHGQ(TLBRELO0) -+ CASE_CSR_XCHGQ(TLBRELO1) -+ CASE_CSR_XCHGQ(TLBREHI) -+ CASE_CSR_XCHGQ(TLBRPRMD) -+ CASE_CSR_XCHGQ(ERRCTL) -+ CASE_CSR_XCHGQ(ERRINFO) -+ CASE_CSR_XCHGQ(ERRINFO1) -+ CASE_CSR_XCHGQ(ERRENT) -+ CASE_CSR_XCHGQ(ERRERA) -+ CASE_CSR_XCHGQ(ERRSAVE) -+ CASE_CSR_XCHGQ(CTAG) -+ CASE_CSR_XCHGQ(DMWIN0) -+ CASE_CSR_XCHGQ(DMWIN1) -+ CASE_CSR_XCHGQ(DMWIN2) -+ CASE_CSR_XCHGQ(DMWIN3) -+ CASE_CSR_XCHGQ(PERFCTRL0) -+ CASE_CSR_XCHGQ(PERFCNTR0) -+ CASE_CSR_XCHGQ(PERFCTRL1) -+ CASE_CSR_XCHGQ(PERFCNTR1) -+ CASE_CSR_XCHGQ(PERFCTRL2) -+ CASE_CSR_XCHGQ(PERFCNTR2) -+ CASE_CSR_XCHGQ(PERFCTRL3) -+ CASE_CSR_XCHGQ(PERFCNTR3) -+ /* debug */ -+ CASE_CSR_XCHGQ(MWPC) -+ CASE_CSR_XCHGQ(MWPS) -+ CASE_CSR_XCHGQ(DB0ADDR) -+ CASE_CSR_XCHGQ(DB0MASK) -+ CASE_CSR_XCHGQ(DB0CTL) -+ CASE_CSR_XCHGQ(DB0ASID) -+ CASE_CSR_XCHGQ(DB1ADDR) -+ CASE_CSR_XCHGQ(DB1MASK) -+ CASE_CSR_XCHGQ(DB1CTL) -+ CASE_CSR_XCHGQ(DB1ASID) -+ CASE_CSR_XCHGQ(DB2ADDR) -+ CASE_CSR_XCHGQ(DB2MASK) -+ CASE_CSR_XCHGQ(DB2CTL) -+ CASE_CSR_XCHGQ(DB2ASID) -+ CASE_CSR_XCHGQ(DB3ADDR) -+ CASE_CSR_XCHGQ(DB3MASK) -+ CASE_CSR_XCHGQ(DB3CTL) -+ CASE_CSR_XCHGQ(DB3ASID) -+ CASE_CSR_XCHGQ(FWPC) -+ CASE_CSR_XCHGQ(FWPS) -+ CASE_CSR_XCHGQ(IB0ADDR) -+ CASE_CSR_XCHGQ(IB0MASK) -+ CASE_CSR_XCHGQ(IB0CTL) -+ CASE_CSR_XCHGQ(IB0ASID) -+ CASE_CSR_XCHGQ(IB1ADDR) -+ CASE_CSR_XCHGQ(IB1MASK) -+ CASE_CSR_XCHGQ(IB1CTL) -+ CASE_CSR_XCHGQ(IB1ASID) -+ CASE_CSR_XCHGQ(IB2ADDR) -+ CASE_CSR_XCHGQ(IB2MASK) -+ CASE_CSR_XCHGQ(IB2CTL) -+ CASE_CSR_XCHGQ(IB2ASID) -+ CASE_CSR_XCHGQ(IB3ADDR) -+ CASE_CSR_XCHGQ(IB3MASK) -+ CASE_CSR_XCHGQ(IB3CTL) -+ CASE_CSR_XCHGQ(IB3ASID) -+ CASE_CSR_XCHGQ(IB4ADDR) -+ CASE_CSR_XCHGQ(IB4MASK) -+ CASE_CSR_XCHGQ(IB4CTL) -+ CASE_CSR_XCHGQ(IB4ASID) -+ CASE_CSR_XCHGQ(IB5ADDR) -+ CASE_CSR_XCHGQ(IB5MASK) -+ CASE_CSR_XCHGQ(IB5CTL) -+ CASE_CSR_XCHGQ(IB5ASID) -+ CASE_CSR_XCHGQ(IB6ADDR) -+ CASE_CSR_XCHGQ(IB6MASK) -+ CASE_CSR_XCHGQ(IB6CTL) -+ CASE_CSR_XCHGQ(IB6ASID) -+ CASE_CSR_XCHGQ(IB7ADDR) -+ CASE_CSR_XCHGQ(IB7MASK) -+ CASE_CSR_XCHGQ(IB7CTL) -+ CASE_CSR_XCHGQ(IB7ASID) -+ CASE_CSR_XCHGQ(DEBUG) -+ CASE_CSR_XCHGQ(DERA) -+ CASE_CSR_XCHGQ(DESAVE) -+ default : -+ assert(0); -+ } -+ -+#undef CASE_CSR_XCHGQ -+ compute_hflags(env); -+ return val; -+} -+ -+static target_ulong confbus_addr(CPULOONGARCHState *env, int cpuid, -+ target_ulong csr_addr) -+{ -+ target_ulong addr; -+ target_ulong node_addr; -+ int cores_per_node = ((0x60018 >> 3) & 0xff) + 1; -+ -+ switch (cores_per_node) { -+ case 4: -+ assert(cpuid < 64); -+ node_addr = ((target_ulong)(cpuid & 0x3c) << 42); -+ break; -+ case 8: -+ assert(cpuid < 128); -+ node_addr = ((target_ulong)(cpuid & 0x78) << 41) + -+ ((target_ulong)(cpuid & 0x4) << 14); -+ break; -+ case 16: -+ assert(cpuid < 256); -+ node_addr = ((target_ulong)(cpuid & 0xf0) << 40) + -+ ((target_ulong)(cpuid & 0xc) << 14); -+ break; -+ default: -+ assert(0); -+ break; -+ } -+ -+ /* -+ * per core address -+ *0x10xx => ipi -+ * 0x18xx => extioi isr -+ */ -+ if (((csr_addr & 0xff00) == 0x1000)) { -+ addr = (csr_addr & 0xff) + (target_ulong)(cpuid << 8); -+ addr = 0x800000001f000000UL + addr; -+ return addr; -+ } else if ((csr_addr & 0xff00) == 0x1800) { -+ addr = (csr_addr & 0xff) + ((target_ulong)(cpuid << 8)); -+ addr = 0x800000001f020000UL + addr; -+ return addr; -+ } else if ((csr_addr & 0xff00) >= 0x1400 && (csr_addr & 0xff00) < 0x1d00) { -+ addr = 0x800000001f010000UL + ((csr_addr & 0xfff) - 0x400); -+ return addr; -+ } else if (csr_addr == 0x408) { -+ addr = csr_addr; -+ } else { -+ addr = csr_addr + node_addr; -+ } -+ -+ addr = 0x800000001fe00000UL + addr; -+ return addr; -+} -+ -+void helper_iocsr(CPULOONGARCHState *env, target_ulong r_addr, -+ target_ulong r_val, uint32_t op) -+{ -+ target_ulong addr; -+ target_ulong val = env->active_tc.gpr[r_val]; -+ int mask; -+ -+ addr = confbus_addr(env, CPU(loongarch_env_get_cpu(env))->cpu_index, -+ env->active_tc.gpr[r_addr]); -+ -+ switch (env->active_tc.gpr[r_addr]) { -+ /* IPI send */ -+ case 0x1040: -+ if (op != OPC_LARCH_ST_W) { -+ return; -+ } -+ op = OPC_LARCH_ST_W; -+ break; -+ -+ /* Mail send */ -+ case 0x1048: -+ if (op != OPC_LARCH_ST_D) { -+ return; -+ } -+ op = OPC_LARCH_ST_D; -+ break; -+ -+ /* ANY send */ -+ case 0x1158: -+ if (op != OPC_LARCH_ST_D) { -+ return; -+ } -+ addr = confbus_addr(env, (val >> 16) & 0x3ff, val & 0xffff); -+ mask = (val >> 27) & 0xf; -+ val = (val >> 32); -+ switch (mask) { -+ case 0: -+ op = OPC_LARCH_ST_W; -+ break; -+ case 0x7: -+ op = OPC_LARCH_ST_B; -+ addr += 3; -+ val >>= 24; -+ break; -+ case 0xb: -+ op = OPC_LARCH_ST_B; -+ addr += 2; -+ val >>= 16; -+ break; -+ case 0xd: -+ op = OPC_LARCH_ST_B; -+ addr += 1; -+ val >>= 8; -+ break; -+ case 0xe: -+ op = OPC_LARCH_ST_B; -+ break; -+ case 0xc: -+ op = OPC_LARCH_ST_H; -+ break; -+ case 0x3: -+ op = OPC_LARCH_ST_H; -+ addr += 2; -+ val >>= 16; -+ break; -+ default: -+ qemu_log("Unsupported any_send mask0x%x\n", mask); -+ break; -+ } -+ break; -+ -+ default: -+ break; -+ } -+ -+ switch (op) { -+ case OPC_LARCH_LD_D: -+ env->active_tc.gpr[r_val] = cpu_ldq_data_ra(env, addr, -+ GETPC()); -+ break; -+ case OPC_LARCH_LD_W: -+ env->active_tc.gpr[r_val] = cpu_ldl_data_ra(env, addr, -+ GETPC()); -+ break; -+ case OPC_LARCH_LD_H: -+ assert(0); -+ break; -+ case OPC_LARCH_LD_B: -+ assert(0); -+ break; -+ case OPC_LARCH_ST_D: -+ cpu_stq_data_ra(env, addr, val, GETPC()); -+ break; -+ case OPC_LARCH_ST_W: -+ cpu_stl_data_ra(env, addr, val, GETPC()); -+ break; -+ case OPC_LARCH_ST_H: -+ cpu_stb_data_ra(env, addr, val, GETPC()); -+ break; -+ case OPC_LARCH_ST_B: -+ cpu_stb_data_ra(env, addr, val, GETPC()); -+ break; -+ default: -+ qemu_log("Unknown op 0x%x", op); -+ assert(0); -+ } -+} -+#endif -+ -+target_ulong helper_cpucfg(CPULOONGARCHState *env, target_ulong rj) -+{ -+ return 0; -+} -+ -+ -diff --git a/target/loongarch64/fpu.c b/target/loongarch64/fpu.c -new file mode 100644 -index 000000000..795458205 ---- /dev/null -+++ b/target/loongarch64/fpu.c -@@ -0,0 +1,28 @@ -+/* -+ * loongarch float point emulation helpers for qemu. -+ * -+ * Copyright (c) 2020-2021 -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+#include "qemu/osdep.h" -+#include "fpu/softfloat.h" -+ -+/* convert loongarch rounding mode in fcsr0 to IEEE library */ -+unsigned int ieee_rm[] = { -+ float_round_nearest_even, -+ float_round_to_zero, -+ float_round_up, -+ float_round_down -+}; -diff --git a/target/loongarch64/fpu_helper.c b/target/loongarch64/fpu_helper.c -new file mode 100644 -index 000000000..42d7f05ca ---- /dev/null -+++ b/target/loongarch64/fpu_helper.c -@@ -0,0 +1,952 @@ -+/* -+ * loongarch float point emulation helpers for qemu. -+ * -+ * Copyright (c) 2020-2021 -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+#include "qemu/osdep.h" -+#include "cpu.h" -+#include "internal.h" -+#include "qemu/host-utils.h" -+#include "exec/helper-proto.h" -+#include "exec/exec-all.h" -+#include "fpu/softfloat.h" -+ -+#define FP_TO_INT32_OVERFLOW 0x7fffffff -+#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL -+ -+#define FLOAT_CLASS_SIGNALING_NAN 0x001 -+#define FLOAT_CLASS_QUIET_NAN 0x002 -+#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 -+#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008 -+#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 -+#define FLOAT_CLASS_NEGATIVE_ZERO 0x020 -+#define FLOAT_CLASS_POSITIVE_INFINITY 0x040 -+#define FLOAT_CLASS_POSITIVE_NORMAL 0x080 -+#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 -+#define FLOAT_CLASS_POSITIVE_ZERO 0x200 -+ -+target_ulong helper_movfcsr2gr(CPULOONGARCHState *env, uint32_t reg) -+{ -+ target_ulong r = 0; -+ -+ switch (reg) { -+ case 0: -+ r = (uint32_t)env->active_fpu.fcsr0; -+ break; -+ case 1: -+ r = (env->active_fpu.fcsr0 & FCSR0_M1); -+ break; -+ case 2: -+ r = (env->active_fpu.fcsr0 & FCSR0_M2); -+ break; -+ case 3: -+ r = (env->active_fpu.fcsr0 & FCSR0_M3); -+ break; -+ case 16: -+ r = (uint32_t)env->active_fpu.vcsr16; -+ break; -+ default: -+ printf("%s: warning, fcsr '%d' not supported\n", __func__, reg); -+ assert(0); -+ break; -+ } -+ -+ return r; -+} -+ -+void helper_movgr2fcsr(CPULOONGARCHState *env, target_ulong arg1, -+ uint32_t fcsr, uint32_t rj) -+{ -+ switch (fcsr) { -+ case 0: -+ env->active_fpu.fcsr0 = arg1; -+ break; -+ case 1: -+ env->active_fpu.fcsr0 = (arg1 & FCSR0_M1) | -+ (env->active_fpu.fcsr0 & ~FCSR0_M1); -+ break; -+ case 2: -+ env->active_fpu.fcsr0 = (arg1 & FCSR0_M2) | -+ (env->active_fpu.fcsr0 & ~FCSR0_M2); -+ break; -+ case 3: -+ env->active_fpu.fcsr0 = (arg1 & FCSR0_M3) | -+ (env->active_fpu.fcsr0 & ~FCSR0_M3); -+ break; -+ case 16: -+ env->active_fpu.vcsr16 = arg1; -+ break; -+ default: -+ printf("%s: warning, fcsr '%d' not supported\n", __func__, fcsr); -+ assert(0); -+ break; -+ } -+ restore_fp_status(env); -+ set_float_exception_flags(0, &env->active_fpu.fp_status); -+} -+ -+void helper_movreg2cf(CPULOONGARCHState *env, uint32_t cd, target_ulong src) -+{ -+ env->active_fpu.cf[cd & 0x7] = src & 0x1; -+} -+ -+void helper_movreg2cf_i32(CPULOONGARCHState *env, uint32_t cd, uint32_t src) -+{ -+ env->active_fpu.cf[cd & 0x7] = src & 0x1; -+} -+ -+void helper_movreg2cf_i64(CPULOONGARCHState *env, uint32_t cd, uint64_t src) -+{ -+ env->active_fpu.cf[cd & 0x7] = src & 0x1; -+} -+ -+target_ulong helper_movcf2reg(CPULOONGARCHState *env, uint32_t cj) -+{ -+ return (target_ulong)env->active_fpu.cf[cj & 0x7]; -+} -+ -+int ieee_ex_to_loongarch(int xcpt) -+{ -+ int ret = 0; -+ if (xcpt) { -+ if (xcpt & float_flag_invalid) { -+ ret |= FP_INVALID; -+ } -+ if (xcpt & float_flag_overflow) { -+ ret |= FP_OVERFLOW; -+ } -+ if (xcpt & float_flag_underflow) { -+ ret |= FP_UNDERFLOW; -+ } -+ if (xcpt & float_flag_divbyzero) { -+ ret |= FP_DIV0; -+ } -+ if (xcpt & float_flag_inexact) { -+ ret |= FP_INEXACT; -+ } -+ } -+ return ret; -+} -+ -+static inline void update_fcsr0(CPULOONGARCHState *env, uintptr_t pc) -+{ -+ int tmp = ieee_ex_to_loongarch(get_float_exception_flags( -+ &env->active_fpu.fp_status)); -+ -+ SET_FP_CAUSE(env->active_fpu.fcsr0, tmp); -+ if (tmp) { -+ set_float_exception_flags(0, &env->active_fpu.fp_status); -+ -+ if (GET_FP_ENABLE(env->active_fpu.fcsr0) & tmp) { -+ do_raise_exception(env, EXCP_FPE, pc); -+ } else { -+ UPDATE_FP_FLAGS(env->active_fpu.fcsr0, tmp); -+ } -+ } -+} -+ -+/* unary operations, modifying fp status */ -+uint64_t helper_float_sqrt_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt0; -+} -+ -+uint32_t helper_float_sqrt_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst0; -+} -+ -+uint64_t helper_float_cvtd_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint64_t helper_float_cvtd_w(CPULOONGARCHState *env, uint32_t wt0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint64_t helper_float_cvtd_l(CPULOONGARCHState *env, uint64_t dt0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint64_t helper_float_cvt_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_cvt_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_cvts_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t fst2; -+ -+ fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint32_t helper_float_cvts_w(CPULOONGARCHState *env, uint32_t wt0) -+{ -+ uint32_t fst2; -+ -+ fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint32_t helper_float_cvts_l(CPULOONGARCHState *env, uint64_t dt0) -+{ -+ uint32_t fst2; -+ -+ fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint32_t helper_float_cvt_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_cvt_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_round_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_nearest_even, -+ &env->active_fpu.fp_status); -+ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_round_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_nearest_even, -+ &env->active_fpu.fp_status); -+ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_round_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_nearest_even, -+ &env->active_fpu.fp_status); -+ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_round_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_nearest_even, -+ &env->active_fpu.fp_status); -+ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_trunc_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float64_to_int64_round_to_zero(fdt0, -+ &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_trunc_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_trunc_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_trunc_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_ceil_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); -+ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_ceil_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); -+ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_ceil_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); -+ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_ceil_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); -+ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_floor_l_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); -+ dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint64_t helper_float_floor_l_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint64_t dt2; -+ -+ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); -+ dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ dt2 = FP_TO_INT64_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_floor_w_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); -+ wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint32_t helper_float_floor_w_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); -+ wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); -+ restore_rounding_mode(env); -+ if (get_float_exception_flags(&env->active_fpu.fp_status) -+ & (float_flag_invalid | float_flag_overflow)) { -+ wt2 = FP_TO_INT32_OVERFLOW; -+ } -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+/* unary operations, not modifying fp status */ -+#define FLOAT_UNOP(name) \ -+uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \ -+{ \ -+ return float64_ ## name(fdt0); \ -+} \ -+uint32_t helper_float_ ## name ## _s(uint32_t fst0) \ -+{ \ -+ return float32_ ## name(fst0); \ -+} -+ -+FLOAT_UNOP(abs) -+FLOAT_UNOP(chs) -+#undef FLOAT_UNOP -+ -+uint64_t helper_float_recip_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint32_t helper_float_recip_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t fst2; -+ -+ fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint64_t helper_float_rsqrt_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t fdt2; -+ -+ fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status); -+ fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdt2; -+} -+ -+uint32_t helper_float_rsqrt_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t fst2; -+ -+ fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status); -+ fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fst2; -+} -+ -+uint32_t helper_float_rint_s(CPULOONGARCHState *env, uint32_t fs) -+{ -+ uint32_t fdret; -+ -+ fdret = float32_round_to_int(fs, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdret; -+} -+ -+uint64_t helper_float_rint_d(CPULOONGARCHState *env, uint64_t fs) -+{ -+ uint64_t fdret; -+ -+ fdret = float64_round_to_int(fs, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return fdret; -+} -+ -+#define FLOAT_CLASS(name, bits) \ -+uint ## bits ## _t float_ ## name(uint ## bits ## _t arg, \ -+ float_status *status) \ -+{ \ -+ if (float ## bits ## _is_signaling_nan(arg, status)) { \ -+ return FLOAT_CLASS_SIGNALING_NAN; \ -+ } else if (float ## bits ## _is_quiet_nan(arg, status)) { \ -+ return FLOAT_CLASS_QUIET_NAN; \ -+ } else if (float ## bits ## _is_neg(arg)) { \ -+ if (float ## bits ## _is_infinity(arg)) { \ -+ return FLOAT_CLASS_NEGATIVE_INFINITY; \ -+ } else if (float ## bits ## _is_zero(arg)) { \ -+ return FLOAT_CLASS_NEGATIVE_ZERO; \ -+ } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ -+ return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ -+ } else { \ -+ return FLOAT_CLASS_NEGATIVE_NORMAL; \ -+ } \ -+ } else { \ -+ if (float ## bits ## _is_infinity(arg)) { \ -+ return FLOAT_CLASS_POSITIVE_INFINITY; \ -+ } else if (float ## bits ## _is_zero(arg)) { \ -+ return FLOAT_CLASS_POSITIVE_ZERO; \ -+ } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ -+ return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ -+ } else { \ -+ return FLOAT_CLASS_POSITIVE_NORMAL; \ -+ } \ -+ } \ -+} \ -+ \ -+uint ## bits ## _t helper_float_ ## name(CPULOONGARCHState *env, \ -+ uint ## bits ## _t arg) \ -+{ \ -+ return float_ ## name(arg, &env->active_fpu.fp_status); \ -+} -+ -+FLOAT_CLASS(class_s, 32) -+FLOAT_CLASS(class_d, 64) -+#undef FLOAT_CLASS -+ -+/* binary operations */ -+#define FLOAT_BINOP(name) \ -+uint64_t helper_float_ ## name ## _d(CPULOONGARCHState *env, \ -+ uint64_t fdt0, uint64_t fdt1) \ -+{ \ -+ uint64_t dt2; \ -+ \ -+ dt2 = float64_ ## name(fdt0, fdt1, &env->active_fpu.fp_status);\ -+ update_fcsr0(env, GETPC()); \ -+ return dt2; \ -+} \ -+ \ -+uint32_t helper_float_ ## name ## _s(CPULOONGARCHState *env, \ -+ uint32_t fst0, uint32_t fst1) \ -+{ \ -+ uint32_t wt2; \ -+ \ -+ wt2 = float32_ ## name(fst0, fst1, &env->active_fpu.fp_status);\ -+ update_fcsr0(env, GETPC()); \ -+ return wt2; \ -+} -+ -+FLOAT_BINOP(add) -+FLOAT_BINOP(sub) -+FLOAT_BINOP(mul) -+FLOAT_BINOP(div) -+#undef FLOAT_BINOP -+ -+uint64_t helper_float_exp2_d(CPULOONGARCHState *env, -+ uint64_t fdt0, uint64_t fdt1) -+{ -+ uint64_t dt2; -+ int64_t n = (int64_t)fdt1; -+ -+ dt2 = float64_scalbn(fdt0, -+ n > 0x1000 ? 0x1000 : -+ n < -0x1000 ? -0x1000 : n, -+ &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+uint32_t helper_float_exp2_s(CPULOONGARCHState *env, -+ uint32_t fst0, uint32_t fst1) -+{ -+ uint32_t wt2; -+ int32_t n = (int32_t)fst1; -+ -+ wt2 = float32_scalbn(fst0, -+ n > 0x200 ? 0x200 : -+ n < -0x200 ? -0x200 : n, -+ &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+#define FLOAT_MINMAX(name, bits, minmaxfunc) \ -+uint ## bits ## _t helper_float_ ## name(CPULOONGARCHState *env, \ -+ uint ## bits ## _t fs, \ -+ uint ## bits ## _t ft) \ -+{ \ -+ uint ## bits ## _t fdret; \ -+ \ -+ fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ -+ &env->active_fpu.fp_status); \ -+ update_fcsr0(env, GETPC()); \ -+ return fdret; \ -+} -+ -+FLOAT_MINMAX(max_s, 32, maxnum) -+FLOAT_MINMAX(max_d, 64, maxnum) -+FLOAT_MINMAX(maxa_s, 32, maxnummag) -+FLOAT_MINMAX(maxa_d, 64, maxnummag) -+ -+FLOAT_MINMAX(min_s, 32, minnum) -+FLOAT_MINMAX(min_d, 64, minnum) -+FLOAT_MINMAX(mina_s, 32, minnummag) -+FLOAT_MINMAX(mina_d, 64, minnummag) -+#undef FLOAT_MINMAX -+ -+#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ -+uint ## bits ## _t helper_float_ ## name(CPULOONGARCHState *env, \ -+ uint ## bits ## _t fs, \ -+ uint ## bits ## _t ft, \ -+ uint ## bits ## _t fd) \ -+{ \ -+ uint ## bits ## _t fdret; \ -+ \ -+ fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ -+ &env->active_fpu.fp_status); \ -+ update_fcsr0(env, GETPC()); \ -+ return fdret; \ -+} -+ -+FLOAT_FMADDSUB(maddf_s, 32, 0) -+FLOAT_FMADDSUB(maddf_d, 64, 0) -+FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_c) -+FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_c) -+FLOAT_FMADDSUB(nmaddf_s, 32, float_muladd_negate_result) -+FLOAT_FMADDSUB(nmaddf_d, 64, float_muladd_negate_result) -+FLOAT_FMADDSUB(nmsubf_s, 32, float_muladd_negate_result | float_muladd_negate_c) -+FLOAT_FMADDSUB(nmsubf_d, 64, float_muladd_negate_result | float_muladd_negate_c) -+#undef FLOAT_FMADDSUB -+ -+/* compare operations */ -+#define FOP_CONDN_D(op, cond) \ -+uint64_t helper_cmp_d_ ## op(CPULOONGARCHState *env, uint64_t fdt0, \ -+ uint64_t fdt1) \ -+{ \ -+ uint64_t c; \ -+ c = cond; \ -+ update_fcsr0(env, GETPC()); \ -+ if (c) { \ -+ return -1; \ -+ } else { \ -+ return 0; \ -+ } \ -+} -+ -+/* -+ * NOTE: the comma operator will make "cond" to eval to false, -+ * but float64_unordered_quiet() is still called. -+ */ -+FOP_CONDN_D(af, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status), 0)) -+FOP_CONDN_D(un, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(eq, (float64_eq_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_eq_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(lt, (float64_lt_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(le, (float64_le_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_le_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+/* -+ * NOTE: the comma operator will make "cond" to eval to false, -+ * but float64_unordered() is still called. -+ */ -+FOP_CONDN_D(saf, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status), 0)) -+FOP_CONDN_D(sun, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(seq, (float64_eq(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_eq(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(slt, (float64_lt(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sle, (float64_le(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_le(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(or, (float64_le_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_le_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(une, (float64_unordered_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(ne, (float64_lt_quiet(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt_quiet(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sor, (float64_le(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_le(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_D(sne, (float64_lt(fdt1, fdt0, -+ &env->active_fpu.fp_status) -+ || float64_lt(fdt0, fdt1, -+ &env->active_fpu.fp_status))) -+ -+#define FOP_CONDN_S(op, cond) \ -+uint32_t helper_cmp_s_ ## op(CPULOONGARCHState *env, uint32_t fst0, \ -+ uint32_t fst1) \ -+{ \ -+ uint64_t c; \ -+ c = cond; \ -+ update_fcsr0(env, GETPC()); \ -+ if (c) { \ -+ return -1; \ -+ } else { \ -+ return 0; \ -+ } \ -+} -+ -+/* -+ * NOTE: the comma operator will make "cond" to eval to false, -+ * but float32_unordered_quiet() is still called. -+ */ -+FOP_CONDN_S(af, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status), 0)) -+FOP_CONDN_S(un, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(eq, (float32_eq_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(ueq, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_eq_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(lt, (float32_lt_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(ult, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(le, (float32_le_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(ule, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_le_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+/* -+ * NOTE: the comma operator will make "cond" to eval to false, -+ * but float32_unordered() is still called. -+ */ -+FOP_CONDN_S(saf, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status), 0)) -+FOP_CONDN_S(sun, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(seq, (float32_eq(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_eq(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(slt, (float32_lt(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sle, (float32_le(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_le(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(or, (float32_le_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_le_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(une, (float32_unordered_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(ne, (float32_lt_quiet(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt_quiet(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sor, (float32_le(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_le(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt(fst0, fst1, -+ &env->active_fpu.fp_status))) -+FOP_CONDN_S(sne, (float32_lt(fst1, fst0, -+ &env->active_fpu.fp_status) -+ || float32_lt(fst0, fst1, -+ &env->active_fpu.fp_status))) -+ -+uint32_t helper_float_logb_s(CPULOONGARCHState *env, uint32_t fst0) -+{ -+ uint32_t wt2; -+ -+ wt2 = float32_log2(fst0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return wt2; -+} -+ -+uint64_t helper_float_logb_d(CPULOONGARCHState *env, uint64_t fdt0) -+{ -+ uint64_t dt2; -+ -+ dt2 = float64_log2(fdt0, &env->active_fpu.fp_status); -+ update_fcsr0(env, GETPC()); -+ return dt2; -+} -+ -+target_ulong helper_fsel(CPULOONGARCHState *env, target_ulong fj, -+ target_ulong fk, uint32_t ca) -+{ -+ if (env->active_fpu.cf[ca & 0x7]) { -+ return fk; -+ } else { -+ return fj; -+ } -+} -diff --git a/target/loongarch64/fpu_helper.h b/target/loongarch64/fpu_helper.h -new file mode 100644 -index 000000000..b6898c2e9 ---- /dev/null -+++ b/target/loongarch64/fpu_helper.h -@@ -0,0 +1,129 @@ -+/* loongarch internal definitions and helpers -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef LOONGARCH_FPU_H -+#define LOONGARCH_FPU_H -+ -+#include "cpu-csr.h" -+ -+ -+extern const struct loongarch_def_t loongarch_defs[]; -+extern const int loongarch_defs_number; -+ -+enum CPULSXDataFormat { -+ DF_BYTE = 0, -+ DF_HALF, -+ DF_WORD, -+ DF_DOUBLE, -+ DF_QUAD -+}; -+ -+void loongarch_cpu_do_interrupt(CPUState *cpu); -+bool loongarch_cpu_exec_interrupt(CPUState *cpu, int int_req); -+void loongarch_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, -+ MMUAccessType access_type, -+ int mmu_idx, uintptr_t retaddr) QEMU_NORETURN; -+ -+#if !defined(CONFIG_USER_ONLY) -+ -+typedef struct r4k_tlb_t r4k_tlb_t; -+struct r4k_tlb_t { -+ target_ulong VPN; -+ uint32_t PageMask; -+ uint16_t ASID; -+ unsigned int G:1; -+ unsigned int C0:3; -+ unsigned int C1:3; -+ unsigned int V0:1; -+ unsigned int V1:1; -+ unsigned int D0:1; -+ unsigned int D1:1; -+ unsigned int XI0:1; -+ unsigned int XI1:1; -+ unsigned int RI0:1; -+ unsigned int RI1:1; -+ unsigned int EHINV:1; -+ uint64_t PPN[2]; -+}; -+ -+int no_mmu_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type); -+int fixed_mmu_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type); -+int r4k_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type); -+ -+/* loongarch 3a5000 tlb helper function : lisa csr */ -+int ls3a5k_map_address(CPULOONGARCHState *env, hwaddr *physical, -+ int *prot, target_ulong address, -+ int rw, int access_type); -+void ls3a5k_helper_tlbwr(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbfill(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbsrch(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbrd(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbclr(CPULOONGARCHState *env); -+void ls3a5k_helper_tlbflush(CPULOONGARCHState *env); -+void ls3a5k_invalidate_tlb(CPULOONGARCHState *env, int idx); -+void ls3a5k_helper_invtlb(CPULOONGARCHState *env, target_ulong addr, -+ target_ulong info, int op); -+void ls3a5k_flush_vtlb(CPULOONGARCHState *env); -+void ls3a5k_flush_ftlb(CPULOONGARCHState *env); -+/*void loongarch_cpu_unassigned_access(CPUState *cpu, hwaddr addr, -+ bool is_write, bool is_exec, int unused, -+ unsigned size); -+*/ -+hwaddr cpu_loongarch_translate_address(CPULOONGARCHState *env, target_ulong address, -+ int rw); -+#endif -+ -+#define cpu_signal_handler cpu_loongarch_signal_handler -+ -+ -+static inline bool cpu_loongarch_hw_interrupts_enabled(CPULOONGARCHState *env) -+{ -+ bool ret = 0; -+ -+ ret = env->CSR_CRMD & (1 << CSR_CRMD_IE_SHIFT); -+ -+ return ret; -+} -+ -+ -+void loongarch_tcg_init(void); -+ -+ -+/* helper.c */ -+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, -+ MMUAccessType access_type, int mmu_idx, -+ bool probe, uintptr_t retaddr); -+ -+/* op_helper.c */ -+uint32_t float_class_s(uint32_t arg, float_status *fst); -+uint64_t float_class_d(uint64_t arg, float_status *fst); -+ -+int ieee_ex_to_loongarch(int xcpt); -+void update_pagemask(CPULOONGARCHState *env, target_ulong arg1, int32_t *pagemask); -+ -+void cpu_loongarch_tlb_flush(CPULOONGARCHState *env); -+void sync_c0_status(CPULOONGARCHState *env, CPULOONGARCHState *cpu, int tc); -+ -+void QEMU_NORETURN do_raise_exception_err(CPULOONGARCHState *env, uint32_t exception, -+ int error_code, uintptr_t pc); -+int loongarch_read_qxfer(CPUState *cs, const char *annex, -+ uint8_t *read_buf, -+ unsigned long offset, unsigned long len); -+int loongarch_write_qxfer(CPUState *cs, const char *annex, -+ const uint8_t *write_buf, -+ unsigned long offset, unsigned long len); -+ -+static inline void QEMU_NORETURN do_raise_exception(CPULOONGARCHState *env, -+ uint32_t exception, -+ uintptr_t pc) -+{ -+ do_raise_exception_err(env, exception, 0, pc); -+} -+ -+#endif -diff --git a/target/loongarch64/gdbstub.c b/target/loongarch64/gdbstub.c -new file mode 100644 -index 000000000..4013178f4 ---- /dev/null -+++ b/target/loongarch64/gdbstub.c -@@ -0,0 +1,109 @@ -+/* -+ * LOONGARCH gdb server stub -+ * -+ * Copyright (c) 2003-2005 Fabrice Bellard -+ * Copyright (c) 2013 SUSE LINUX Products GmbH -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+#include "qemu/osdep.h" -+#include "qemu-common.h" -+#include "cpu.h" -+#include "internal.h" -+#include "exec/gdbstub.h" -+#ifdef CONFIG_TCG -+#include "exec/helper-proto.h" -+#endif -+int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ if (0 <= n && n < 32) { -+ return gdb_get_regl(mem_buf, env->active_tc.gpr[n]); -+ } else if (n == 32) { -+ return gdb_get_regl(mem_buf, env->active_tc.PC); -+ } -+ return 0; -+} -+ -+int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ target_ulong tmp = ldtul_p(mem_buf); -+ -+ if (0 <= n && n < 32) { -+ return env->active_tc.gpr[n] = tmp, sizeof(target_ulong); -+ } else if (n == 32) { -+ return env->active_tc.PC = tmp, sizeof(target_ulong); -+ } -+ return 0; -+} -+ -+static int loongarch_gdb_get_fpu(CPULOONGARCHState *env, GByteArray *mem_buf, int n) -+{ -+ if (0 <= n && n < 32) { -+ return gdb_get_reg64(mem_buf, env->active_fpu.fpr[n].d); -+ } else if (32 <= n && n < 40) { -+ return gdb_get_reg8(mem_buf, env->active_fpu.cf[n - 32]); -+ } else if (n == 40) { -+ return gdb_get_reg32(mem_buf, env->active_fpu.fcsr0); -+ } -+ return 0; -+} -+ -+static int loongarch_gdb_set_fpu(CPULOONGARCHState *env, uint8_t *mem_buf, int n) -+{ -+ if (0 <= n && n < 32) { -+ return env->active_fpu.fpr[n].d = ldq_p(mem_buf), 8; -+ } else if (32 <= n && n < 40) { -+ return env->active_fpu.cf[n - 32] = ldub_p(mem_buf), 1; -+ } else if (n == 40) { -+ return env->active_fpu.fcsr0 = ldl_p(mem_buf), 4; -+ } -+ return 0; -+} -+ -+void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs) -+{ -+ gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu, -+ 41, "loongarch-fpu64.xml", 0); -+} -+ -+#ifdef CONFIG_TCG -+int loongarch_read_qxfer(CPUState *cs, const char *annex, uint8_t *read_buf, -+ unsigned long offset, unsigned long len) -+{ -+ if (strncmp(annex, "cpucfg", sizeof("cpucfg") - 1) == 0) { -+ if (offset % 4 != 0 || len % 4 != 0) { -+ return 0; -+ } -+ -+ size_t i; -+ for (i = offset; i < offset + len; i += 4) -+ ((uint32_t *)read_buf)[(i - offset) / 4] = -+ helper_cpucfg(&(LOONGARCH_CPU(cs)->env), i / 4); -+ return 32 * 4; -+ } -+ return 0; -+} -+ -+int loongarch_write_qxfer(CPUState *cs, const char *annex, -+ const uint8_t *write_buf, unsigned long offset, -+ unsigned long len) -+{ -+ return 0; -+} -+#endif -diff --git a/target/loongarch64/helper.c b/target/loongarch64/helper.c -new file mode 100644 -index 000000000..841240e57 ---- /dev/null -+++ b/target/loongarch64/helper.c -@@ -0,0 +1,727 @@ -+/* -+ * LOONGARCH emulation helpers for qemu. -+ * -+ * Copyright (c) 2004-2005 Jocelyn Mayer -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+#include "qemu/osdep.h" -+#include "cpu.h" -+#include "internal.h" -+#include "exec/exec-all.h" -+#include "exec/cpu_ldst.h" -+#include "exec/log.h" -+#include "hw/loongarch/cpudevs.h" -+ -+ -+#if !defined(CONFIG_USER_ONLY) -+ -+static int ls3a5k_map_address_tlb_entry( -+ CPULOONGARCHState *env, -+ hwaddr *physical, -+ int *prot, -+ target_ulong address, -+ int rw, -+ int access_type, -+ ls3a5k_tlb_t *tlb) -+{ -+ uint64_t mask = tlb->PageMask; -+ int n = !!(address & mask & ~(mask >> 1)); -+ uint32_t plv = env->CSR_CRMD & CSR_CRMD_PLV; -+ -+ /* Check access rights */ -+ if (!(n ? tlb->V1 : tlb->V0)) { -+ return TLBRET_INVALID; -+ } -+ -+ if (rw == MMU_INST_FETCH && (n ? tlb->XI1 : tlb->XI0)) { -+ return TLBRET_XI; -+ } -+ -+ if (rw == MMU_DATA_LOAD && (n ? tlb->RI1 : tlb->RI0)) { -+ return TLBRET_RI; -+ } -+ -+ if (plv > (n ? tlb->PLV1 : tlb->PLV0)) { -+ return TLBRET_PE; -+ } -+ -+ if (rw != MMU_DATA_STORE || (n ? tlb->WE1 : tlb->WE0)) { -+ /* PPN address -+ * 4 KB: [47:13] [12;0] -+ * 16 KB: [47:15] [14:0] -+ */ -+ if (n) { -+ *physical = tlb->PPN1 | (address & (mask >> 1)); -+ } else { -+ *physical = tlb->PPN0 | (address & (mask >> 1)); -+ } -+ *prot = PAGE_READ; -+ if (n ? tlb->WE1 : tlb->WE0) { -+ *prot |= PAGE_WRITE; -+ } -+ if (!(n ? tlb->XI1 : tlb->XI0)) { -+ *prot |= PAGE_EXEC; -+ } -+ return TLBRET_MATCH; -+ } -+ -+ return TLBRET_DIRTY; -+} -+ -+/* Loongarch 3A5K -style MMU emulation */ -+int ls3a5k_map_address(CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type) -+{ -+ uint16_t asid = env->CSR_ASID & 0x3ff; -+ int i; -+ ls3a5k_tlb_t *tlb; -+ -+ int ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ int vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; -+ -+ int ftlb_idx; -+ -+ uint64_t mask; -+ uint64_t vpn; /* address to map */ -+ uint64_t tag; /* address in TLB entry */ -+ -+ /* search VTLB */ -+ for (i = ftlb_size; i < ftlb_size + vtlb_size; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ mask = tlb->PageMask; -+ -+ vpn = address & 0xffffffffe000 & ~mask; -+ tag = tlb->VPN & ~mask; -+ -+ if ((tlb->G == 1 || tlb->ASID == asid) -+ && vpn == tag -+ && tlb->EHINV != 1) -+ { -+ return ls3a5k_map_address_tlb_entry(env, physical, prot, -+ address, rw, access_type, tlb); -+ } -+ } -+ -+ if (ftlb_size == 0) { -+ return TLBRET_NOMATCH; -+ } -+ -+ /* search FTLB */ -+ mask = env->tlb->mmu.ls3a5k.ftlb_mask; -+ vpn = address & 0xffffffffe000 & ~mask; -+ -+ ftlb_idx = (address & 0xffffffffc000) >> 15; /* 16 KB */ -+ ftlb_idx = ftlb_idx & 0xff; /* [0,255] */ -+ -+ for (i = 0; i < 8; ++i) { -+ /* ---------- set 0 1 2 ... 7 -+ * ftlb_idx ----------------------------------- -+ * 0 | 0 1 2 ... 7 -+ * 1 | 8 9 10 ... 15 -+ * 2 | 16 17 18 ... 23 -+ * ... | -+ * 255 | 2040 2041 2042 ... 2047 -+ */ -+ tlb = &env->tlb->mmu.ls3a5k.tlb[ftlb_idx * 8 + i]; -+ tag = tlb->VPN & ~mask; -+ -+ if ((tlb->G == 1 || tlb->ASID == asid) -+ && vpn == tag -+ && tlb->EHINV != 1) -+ { -+ return ls3a5k_map_address_tlb_entry(env, physical, prot, -+ address, rw, access_type, tlb); -+ } -+ } -+ -+ return TLBRET_NOMATCH; -+} -+ -+static int get_physical_address(CPULOONGARCHState *env, hwaddr *physical, -+ int *prot, target_ulong real_address, -+ int rw, int access_type, int mmu_idx) -+{ -+ int user_mode = mmu_idx == LARCH_HFLAG_UM; -+ int kernel_mode = !user_mode; -+ unsigned plv, base_c, base_v, tmp; -+ -+ /* effective address (modified for KVM T&E kernel segments) */ -+ target_ulong address = real_address; -+ -+ /* Check PG */ -+ if (!(env->CSR_CRMD & CSR_CRMD_PG)) { -+ /* DA mode */ -+ *physical = address & 0xffffffffffffUL; -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ -+ plv = kernel_mode | (user_mode << 3); -+ base_v = address >> CSR_DMW_BASE_SH; -+ /* Check direct map window 0 */ -+ base_c = env->CSR_DMWIN0 >> CSR_DMW_BASE_SH; -+ if ((plv & env->CSR_DMWIN0) && (base_c == base_v)) { -+ *physical = dmwin_va2pa(address); -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ /* Check direct map window 1 */ -+ base_c = env->CSR_DMWIN1 >> CSR_DMW_BASE_SH; -+ if ((plv & env->CSR_DMWIN1) && (base_c == base_v)) { -+ *physical = dmwin_va2pa(address); -+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; -+ return TLBRET_MATCH; -+ } -+ /* Check valid extension */ -+ tmp = address >> 47; -+ if (!(tmp == 0 || tmp == 0x1ffff)) { -+ return TLBRET_BADADDR; -+ } -+ /* mapped address */ -+ return env->tlb->map_address(env, physical, prot, real_address, rw, -+ access_type); -+} -+ -+void cpu_loongarch_tlb_flush(CPULOONGARCHState *env) -+{ -+ LOONGARCHCPU *cpu = loongarch_env_get_cpu(env); -+ -+ /* Flush qemu's TLB and discard all shadowed entries. */ -+ tlb_flush(CPU(cpu)); -+ env->tlb->tlb_in_use = env->tlb->nb_tlb; -+} -+#endif -+ -+static void raise_mmu_exception(CPULOONGARCHState *env, target_ulong address, -+ int rw, int tlb_error) -+{ -+ CPUState *cs = CPU(loongarch_env_get_cpu(env)); -+ int exception = 0, error_code = 0; -+ -+ if (rw == MMU_INST_FETCH) { -+ error_code |= EXCP_INST_NOTAVAIL; -+ } -+ -+ switch (tlb_error) { -+ default: -+ case TLBRET_BADADDR: -+ /* Reference to kernel address from user mode or supervisor mode */ -+ /* Reference to supervisor address from user mode */ -+ if (rw == MMU_DATA_STORE) { -+ exception = EXCP_AdES; -+ } else { -+ exception = EXCP_AdEL; -+ } -+ break; -+ case TLBRET_NOMATCH: -+ /* No TLB match for a mapped address */ -+ if (rw == MMU_DATA_STORE) { -+ exception = EXCP_TLBS; -+ } else { -+ exception = EXCP_TLBL; -+ } -+ error_code |= EXCP_TLB_NOMATCH; -+ break; -+ case TLBRET_INVALID: -+ /* TLB match with no valid bit */ -+ if (rw == MMU_DATA_STORE) { -+ exception = EXCP_TLBS; -+ } else { -+ exception = EXCP_TLBL; -+ } -+ break; -+ case TLBRET_DIRTY: -+ /* TLB match but 'D' bit is cleared */ -+ exception = EXCP_LTLBL; -+ break; -+ case TLBRET_XI: -+ /* Execute-Inhibit Exception */ -+ exception = EXCP_TLBXI; -+ break; -+ case TLBRET_RI: -+ /* Read-Inhibit Exception */ -+ exception = EXCP_TLBRI; -+ break; -+ case TLBRET_PE: -+ /* Privileged Exception */ -+ exception = EXCP_TLBPE; -+ break; -+ } -+ -+ if (env->insn_flags & INSN_LOONGARCH) { -+ if (tlb_error == TLBRET_NOMATCH) { -+ env->CSR_TLBRBADV = address; -+ env->CSR_TLBREHI = address & (TARGET_PAGE_MASK << 1); -+ cs->exception_index = exception; -+ env->error_code = error_code; -+ return; -+ } -+ } -+ -+ /* Raise exception */ -+ env->CSR_BADV = address; -+ cs->exception_index = exception; -+ env->error_code = error_code; -+ -+ if (env->insn_flags & INSN_LOONGARCH) { -+ env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1); -+ } -+} -+ -+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, -+ MMUAccessType access_type, int mmu_idx, -+ bool probe, uintptr_t retaddr) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+#if !defined(CONFIG_USER_ONLY) -+ hwaddr physical; -+ int prot; -+ int loongarch_access_type; -+#endif -+ int ret = TLBRET_BADADDR; -+ -+ qemu_log_mask(CPU_LOG_MMU, -+ "%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " mmu_idx %d\n", -+ __func__, env->active_tc.PC, address, mmu_idx); -+ -+ /* data access */ -+#if !defined(CONFIG_USER_ONLY) -+ /* XXX: put correct access by using cpu_restore_state() correctly */ -+ loongarch_access_type = ACCESS_INT; -+ ret = get_physical_address(env, &physical, &prot, address, -+ access_type, loongarch_access_type, mmu_idx); -+ switch (ret) { -+ case TLBRET_MATCH: -+ qemu_log_mask(CPU_LOG_MMU, -+ "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx -+ " prot %d asid %ld pc 0x%lx\n", -+ __func__, address, physical, prot, -+ env->CSR_ASID, env->active_tc.PC); -+ break; -+ default: -+ qemu_log_mask(CPU_LOG_MMU, -+ "%s address=%" VADDR_PRIx " ret %d asid %ld pc 0x%lx\n", -+ __func__, address, ret, env->CSR_ASID, env->active_tc.PC); -+ break; -+ } -+ if (ret == TLBRET_MATCH) { -+ tlb_set_page(cs, address & TARGET_PAGE_MASK, -+ physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, -+ mmu_idx, TARGET_PAGE_SIZE); -+ ret = true; -+ } -+ if (probe) { -+ return false; -+ } -+#endif -+ -+ raise_mmu_exception(env, address, access_type, ret); -+ do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr); -+} -+ -+#if !defined(CONFIG_USER_ONLY) -+hwaddr cpu_loongarch_translate_address(CPULOONGARCHState *env, -+ target_ulong address, int rw) -+{ -+ hwaddr physical; -+ int prot; -+ int access_type; -+ int ret = 0; -+ -+ /* data access */ -+ access_type = ACCESS_INT; -+ ret = get_physical_address(env, &physical, &prot, address, rw, access_type, -+ cpu_mmu_index(env, false)); -+ if (ret != TLBRET_MATCH) { -+ raise_mmu_exception(env, address, rw, ret); -+ return -1LL; -+ } else { -+ return physical; -+ } -+} -+ -+static const char * const excp_names[EXCP_LAST + 1] = { -+ [EXCP_RESET] = "reset", -+ [EXCP_SRESET] = "soft reset", -+ [EXCP_NMI] = "non-maskable interrupt", -+ [EXCP_EXT_INTERRUPT] = "interrupt", -+ [EXCP_AdEL] = "address error load", -+ [EXCP_AdES] = "address error store", -+ [EXCP_TLBF] = "TLB refill", -+ [EXCP_IBE] = "instruction bus error", -+ [EXCP_SYSCALL] = "syscall", -+ [EXCP_BREAK] = "break", -+ [EXCP_FPDIS] = "float unit unusable", -+ [EXCP_LSXDIS] = "vector128 unusable", -+ [EXCP_LASXDIS] = "vector256 unusable", -+ [EXCP_RI] = "reserved instruction", -+ [EXCP_OVERFLOW] = "arithmetic overflow", -+ [EXCP_TRAP] = "trap", -+ [EXCP_FPE] = "floating point", -+ [EXCP_LTLBL] = "TLB modify", -+ [EXCP_TLBL] = "TLB load", -+ [EXCP_TLBS] = "TLB store", -+ [EXCP_DBE] = "data bus error", -+ [EXCP_TLBXI] = "TLB execute-inhibit", -+ [EXCP_TLBRI] = "TLB read-inhibit", -+ [EXCP_TLBPE] = "TLB priviledged error", -+}; -+#endif -+ -+target_ulong exception_resume_pc(CPULOONGARCHState *env) -+{ -+ target_ulong bad_pc; -+ -+ bad_pc = env->active_tc.PC; -+ if (env->hflags & LARCH_HFLAG_BMASK) { -+ /* If the exception was raised from a delay slot, come back to -+ the jump. */ -+ bad_pc -= 4; -+ } -+ -+ return bad_pc; -+} -+ -+#if !defined(CONFIG_USER_ONLY) -+static void set_hflags_for_handler (CPULOONGARCHState *env) -+{ -+ /* Exception handlers are entered in 32-bit mode. */ -+} -+ -+static inline void set_badinstr_registers(CPULOONGARCHState *env) -+{ -+ if ((env->insn_flags & INSN_LOONGARCH)) { -+ env->CSR_BADI = cpu_ldl_code(env, env->active_tc.PC); -+ return; -+ } -+} -+#endif -+ -+static inline unsigned int get_vint_size(CPULOONGARCHState *env) -+{ -+ unsigned int size = 0; -+ -+ switch ((env->CSR_ECFG >> 16) & 0x7) { -+ case 0: -+ break; -+ case 1: -+ size = 2 * 4; /* #Insts * inst_size */ -+ break; -+ case 2: -+ size = 4 * 4; -+ break; -+ case 3: -+ size = 8 * 4; -+ break; -+ case 4: -+ size = 16 * 4; -+ break; -+ case 5: -+ size = 32 * 4; -+ break; -+ case 6: -+ size = 64 * 4; -+ break; -+ case 7: -+ size = 128 * 4; -+ break; -+ default: -+ printf("%s: unexpected value", __func__); -+ assert(0); -+ } -+ -+ return size; -+} -+ -+#define is_refill(cs, env) (((cs->exception_index == EXCP_TLBL) \ -+ || (cs->exception_index == EXCP_TLBS)) \ -+ && (env->error_code & EXCP_TLB_NOMATCH)) -+ -+void loongarch_cpu_do_interrupt(CPUState *cs) -+{ -+#if !defined(CONFIG_USER_ONLY) -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ bool update_badinstr = 0; -+ int cause = -1; -+ const char *name; -+ -+ if (qemu_loglevel_mask(CPU_LOG_INT) -+ && cs->exception_index != EXCP_EXT_INTERRUPT) { -+ if (cs->exception_index < 0 || cs->exception_index > EXCP_LAST) { -+ name = "unknown"; -+ } else { -+ name = excp_names[cs->exception_index]; -+ } -+ -+ qemu_log("%s enter: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx -+ " TLBRERA 0x%016lx" " %s exception\n", __func__, -+ env->active_tc.PC, env->CSR_ERA, env->CSR_TLBRERA, name); -+ } -+ -+ switch (cs->exception_index) { -+ case EXCP_RESET: -+ cpu_reset(CPU(cpu)); -+ break; -+ case EXCP_NMI: -+ env->CSR_ERRERA = exception_resume_pc(env); -+ env->hflags &= ~LARCH_HFLAG_BMASK; -+ env->hflags |= LARCH_HFLAG_64; -+ env->hflags &= ~LARCH_HFLAG_AWRAP; -+ env->hflags &= ~(LARCH_HFLAG_KSU); -+ env->active_tc.PC = env->exception_base; -+ set_hflags_for_handler(env); -+ break; -+ case EXCP_EXT_INTERRUPT: -+ cause = 0; -+ goto set_ERA; -+ case EXCP_LTLBL: -+ cause = 1; -+ update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); -+ goto set_ERA; -+ case EXCP_TLBL: -+ cause = 2; -+ update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); -+ goto set_ERA; -+ case EXCP_TLBS: -+ cause = 3; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_AdEL: -+ cause = 4; -+ update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); -+ goto set_ERA; -+ case EXCP_AdES: -+ cause = 5; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_IBE: -+ cause = 6; -+ goto set_ERA; -+ case EXCP_DBE: -+ cause = 7; -+ goto set_ERA; -+ case EXCP_SYSCALL: -+ cause = 8; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_BREAK: -+ cause = 9; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_RI: -+ cause = 10; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_FPDIS: -+ case EXCP_LSXDIS: -+ case EXCP_LASXDIS: -+ cause = 11; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_OVERFLOW: -+ cause = 12; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_TRAP: -+ cause = 13; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_FPE: -+ cause = 15; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_TLBRI: -+ cause = 19; -+ update_badinstr = 1; -+ goto set_ERA; -+ case EXCP_TLBXI: -+ case EXCP_TLBPE: -+ cause = 20; -+ goto set_ERA; -+ set_ERA: -+ if (is_refill(cs, env)) { -+ env->CSR_TLBRERA = exception_resume_pc(env); -+ env->CSR_TLBRERA |= 1; -+ } else { -+ env->CSR_ERA = exception_resume_pc(env); -+ } -+ -+ if (update_badinstr) { -+ set_badinstr_registers(env); -+ } -+ env->hflags &= ~(LARCH_HFLAG_KSU); -+ -+ env->hflags &= ~LARCH_HFLAG_BMASK; -+ if (env->insn_flags & INSN_LOONGARCH) { -+ /* save PLV and IE */ -+ if (is_refill(cs, env)) { -+ env->CSR_TLBRPRMD &= (~0x7); -+ env->CSR_TLBRPRMD |= (env->CSR_CRMD & 0x7); -+ } else { -+ env->CSR_PRMD &= (~0x7); -+ env->CSR_PRMD |= (env->CSR_CRMD & 0x7); -+ } -+ -+ env->CSR_CRMD &= ~(0x7); -+ -+ switch (cs->exception_index) { -+ case EXCP_EXT_INTERRUPT: -+ break; -+ case EXCP_TLBL: -+ if (env->error_code & EXCP_INST_NOTAVAIL) { -+ cause = EXCCODE_TLBI; -+ } else { -+ cause = EXCCODE_TLBL; -+ } -+ break; -+ case EXCP_TLBS: -+ cause = EXCCODE_TLBS; -+ break; -+ case EXCP_LTLBL: -+ cause = EXCCODE_MOD; -+ break; -+ case EXCP_TLBRI: -+ cause = EXCCODE_TLBRI; -+ break; -+ case EXCP_TLBXI: -+ cause = EXCCODE_TLBXI; -+ break; -+ case EXCP_TLBPE: -+ cause = EXCCODE_TLBPE; -+ break; -+ case EXCP_AdEL: -+ case EXCP_AdES: -+ case EXCP_IBE: -+ case EXCP_DBE: -+ cause = EXCCODE_ADE; -+ break; -+ case EXCP_SYSCALL: -+ cause = EXCCODE_SYS; -+ break; -+ case EXCP_BREAK: -+ cause = EXCCODE_BP; -+ break; -+ case EXCP_RI: -+ cause = EXCCODE_RI; -+ break; -+ case EXCP_FPDIS: -+ cause = EXCCODE_FPDIS; -+ break; -+ case EXCP_LSXDIS: -+ cause = EXCCODE_LSXDIS; -+ break; -+ case EXCP_LASXDIS: -+ cause = EXCCODE_LASXDIS; -+ break; -+ case EXCP_FPE: -+ cause = EXCCODE_FPE; -+ break; -+ default: -+ printf("Error: exception(%d) '%s' has not been supported\n", -+ cs->exception_index, excp_names[cs->exception_index]); -+ abort(); -+ } -+ -+ uint32_t vec_size = get_vint_size(env); -+ env->active_tc.PC = env->CSR_EEPN; -+ env->active_tc.PC += cause * vec_size; -+ if (is_refill(cs, env)) { -+ /* TLB Refill */ -+ env->active_tc.PC = env->CSR_TLBRENT; -+ break; /* Do not modify excode */ -+ } -+ if (cs->exception_index == EXCP_EXT_INTERRUPT) { -+ /* Interrupt */ -+ uint32_t vector = 0; -+ uint32_t pending = env->CSR_ESTAT & CSR_ESTAT_IPMASK; -+ pending &= env->CSR_ECFG & CSR_ECFG_IPMASK; -+ -+ /* Find the highest-priority interrupt. */ -+ while (pending >>= 1) { -+ vector++; -+ } -+ env->active_tc.PC = env->CSR_EEPN + -+ (EXCODE_IP + vector) * vec_size; -+ if (qemu_loglevel_mask(CPU_LOG_INT)) { -+ qemu_log("%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx -+ " cause %d\n" " A " TARGET_FMT_lx " D " -+ TARGET_FMT_lx " vector = %d ExC %08lx ExS %08lx\n", -+ __func__, env->active_tc.PC, env->CSR_ERA, -+ cause, env->CSR_BADV, env->CSR_DERA, vector, -+ env->CSR_ECFG, env->CSR_ESTAT); -+ } -+ } -+ /* Excode */ -+ env->CSR_ESTAT = (env->CSR_ESTAT & ~(0x1f << CSR_ESTAT_EXC_SH)) | -+ (cause << CSR_ESTAT_EXC_SH); -+ } -+ set_hflags_for_handler(env); -+ break; -+ default: -+ abort(); -+ } -+ if (qemu_loglevel_mask(CPU_LOG_INT) -+ && cs->exception_index != EXCP_EXT_INTERRUPT) { -+ qemu_log("%s: PC " TARGET_FMT_lx " ERA 0x%08lx" " cause %d%s\n" -+ " ESTAT %08lx EXCFG 0x%08lx BADVA 0x%08lx BADI 0x%08lx \ -+ SYS_NUM %lu cpu %d asid 0x%lx" "\n", -+ __func__, env->active_tc.PC, -+ is_refill(cs, env) ? env->CSR_TLBRERA : env->CSR_ERA, -+ cause, -+ is_refill(cs, env) ? "(refill)" : "", -+ env->CSR_ESTAT, env->CSR_ECFG, -+ is_refill(cs, env) ? env->CSR_TLBRBADV : env->CSR_BADV, -+ env->CSR_BADI, env->active_tc.gpr[11], cs->cpu_index, -+ env->CSR_ASID -+ ); -+ } -+#endif -+ cs->exception_index = EXCP_NONE; -+} -+ -+bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -+{ -+ if (interrupt_request & CPU_INTERRUPT_HARD) { -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ if (cpu_loongarch_hw_interrupts_enabled(env) && -+ cpu_loongarch_hw_interrupts_pending(env)) { -+ /* Raise it */ -+ cs->exception_index = EXCP_EXT_INTERRUPT; -+ env->error_code = 0; -+ loongarch_cpu_do_interrupt(cs); -+ return true; -+ } -+ } -+ return false; -+} -+ -+void QEMU_NORETURN do_raise_exception_err(CPULOONGARCHState *env, -+ uint32_t exception, -+ int error_code, -+ uintptr_t pc) -+{ -+ CPUState *cs = CPU(loongarch_env_get_cpu(env)); -+ -+ qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n", -+ __func__, exception, error_code); -+ cs->exception_index = exception; -+ env->error_code = error_code; -+ -+ cpu_loop_exit_restore(cs, pc); -+} -diff --git a/target/loongarch64/helper.h b/target/loongarch64/helper.h -new file mode 100644 -index 000000000..ff2026ed8 ---- /dev/null -+++ b/target/loongarch64/helper.h -@@ -0,0 +1,168 @@ -+DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) -+DEF_HELPER_2(raise_exception, noreturn, env, i32) -+DEF_HELPER_1(raise_exception_debug, noreturn, env) -+ -+#if 0 -+#ifndef CONFIG_USER_ONLY -+DEF_HELPER_3(ll, tl, env, tl, int) -+DEF_HELPER_3(lld, tl, env, tl, int) -+#endif -+#endif -+ -+DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) -+DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) -+ -+DEF_HELPER_3(crc32, tl, tl, tl, i32) -+DEF_HELPER_3(crc32c, tl, tl, tl, i32) -+ -+#ifndef CONFIG_USER_ONLY -+/* LoongISA CSR register */ -+DEF_HELPER_2(csr_rdq, tl, env, i64) -+DEF_HELPER_3(csr_wrq, tl, env, tl, i64) -+DEF_HELPER_4(csr_xchgq, tl, env, tl, tl, i64) -+ -+#endif /* !CONFIG_USER_ONLY */ -+ -+/* CP1 functions */ -+DEF_HELPER_2(movfcsr2gr, tl, env, i32) -+DEF_HELPER_4(movgr2fcsr, void, env, tl, i32, i32) -+ -+DEF_HELPER_2(float_cvtd_s, i64, env, i32) -+DEF_HELPER_2(float_cvtd_w, i64, env, i32) -+DEF_HELPER_2(float_cvtd_l, i64, env, i64) -+DEF_HELPER_2(float_cvts_d, i32, env, i64) -+DEF_HELPER_2(float_cvts_w, i32, env, i32) -+DEF_HELPER_2(float_cvts_l, i32, env, i64) -+ -+DEF_HELPER_FLAGS_2(float_class_s, TCG_CALL_NO_RWG_SE, i32, env, i32) -+DEF_HELPER_FLAGS_2(float_class_d, TCG_CALL_NO_RWG_SE, i64, env, i64) -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_4(float_ ## op ## _s, i32, env, i32, i32, i32) \ -+DEF_HELPER_4(float_ ## op ## _d, i64, env, i64, i64, i64) -+FOP_PROTO(maddf) -+FOP_PROTO(msubf) -+FOP_PROTO(nmaddf) -+FOP_PROTO(nmsubf) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \ -+DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64) -+FOP_PROTO(max) -+FOP_PROTO(maxa) -+FOP_PROTO(min) -+FOP_PROTO(mina) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_2(float_ ## op ## _l_s, i64, env, i32) \ -+DEF_HELPER_2(float_ ## op ## _l_d, i64, env, i64) \ -+DEF_HELPER_2(float_ ## op ## _w_s, i32, env, i32) \ -+DEF_HELPER_2(float_ ## op ## _w_d, i32, env, i64) -+FOP_PROTO(cvt) -+FOP_PROTO(round) -+FOP_PROTO(trunc) -+FOP_PROTO(ceil) -+FOP_PROTO(floor) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_2(float_ ## op ## _s, i32, env, i32) \ -+DEF_HELPER_2(float_ ## op ## _d, i64, env, i64) -+FOP_PROTO(sqrt) -+FOP_PROTO(rsqrt) -+FOP_PROTO(recip) -+FOP_PROTO(rint) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_1(float_ ## op ## _s, i32, i32) \ -+DEF_HELPER_1(float_ ## op ## _d, i64, i64) -+FOP_PROTO(abs) -+FOP_PROTO(chs) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \ -+DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64) -+FOP_PROTO(add) -+FOP_PROTO(sub) -+FOP_PROTO(mul) -+FOP_PROTO(div) -+#undef FOP_PROTO -+ -+#define FOP_PROTO(op) \ -+DEF_HELPER_3(cmp_d_ ## op, i64, env, i64, i64) \ -+DEF_HELPER_3(cmp_s_ ## op, i32, env, i32, i32) -+FOP_PROTO(af) -+FOP_PROTO(un) -+FOP_PROTO(eq) -+FOP_PROTO(ueq) -+FOP_PROTO(lt) -+FOP_PROTO(ult) -+FOP_PROTO(le) -+FOP_PROTO(ule) -+FOP_PROTO(saf) -+FOP_PROTO(sun) -+FOP_PROTO(seq) -+FOP_PROTO(sueq) -+FOP_PROTO(slt) -+FOP_PROTO(sult) -+FOP_PROTO(sle) -+FOP_PROTO(sule) -+FOP_PROTO(or) -+FOP_PROTO(une) -+FOP_PROTO(ne) -+FOP_PROTO(sor) -+FOP_PROTO(sune) -+FOP_PROTO(sne) -+#undef FOP_PROTO -+ -+/* Special functions */ -+#ifndef CONFIG_USER_ONLY -+DEF_HELPER_1(tlbwr, void, env) -+DEF_HELPER_1(tlbfill, void, env) -+DEF_HELPER_1(tlbsrch, void, env) -+DEF_HELPER_1(tlbrd, void, env) -+DEF_HELPER_1(tlbclr, void, env) -+DEF_HELPER_1(tlbflush, void, env) -+DEF_HELPER_4(invtlb, void, env, tl, tl, tl) -+DEF_HELPER_1(ertn, void, env) -+DEF_HELPER_5(lddir, void, env, tl, tl, tl, i32) -+DEF_HELPER_4(ldpte, void, env, tl, tl, i32) -+DEF_HELPER_3(drdtime, void, env, tl, tl) -+DEF_HELPER_1(read_pgd, tl, env) -+#endif /* !CONFIG_USER_ONLY */ -+DEF_HELPER_2(cpucfg, tl, env, tl) -+DEF_HELPER_1(idle, void, env) -+ -+DEF_HELPER_3(float_exp2_s, i32, env, i32, i32) -+DEF_HELPER_3(float_exp2_d, i64, env, i64, i64) -+DEF_HELPER_2(float_logb_s, i32, env, i32) -+DEF_HELPER_2(float_logb_d, i64, env, i64) -+DEF_HELPER_3(movreg2cf, void, env, i32, tl) -+DEF_HELPER_2(movcf2reg, tl, env, i32) -+DEF_HELPER_3(movreg2cf_i32, void, env, i32, i32) -+DEF_HELPER_3(movreg2cf_i64, void, env, i32, i64) -+ -+DEF_HELPER_2(cto_w, tl, env, tl) -+DEF_HELPER_2(ctz_w, tl, env, tl) -+DEF_HELPER_2(cto_d, tl, env, tl) -+DEF_HELPER_2(ctz_d, tl, env, tl) -+DEF_HELPER_2(bitrev_w, tl, env, tl) -+DEF_HELPER_2(bitrev_d, tl, env, tl) -+ -+DEF_HELPER_2(load_scr, i64, env, i32) -+DEF_HELPER_3(store_scr, void, env, i32, i64) -+ -+DEF_HELPER_3(asrtle_d, void, env, tl, tl) -+DEF_HELPER_3(asrtgt_d, void, env, tl, tl) -+ -+DEF_HELPER_4(fsel, i64, env, i64, i64, i32) -+ -+#ifndef CONFIG_USER_ONLY -+DEF_HELPER_4(iocsr, void, env, tl, tl, i32) -+#endif -+DEF_HELPER_3(memtrace_addr, void, env, tl, i32) -+DEF_HELPER_2(memtrace_val, void, env, tl) -diff --git a/target/loongarch64/insn.decode b/target/loongarch64/insn.decode -new file mode 100644 -index 000000000..f194f7011 ---- /dev/null -+++ b/target/loongarch64/insn.decode -@@ -0,0 +1,514 @@ -+# Fields -+%sd 0:2 -+%rj 5:5 -+%rd 0:5 -+%sj 5:2 -+%ptr 5:3 -+%rk 10:5 -+%sa2 15:2 -+%sa3 15:3 -+%si5 10:s5 -+%code 0:15 -+%cond 10:4 -+%cond2 0:4 -+%ui5 10:5 -+%ui6 10:6 -+%ui3 10:3 -+%ui4 10:4 -+%op 5:5 -+%ui8 10:8 -+%msbw 16:5 -+%lsbw 10:5 -+%msbd 16:6 -+%lsbd 10:6 -+%fd 0:5 -+%fj 5:5 -+%fk 10:5 -+%fcsrd 0:5 -+%fcsrs 5:5 -+%cd 0:3 -+%cj 5:3 -+%si12 10:s12 -+%ui12 10:12 -+%csr 10:14 -+%cop 0:5 -+%level 10:8 -+%seq 10:8 -+%whint 0:15 -+%addr 10:5 -+%info 5:5 -+%invop 0:5 -+%fa 15:5 -+%vd 0:5 -+%vj 5:5 -+%vk 10:5 -+%va 15:5 -+%xd 0:5 -+%xj 5:5 -+%xk 10:5 -+%xa 15:5 -+%fcond 15:5 -+%ca 15:3 -+%vui5 15:5 -+%si16 10:s16 -+%si20 5:s20 -+%si14 10:s14 -+%hint 0:5 -+%si9 10:s9 -+%si10 10:s10 -+%si11 10:s11 -+%si8 10:s8 -+%idx1 18:1 -+%idx2 18:2 -+%idx3 18:3 -+%idx4 18:4 -+%idx 18:5 -+%offs21 0:s5 10:16 -+%offs16 10:s16 -+%offs 0:s10 10:16 -+%mode 5:5 -+%ui2 10:2 -+%ui1 10:1 -+%ui7 10:7 -+%i13 5:13 -+ -+# Argument sets -+&fmt_sdrj sd rj -+&fmt_rdsj rd sj -+&fmt_rdrj rd rj -+&fmt_empty -+&fmt_rjrk rj rk -+&fmt_rdrjrksa2 rd rj rk sa2 -+&fmt_rdrjrksa3 rd rj rk sa3 -+&fmt_rdrjrk rd rj rk -+&fmt_code code -+&fmt_rdrjui5 rd rj ui5 -+&fmt_rdrjui6 rd rj ui6 -+&fmt_rdrjmsbwlsbw rd rj msbw lsbw -+&fmt_rdrjmsbdlsbd rd rj msbd lsbd -+&fmt_fdfjfk fd fj fk -+&fmt_fdfj fd fj -+&fmt_fdrj fd rj -+&fmt_rdfj rd fj -+&fmt_fcsrdrj fcsrd rj -+&fmt_rdfcsrs rd fcsrs -+&fmt_cdfj cd fj -+&fmt_fdcj fd cj -+&fmt_cdrj cd rj -+&fmt_rdcj rd cj -+&fmt_rdrjsi12 rd rj si12 -+&fmt_rdrjui12 rd rj ui12 -+&fmt_rdrjcsr rd rj csr -+&fmt_coprjsi12 cop rj si12 -+&fmt_rdrjlevel rd rj level -+&fmt_rjseq rj seq -+&fmt_whint whint -+&fmt_invtlb addr info invop -+&fmt_fdfjfkfa fd fj fk fa -+&fmt_cdfjfkfcond cd fj fk fcond -+&fmt_fdfjfkca fd fj fk ca -+&fmt_rdrjsi16 rd rj si16 -+&fmt_rdsi20 rd si20 -+&fmt_rdrjsi14 rd rj si14 -+&fmt_hintrjsi12 hint rj si12 -+&fmt_fdrjsi12 fd rj si12 -+&fmt_fdrjrk fd rj rk -+&fmt_rjoffs21 rj offs21 -+&fmt_cjoffs21 cj offs21 -+&fmt_rdrjoffs16 rd rj offs16 -+&fmt_offs offs -+&fmt_rjrdoffs16 rj rd offs16 -+ -+# Formats -+@fmt_sdrj .... ........ ..... ..... ..... ... .. &fmt_sdrj %sd %rj -+@fmt_rdsj .... ........ ..... ..... ... .. ..... &fmt_rdsj %rd %sj -+@fmt_rdrj .... ........ ..... ..... ..... ..... &fmt_rdrj %rd %rj -+@fmt_empty .... ........ ..... ..... ..... ..... &fmt_empty -+@fmt_rjrk .... ........ ..... ..... ..... ..... &fmt_rjrk %rj %rk -+@fmt_rdrjrksa2 .... ........ ... .. ..... ..... ..... &fmt_rdrjrksa2 %rd %rj %rk %sa2 -+@fmt_rdrjrksa3 .... ........ .. ... ..... ..... ..... &fmt_rdrjrksa3 %rd %rj %rk %sa3 -+@fmt_rdrjrk .... ........ ..... ..... ..... ..... &fmt_rdrjrk %rd %rj %rk -+@fmt_code .... ........ ..... ............... &fmt_code %code -+@fmt_rdrjui5 .... ........ ..... ..... ..... ..... &fmt_rdrjui5 %rd %rj %ui5 -+@fmt_rdrjui6 .... ........ .... ...... ..... ..... &fmt_rdrjui6 %rd %rj %ui6 -+@fmt_rdrjmsbwlsbw .... ....... ..... . ..... ..... ..... &fmt_rdrjmsbwlsbw %rd %rj %msbw %lsbw -+@fmt_rdrjmsbdlsbd .... ...... ...... ...... ..... ..... &fmt_rdrjmsbdlsbd %rd %rj %msbd %lsbd -+@fmt_fdfjfk .... ........ ..... ..... ..... ..... &fmt_fdfjfk %fd %fj %fk -+@fmt_fdfj .... ........ ..... ..... ..... ..... &fmt_fdfj %fd %fj -+@fmt_fdrj .... ........ ..... ..... ..... ..... &fmt_fdrj %fd %rj -+@fmt_rdfj .... ........ ..... ..... ..... ..... &fmt_rdfj %rd %fj -+@fmt_fcsrdrj .... ........ ..... ..... ..... ..... &fmt_fcsrdrj %fcsrd %rj -+@fmt_rdfcsrs .... ........ ..... ..... ..... ..... &fmt_rdfcsrs %rd %fcsrs -+@fmt_cdfj .... ........ ..... ..... ..... .. ... &fmt_cdfj %cd %fj -+@fmt_fdcj .... ........ ..... ..... .. ... ..... &fmt_fdcj %fd %cj -+@fmt_cdrj .... ........ ..... ..... ..... .. ... &fmt_cdrj %cd %rj -+@fmt_rdcj .... ........ ..... ..... .. ... ..... &fmt_rdcj %rd %cj -+@fmt_rdrjsi12 .... ...... ............ ..... ..... &fmt_rdrjsi12 %rd %rj %si12 -+@fmt_rdrjui12 .... ...... ............ ..... ..... &fmt_rdrjui12 %rd %rj %ui12 -+@fmt_rdrjcsr .... .... .............. ..... ..... &fmt_rdrjcsr %rd %rj %csr -+@fmt_coprjsi12 .... ...... ............ ..... ..... &fmt_coprjsi12 %cop %rj %si12 -+@fmt_rdrjlevel .... ........ .. ........ ..... ..... &fmt_rdrjlevel %rd %rj %level -+@fmt_rjseq .... ........ .. ........ ..... ..... &fmt_rjseq %rj %seq -+@fmt_whint .... ........ ..... ............... &fmt_whint %whint -+@fmt_invtlb ...... ...... ..... ..... ..... ..... &fmt_invtlb %addr %info %invop -+@fmt_fdfjfkfa .... ........ ..... ..... ..... ..... &fmt_fdfjfkfa %fd %fj %fk %fa -+@fmt_cdfjfkfcond .... ........ ..... ..... ..... .. ... &fmt_cdfjfkfcond %cd %fj %fk %fcond -+@fmt_fdfjfkca .... ........ .. ... ..... ..... ..... &fmt_fdfjfkca %fd %fj %fk %ca -+@fmt_rdrjsi16 .... .. ................ ..... ..... &fmt_rdrjsi16 %rd %rj %si16 -+@fmt_rdsi20 .... ... .................... ..... &fmt_rdsi20 %rd %si20 -+@fmt_rdrjsi14 .... .... .............. ..... ..... &fmt_rdrjsi14 %rd %rj %si14 -+@fmt_hintrjsi12 .... ...... ............ ..... ..... &fmt_hintrjsi12 %hint %rj %si12 -+@fmt_fdrjsi12 .... ...... ............ ..... ..... &fmt_fdrjsi12 %fd %rj %si12 -+@fmt_fdrjrk .... ........ ..... ..... ..... ..... &fmt_fdrjrk %fd %rj %rk -+@fmt_rjoffs21 .... .. ................ ..... ..... &fmt_rjoffs21 %rj %offs21 -+@fmt_cjoffs21 .... .. ................ .. ... ..... &fmt_cjoffs21 %cj %offs21 -+@fmt_rdrjoffs16 .... .. ................ ..... ..... &fmt_rdrjoffs16 %rd %rj %offs16 -+@fmt_offs .... .. .......................... &fmt_offs %offs -+@fmt_rjrdoffs16 .... .. ................ ..... ..... &fmt_rjrdoffs16 %rj %rd %offs16 -+ -+# Instructions -+ -+# Fiexd point arithmetic Instructions -+gr2scr 0000 00000000 00000 00010 ..... 000 .. @fmt_sdrj -+scr2gr 0000 00000000 00000 00011 000 .. ..... @fmt_rdsj -+clo_w 0000 00000000 00000 00100 ..... ..... @fmt_rdrj -+clz_w 0000 00000000 00000 00101 ..... ..... @fmt_rdrj -+cto_w 0000 00000000 00000 00110 ..... ..... @fmt_rdrj -+ctz_w 0000 00000000 00000 00111 ..... ..... @fmt_rdrj -+clo_d 0000 00000000 00000 01000 ..... ..... @fmt_rdrj -+clz_d 0000 00000000 00000 01001 ..... ..... @fmt_rdrj -+cto_d 0000 00000000 00000 01010 ..... ..... @fmt_rdrj -+ctz_d 0000 00000000 00000 01011 ..... ..... @fmt_rdrj -+revb_2h 0000 00000000 00000 01100 ..... ..... @fmt_rdrj -+revb_4h 0000 00000000 00000 01101 ..... ..... @fmt_rdrj -+revb_2w 0000 00000000 00000 01110 ..... ..... @fmt_rdrj -+revb_d 0000 00000000 00000 01111 ..... ..... @fmt_rdrj -+revh_2w 0000 00000000 00000 10000 ..... ..... @fmt_rdrj -+revh_d 0000 00000000 00000 10001 ..... ..... @fmt_rdrj -+bitrev_4b 0000 00000000 00000 10010 ..... ..... @fmt_rdrj -+bitrev_8b 0000 00000000 00000 10011 ..... ..... @fmt_rdrj -+bitrev_w 0000 00000000 00000 10100 ..... ..... @fmt_rdrj -+bitrev_d 0000 00000000 00000 10101 ..... ..... @fmt_rdrj -+ext_w_h 0000 00000000 00000 10110 ..... ..... @fmt_rdrj -+ext_w_b 0000 00000000 00000 10111 ..... ..... @fmt_rdrj -+rdtime_d 0000 00000000 00000 11010 ..... ..... @fmt_rdrj -+cpucfg 0000 00000000 00000 11011 ..... ..... @fmt_rdrj -+asrtle_d 0000 00000000 00010 ..... ..... 00000 @fmt_rjrk -+asrtgt_d 0000 00000000 00011 ..... ..... 00000 @fmt_rjrk -+alsl_w 0000 00000000 010 .. ..... ..... ..... @fmt_rdrjrksa2 -+alsl_wu 0000 00000000 011 .. ..... ..... ..... @fmt_rdrjrksa2 -+bytepick_w 0000 00000000 100 .. ..... ..... ..... @fmt_rdrjrksa2 -+bytepick_d 0000 00000000 11 ... ..... ..... ..... @fmt_rdrjrksa3 -+add_w 0000 00000001 00000 ..... ..... ..... @fmt_rdrjrk -+add_d 0000 00000001 00001 ..... ..... ..... @fmt_rdrjrk -+sub_w 0000 00000001 00010 ..... ..... ..... @fmt_rdrjrk -+sub_d 0000 00000001 00011 ..... ..... ..... @fmt_rdrjrk -+slt 0000 00000001 00100 ..... ..... ..... @fmt_rdrjrk -+sltu 0000 00000001 00101 ..... ..... ..... @fmt_rdrjrk -+maskeqz 0000 00000001 00110 ..... ..... ..... @fmt_rdrjrk -+masknez 0000 00000001 00111 ..... ..... ..... @fmt_rdrjrk -+nor 0000 00000001 01000 ..... ..... ..... @fmt_rdrjrk -+and 0000 00000001 01001 ..... ..... ..... @fmt_rdrjrk -+or 0000 00000001 01010 ..... ..... ..... @fmt_rdrjrk -+xor 0000 00000001 01011 ..... ..... ..... @fmt_rdrjrk -+orn 0000 00000001 01100 ..... ..... ..... @fmt_rdrjrk -+andn 0000 00000001 01101 ..... ..... ..... @fmt_rdrjrk -+sll_w 0000 00000001 01110 ..... ..... ..... @fmt_rdrjrk -+srl_w 0000 00000001 01111 ..... ..... ..... @fmt_rdrjrk -+sra_w 0000 00000001 10000 ..... ..... ..... @fmt_rdrjrk -+sll_d 0000 00000001 10001 ..... ..... ..... @fmt_rdrjrk -+srl_d 0000 00000001 10010 ..... ..... ..... @fmt_rdrjrk -+sra_d 0000 00000001 10011 ..... ..... ..... @fmt_rdrjrk -+rotr_w 0000 00000001 10110 ..... ..... ..... @fmt_rdrjrk -+rotr_d 0000 00000001 10111 ..... ..... ..... @fmt_rdrjrk -+mul_w 0000 00000001 11000 ..... ..... ..... @fmt_rdrjrk -+mulh_w 0000 00000001 11001 ..... ..... ..... @fmt_rdrjrk -+mulh_wu 0000 00000001 11010 ..... ..... ..... @fmt_rdrjrk -+mul_d 0000 00000001 11011 ..... ..... ..... @fmt_rdrjrk -+mulh_d 0000 00000001 11100 ..... ..... ..... @fmt_rdrjrk -+mulh_du 0000 00000001 11101 ..... ..... ..... @fmt_rdrjrk -+mulw_d_w 0000 00000001 11110 ..... ..... ..... @fmt_rdrjrk -+mulw_d_wu 0000 00000001 11111 ..... ..... ..... @fmt_rdrjrk -+div_w 0000 00000010 00000 ..... ..... ..... @fmt_rdrjrk -+mod_w 0000 00000010 00001 ..... ..... ..... @fmt_rdrjrk -+div_wu 0000 00000010 00010 ..... ..... ..... @fmt_rdrjrk -+mod_wu 0000 00000010 00011 ..... ..... ..... @fmt_rdrjrk -+div_d 0000 00000010 00100 ..... ..... ..... @fmt_rdrjrk -+mod_d 0000 00000010 00101 ..... ..... ..... @fmt_rdrjrk -+div_du 0000 00000010 00110 ..... ..... ..... @fmt_rdrjrk -+mod_du 0000 00000010 00111 ..... ..... ..... @fmt_rdrjrk -+crc_w_b_w 0000 00000010 01000 ..... ..... ..... @fmt_rdrjrk -+crc_w_h_w 0000 00000010 01001 ..... ..... ..... @fmt_rdrjrk -+crc_w_w_w 0000 00000010 01010 ..... ..... ..... @fmt_rdrjrk -+crc_w_d_w 0000 00000010 01011 ..... ..... ..... @fmt_rdrjrk -+crcc_w_b_w 0000 00000010 01100 ..... ..... ..... @fmt_rdrjrk -+crcc_w_h_w 0000 00000010 01101 ..... ..... ..... @fmt_rdrjrk -+crcc_w_w_w 0000 00000010 01110 ..... ..... ..... @fmt_rdrjrk -+crcc_w_d_w 0000 00000010 01111 ..... ..... ..... @fmt_rdrjrk -+break 0000 00000010 10100 ............... @fmt_code -+dbcl 0000 00000010 10101 ............... @fmt_code -+syscall 0000 00000010 10110 ............... @fmt_code -+alsl_d 0000 00000010 110 .. ..... ..... ..... @fmt_rdrjrksa2 -+slli_w 0000 00000100 00001 ..... ..... ..... @fmt_rdrjui5 -+slli_d 0000 00000100 0001 ...... ..... ..... @fmt_rdrjui6 -+srli_w 0000 00000100 01001 ..... ..... ..... @fmt_rdrjui5 -+srli_d 0000 00000100 0101 ...... ..... ..... @fmt_rdrjui6 -+srai_w 0000 00000100 10001 ..... ..... ..... @fmt_rdrjui5 -+srai_d 0000 00000100 1001 ...... ..... ..... @fmt_rdrjui6 -+rotri_w 0000 00000100 11001 ..... ..... ..... @fmt_rdrjui5 -+rotri_d 0000 00000100 1101 ...... ..... ..... @fmt_rdrjui6 -+bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @fmt_rdrjmsbwlsbw -+bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @fmt_rdrjmsbwlsbw -+bstrins_d 0000 000010 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd -+bstrpick_d 0000 000011 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd -+ -+# float Instructions -+fadd_s 0000 00010000 00001 ..... ..... ..... @fmt_fdfjfk -+fadd_d 0000 00010000 00010 ..... ..... ..... @fmt_fdfjfk -+fsub_s 0000 00010000 00101 ..... ..... ..... @fmt_fdfjfk -+fsub_d 0000 00010000 00110 ..... ..... ..... @fmt_fdfjfk -+fmul_s 0000 00010000 01001 ..... ..... ..... @fmt_fdfjfk -+fmul_d 0000 00010000 01010 ..... ..... ..... @fmt_fdfjfk -+fdiv_s 0000 00010000 01101 ..... ..... ..... @fmt_fdfjfk -+fdiv_d 0000 00010000 01110 ..... ..... ..... @fmt_fdfjfk -+fmax_s 0000 00010000 10001 ..... ..... ..... @fmt_fdfjfk -+fmax_d 0000 00010000 10010 ..... ..... ..... @fmt_fdfjfk -+fmin_s 0000 00010000 10101 ..... ..... ..... @fmt_fdfjfk -+fmin_d 0000 00010000 10110 ..... ..... ..... @fmt_fdfjfk -+fmaxa_s 0000 00010000 11001 ..... ..... ..... @fmt_fdfjfk -+fmaxa_d 0000 00010000 11010 ..... ..... ..... @fmt_fdfjfk -+fmina_s 0000 00010000 11101 ..... ..... ..... @fmt_fdfjfk -+fmina_d 0000 00010000 11110 ..... ..... ..... @fmt_fdfjfk -+fscaleb_s 0000 00010001 00001 ..... ..... ..... @fmt_fdfjfk -+fscaleb_d 0000 00010001 00010 ..... ..... ..... @fmt_fdfjfk -+fcopysign_s 0000 00010001 00101 ..... ..... ..... @fmt_fdfjfk -+fcopysign_d 0000 00010001 00110 ..... ..... ..... @fmt_fdfjfk -+fabs_s 0000 00010001 01000 00001 ..... ..... @fmt_fdfj -+fabs_d 0000 00010001 01000 00010 ..... ..... @fmt_fdfj -+fneg_s 0000 00010001 01000 00101 ..... ..... @fmt_fdfj -+fneg_d 0000 00010001 01000 00110 ..... ..... @fmt_fdfj -+flogb_s 0000 00010001 01000 01001 ..... ..... @fmt_fdfj -+flogb_d 0000 00010001 01000 01010 ..... ..... @fmt_fdfj -+fclass_s 0000 00010001 01000 01101 ..... ..... @fmt_fdfj -+fclass_d 0000 00010001 01000 01110 ..... ..... @fmt_fdfj -+fsqrt_s 0000 00010001 01000 10001 ..... ..... @fmt_fdfj -+fsqrt_d 0000 00010001 01000 10010 ..... ..... @fmt_fdfj -+frecip_s 0000 00010001 01000 10101 ..... ..... @fmt_fdfj -+frecip_d 0000 00010001 01000 10110 ..... ..... @fmt_fdfj -+frsqrt_s 0000 00010001 01000 11001 ..... ..... @fmt_fdfj -+frsqrt_d 0000 00010001 01000 11010 ..... ..... @fmt_fdfj -+fmov_s 0000 00010001 01001 00101 ..... ..... @fmt_fdfj -+fmov_d 0000 00010001 01001 00110 ..... ..... @fmt_fdfj -+movgr2fr_w 0000 00010001 01001 01001 ..... ..... @fmt_fdrj -+movgr2fr_d 0000 00010001 01001 01010 ..... ..... @fmt_fdrj -+movgr2frh_w 0000 00010001 01001 01011 ..... ..... @fmt_fdrj -+movfr2gr_s 0000 00010001 01001 01101 ..... ..... @fmt_rdfj -+movfr2gr_d 0000 00010001 01001 01110 ..... ..... @fmt_rdfj -+movfrh2gr_s 0000 00010001 01001 01111 ..... ..... @fmt_rdfj -+movgr2fcsr 0000 00010001 01001 10000 ..... ..... @fmt_fcsrdrj -+movfcsr2gr 0000 00010001 01001 10010 ..... ..... @fmt_rdfcsrs -+movfr2cf 0000 00010001 01001 10100 ..... 00 ... @fmt_cdfj -+movcf2fr 0000 00010001 01001 10101 00 ... ..... @fmt_fdcj -+movgr2cf 0000 00010001 01001 10110 ..... 00 ... @fmt_cdrj -+movcf2gr 0000 00010001 01001 10111 00 ... ..... @fmt_rdcj -+fcvt_s_d 0000 00010001 10010 00110 ..... ..... @fmt_fdfj -+fcvt_d_s 0000 00010001 10010 01001 ..... ..... @fmt_fdfj -+ftintrm_w_s 0000 00010001 10100 00001 ..... ..... @fmt_fdfj -+ftintrm_w_d 0000 00010001 10100 00010 ..... ..... @fmt_fdfj -+ftintrm_l_s 0000 00010001 10100 01001 ..... ..... @fmt_fdfj -+ftintrm_l_d 0000 00010001 10100 01010 ..... ..... @fmt_fdfj -+ftintrp_w_s 0000 00010001 10100 10001 ..... ..... @fmt_fdfj -+ftintrp_w_d 0000 00010001 10100 10010 ..... ..... @fmt_fdfj -+ftintrp_l_s 0000 00010001 10100 11001 ..... ..... @fmt_fdfj -+ftintrp_l_d 0000 00010001 10100 11010 ..... ..... @fmt_fdfj -+ftintrz_w_s 0000 00010001 10101 00001 ..... ..... @fmt_fdfj -+ftintrz_w_d 0000 00010001 10101 00010 ..... ..... @fmt_fdfj -+ftintrz_l_s 0000 00010001 10101 01001 ..... ..... @fmt_fdfj -+ftintrz_l_d 0000 00010001 10101 01010 ..... ..... @fmt_fdfj -+ftintrne_w_s 0000 00010001 10101 10001 ..... ..... @fmt_fdfj -+ftintrne_w_d 0000 00010001 10101 10010 ..... ..... @fmt_fdfj -+ftintrne_l_s 0000 00010001 10101 11001 ..... ..... @fmt_fdfj -+ftintrne_l_d 0000 00010001 10101 11010 ..... ..... @fmt_fdfj -+ftint_w_s 0000 00010001 10110 00001 ..... ..... @fmt_fdfj -+ftint_w_d 0000 00010001 10110 00010 ..... ..... @fmt_fdfj -+ftint_l_s 0000 00010001 10110 01001 ..... ..... @fmt_fdfj -+ftint_l_d 0000 00010001 10110 01010 ..... ..... @fmt_fdfj -+ffint_s_w 0000 00010001 11010 00100 ..... ..... @fmt_fdfj -+ffint_s_l 0000 00010001 11010 00110 ..... ..... @fmt_fdfj -+ffint_d_w 0000 00010001 11010 01000 ..... ..... @fmt_fdfj -+ffint_d_l 0000 00010001 11010 01010 ..... ..... @fmt_fdfj -+frint_s 0000 00010001 11100 10001 ..... ..... @fmt_fdfj -+frint_d 0000 00010001 11100 10010 ..... ..... @fmt_fdfj -+ -+# 12 bit immediate Instructions -+slti 0000 001000 ............ ..... ..... @fmt_rdrjsi12 -+sltui 0000 001001 ............ ..... ..... @fmt_rdrjsi12 -+addi_w 0000 001010 ............ ..... ..... @fmt_rdrjsi12 -+addi_d 0000 001011 ............ ..... ..... @fmt_rdrjsi12 -+lu52i_d 0000 001100 ............ ..... ..... @fmt_rdrjsi12 -+andi 0000 001101 ............ ..... ..... @fmt_rdrjui12 -+ori 0000 001110 ............ ..... ..... @fmt_rdrjui12 -+xori 0000 001111 ............ ..... ..... @fmt_rdrjui12 -+ -+# core Instructions -+csrxchg 0000 0100 .............. ..... ..... @fmt_rdrjcsr -+cacop 0000 011000 ............ ..... ..... @fmt_coprjsi12 -+lddir 0000 01100100 00 ........ ..... ..... @fmt_rdrjlevel -+ldpte 0000 01100100 01 ........ ..... 00000 @fmt_rjseq -+iocsrrd_b 0000 01100100 10000 00000 ..... ..... @fmt_rdrj -+iocsrrd_h 0000 01100100 10000 00001 ..... ..... @fmt_rdrj -+iocsrrd_w 0000 01100100 10000 00010 ..... ..... @fmt_rdrj -+iocsrrd_d 0000 01100100 10000 00011 ..... ..... @fmt_rdrj -+iocsrwr_b 0000 01100100 10000 00100 ..... ..... @fmt_rdrj -+iocsrwr_h 0000 01100100 10000 00101 ..... ..... @fmt_rdrj -+iocsrwr_w 0000 01100100 10000 00110 ..... ..... @fmt_rdrj -+iocsrwr_d 0000 01100100 10000 00111 ..... ..... @fmt_rdrj -+tlbclr 0000 01100100 10000 01000 00000 00000 @fmt_empty -+tlbflush 0000 01100100 10000 01001 00000 00000 @fmt_empty -+tlbsrch 0000 01100100 10000 01010 00000 00000 @fmt_empty -+tlbrd 0000 01100100 10000 01011 00000 00000 @fmt_empty -+tlbwr 0000 01100100 10000 01100 00000 00000 @fmt_empty -+tlbfill 0000 01100100 10000 01101 00000 00000 @fmt_empty -+ertn 0000 01100100 10000 01110 00000 00000 @fmt_empty -+idle 0000 01100100 10001 ............... @fmt_whint -+invtlb 0000 01100100 10011 ..... ..... ..... @fmt_invtlb -+ -+# foure Op Instructions -+fmadd_s 0000 10000001 ..... ..... ..... ..... @fmt_fdfjfkfa -+fmadd_d 0000 10000010 ..... ..... ..... ..... @fmt_fdfjfkfa -+fmsub_s 0000 10000101 ..... ..... ..... ..... @fmt_fdfjfkfa -+fmsub_d 0000 10000110 ..... ..... ..... ..... @fmt_fdfjfkfa -+fnmadd_s 0000 10001001 ..... ..... ..... ..... @fmt_fdfjfkfa -+fnmadd_d 0000 10001010 ..... ..... ..... ..... @fmt_fdfjfkfa -+fnmsub_s 0000 10001101 ..... ..... ..... ..... @fmt_fdfjfkfa -+fnmsub_d 0000 10001110 ..... ..... ..... ..... @fmt_fdfjfkfa -+fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @fmt_cdfjfkfcond -+fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @fmt_cdfjfkfcond -+fsel 0000 11010000 00 ... ..... ..... ..... @fmt_fdfjfkca -+ -+# loog immediate Instructions -+addu16i_d 0001 00 ................ ..... ..... @fmt_rdrjsi16 -+lu12i_w 0001 010 .................... ..... @fmt_rdsi20 -+lu32i_d 0001 011 .................... ..... @fmt_rdsi20 -+pcaddi 0001 100 .................... ..... @fmt_rdsi20 -+pcalau12i 0001 101 .................... ..... @fmt_rdsi20 -+pcaddu12i 0001 110 .................... ..... @fmt_rdsi20 -+pcaddu18i 0001 111 .................... ..... @fmt_rdsi20 -+ -+# load/store Instructions -+ll_w 0010 0000 .............. ..... ..... @fmt_rdrjsi14 -+sc_w 0010 0001 .............. ..... ..... @fmt_rdrjsi14 -+ll_d 0010 0010 .............. ..... ..... @fmt_rdrjsi14 -+sc_d 0010 0011 .............. ..... ..... @fmt_rdrjsi14 -+ldptr_w 0010 0100 .............. ..... ..... @fmt_rdrjsi14 -+stptr_w 0010 0101 .............. ..... ..... @fmt_rdrjsi14 -+ldptr_d 0010 0110 .............. ..... ..... @fmt_rdrjsi14 -+stptr_d 0010 0111 .............. ..... ..... @fmt_rdrjsi14 -+ld_b 0010 100000 ............ ..... ..... @fmt_rdrjsi12 -+ld_h 0010 100001 ............ ..... ..... @fmt_rdrjsi12 -+ld_w 0010 100010 ............ ..... ..... @fmt_rdrjsi12 -+ld_d 0010 100011 ............ ..... ..... @fmt_rdrjsi12 -+st_b 0010 100100 ............ ..... ..... @fmt_rdrjsi12 -+st_h 0010 100101 ............ ..... ..... @fmt_rdrjsi12 -+st_w 0010 100110 ............ ..... ..... @fmt_rdrjsi12 -+st_d 0010 100111 ............ ..... ..... @fmt_rdrjsi12 -+ld_bu 0010 101000 ............ ..... ..... @fmt_rdrjsi12 -+ld_hu 0010 101001 ............ ..... ..... @fmt_rdrjsi12 -+ld_wu 0010 101010 ............ ..... ..... @fmt_rdrjsi12 -+preld 0010 101011 ............ ..... ..... @fmt_hintrjsi12 -+fld_s 0010 101100 ............ ..... ..... @fmt_fdrjsi12 -+fst_s 0010 101101 ............ ..... ..... @fmt_fdrjsi12 -+fld_d 0010 101110 ............ ..... ..... @fmt_fdrjsi12 -+fst_d 0010 101111 ............ ..... ..... @fmt_fdrjsi12 -+ldx_b 0011 10000000 00000 ..... ..... ..... @fmt_rdrjrk -+ldx_h 0011 10000000 01000 ..... ..... ..... @fmt_rdrjrk -+ldx_w 0011 10000000 10000 ..... ..... ..... @fmt_rdrjrk -+ldx_d 0011 10000000 11000 ..... ..... ..... @fmt_rdrjrk -+stx_b 0011 10000001 00000 ..... ..... ..... @fmt_rdrjrk -+stx_h 0011 10000001 01000 ..... ..... ..... @fmt_rdrjrk -+stx_w 0011 10000001 10000 ..... ..... ..... @fmt_rdrjrk -+stx_d 0011 10000001 11000 ..... ..... ..... @fmt_rdrjrk -+ldx_bu 0011 10000010 00000 ..... ..... ..... @fmt_rdrjrk -+ldx_hu 0011 10000010 01000 ..... ..... ..... @fmt_rdrjrk -+ldx_wu 0011 10000010 10000 ..... ..... ..... @fmt_rdrjrk -+fldx_s 0011 10000011 00000 ..... ..... ..... @fmt_fdrjrk -+fldx_d 0011 10000011 01000 ..... ..... ..... @fmt_fdrjrk -+fstx_s 0011 10000011 10000 ..... ..... ..... @fmt_fdrjrk -+fstx_d 0011 10000011 11000 ..... ..... ..... @fmt_fdrjrk -+amswap_w 0011 10000110 00000 ..... ..... ..... @fmt_rdrjrk -+amswap_d 0011 10000110 00001 ..... ..... ..... @fmt_rdrjrk -+amadd_w 0011 10000110 00010 ..... ..... ..... @fmt_rdrjrk -+amadd_d 0011 10000110 00011 ..... ..... ..... @fmt_rdrjrk -+amand_w 0011 10000110 00100 ..... ..... ..... @fmt_rdrjrk -+amand_d 0011 10000110 00101 ..... ..... ..... @fmt_rdrjrk -+amor_w 0011 10000110 00110 ..... ..... ..... @fmt_rdrjrk -+amor_d 0011 10000110 00111 ..... ..... ..... @fmt_rdrjrk -+amxor_w 0011 10000110 01000 ..... ..... ..... @fmt_rdrjrk -+amxor_d 0011 10000110 01001 ..... ..... ..... @fmt_rdrjrk -+ammax_w 0011 10000110 01010 ..... ..... ..... @fmt_rdrjrk -+ammax_d 0011 10000110 01011 ..... ..... ..... @fmt_rdrjrk -+ammin_w 0011 10000110 01100 ..... ..... ..... @fmt_rdrjrk -+ammin_d 0011 10000110 01101 ..... ..... ..... @fmt_rdrjrk -+ammax_wu 0011 10000110 01110 ..... ..... ..... @fmt_rdrjrk -+ammax_du 0011 10000110 01111 ..... ..... ..... @fmt_rdrjrk -+ammin_wu 0011 10000110 10000 ..... ..... ..... @fmt_rdrjrk -+ammin_du 0011 10000110 10001 ..... ..... ..... @fmt_rdrjrk -+amswap_db_w 0011 10000110 10010 ..... ..... ..... @fmt_rdrjrk -+amswap_db_d 0011 10000110 10011 ..... ..... ..... @fmt_rdrjrk -+amadd_db_w 0011 10000110 10100 ..... ..... ..... @fmt_rdrjrk -+amadd_db_d 0011 10000110 10101 ..... ..... ..... @fmt_rdrjrk -+amand_db_w 0011 10000110 10110 ..... ..... ..... @fmt_rdrjrk -+amand_db_d 0011 10000110 10111 ..... ..... ..... @fmt_rdrjrk -+amor_db_w 0011 10000110 11000 ..... ..... ..... @fmt_rdrjrk -+amor_db_d 0011 10000110 11001 ..... ..... ..... @fmt_rdrjrk -+amxor_db_w 0011 10000110 11010 ..... ..... ..... @fmt_rdrjrk -+amxor_db_d 0011 10000110 11011 ..... ..... ..... @fmt_rdrjrk -+ammax_db_w 0011 10000110 11100 ..... ..... ..... @fmt_rdrjrk -+ammax_db_d 0011 10000110 11101 ..... ..... ..... @fmt_rdrjrk -+ammin_db_w 0011 10000110 11110 ..... ..... ..... @fmt_rdrjrk -+ammin_db_d 0011 10000110 11111 ..... ..... ..... @fmt_rdrjrk -+ammax_db_wu 0011 10000111 00000 ..... ..... ..... @fmt_rdrjrk -+ammax_db_du 0011 10000111 00001 ..... ..... ..... @fmt_rdrjrk -+ammin_db_wu 0011 10000111 00010 ..... ..... ..... @fmt_rdrjrk -+ammin_db_du 0011 10000111 00011 ..... ..... ..... @fmt_rdrjrk -+dbar 0011 10000111 00100 ............... @fmt_whint -+ibar 0011 10000111 00101 ............... @fmt_whint -+fldgt_s 0011 10000111 01000 ..... ..... ..... @fmt_fdrjrk -+fldgt_d 0011 10000111 01001 ..... ..... ..... @fmt_fdrjrk -+fldle_s 0011 10000111 01010 ..... ..... ..... @fmt_fdrjrk -+fldle_d 0011 10000111 01011 ..... ..... ..... @fmt_fdrjrk -+fstgt_s 0011 10000111 01100 ..... ..... ..... @fmt_fdrjrk -+fstgt_d 0011 10000111 01101 ..... ..... ..... @fmt_fdrjrk -+fstle_s 0011 10000111 01110 ..... ..... ..... @fmt_fdrjrk -+fstle_d 0011 10000111 01111 ..... ..... ..... @fmt_fdrjrk -+ldgt_b 0011 10000111 10000 ..... ..... ..... @fmt_rdrjrk -+ldgt_h 0011 10000111 10001 ..... ..... ..... @fmt_rdrjrk -+ldgt_w 0011 10000111 10010 ..... ..... ..... @fmt_rdrjrk -+ldgt_d 0011 10000111 10011 ..... ..... ..... @fmt_rdrjrk -+ldle_b 0011 10000111 10100 ..... ..... ..... @fmt_rdrjrk -+ldle_h 0011 10000111 10101 ..... ..... ..... @fmt_rdrjrk -+ldle_w 0011 10000111 10110 ..... ..... ..... @fmt_rdrjrk -+ldle_d 0011 10000111 10111 ..... ..... ..... @fmt_rdrjrk -+stgt_b 0011 10000111 11000 ..... ..... ..... @fmt_rdrjrk -+stgt_h 0011 10000111 11001 ..... ..... ..... @fmt_rdrjrk -+stgt_w 0011 10000111 11010 ..... ..... ..... @fmt_rdrjrk -+stgt_d 0011 10000111 11011 ..... ..... ..... @fmt_rdrjrk -+stle_b 0011 10000111 11100 ..... ..... ..... @fmt_rdrjrk -+stle_h 0011 10000111 11101 ..... ..... ..... @fmt_rdrjrk -+stle_w 0011 10000111 11110 ..... ..... ..... @fmt_rdrjrk -+stle_d 0011 10000111 11111 ..... ..... ..... @fmt_rdrjrk -+ -+# jump Instructions -+beqz 0100 00 ................ ..... ..... @fmt_rjoffs21 -+bnez 0100 01 ................ ..... ..... @fmt_rjoffs21 -+bceqz 0100 10 ................ 00 ... ..... @fmt_cjoffs21 -+bcnez 0100 10 ................ 01 ... ..... @fmt_cjoffs21 -+jirl 0100 11 ................ ..... ..... @fmt_rdrjoffs16 -+b 0101 00 .......................... @fmt_offs -+bl 0101 01 .......................... @fmt_offs -+beq 0101 10 ................ ..... ..... @fmt_rjrdoffs16 -+bne 0101 11 ................ ..... ..... @fmt_rjrdoffs16 -+blt 0110 00 ................ ..... ..... @fmt_rjrdoffs16 -+bge 0110 01 ................ ..... ..... @fmt_rjrdoffs16 -+bltu 0110 10 ................ ..... ..... @fmt_rjrdoffs16 -+bgeu 0110 11 ................ ..... ..... @fmt_rjrdoffs16 -diff --git a/target/loongarch64/instmap.h b/target/loongarch64/instmap.h -new file mode 100644 -index 000000000..6e85847f8 ---- /dev/null -+++ b/target/loongarch64/instmap.h -@@ -0,0 +1,216 @@ -+/* -+ * Loongarch emulation for qemu: instruction opcode -+ * -+ * Copyright (c) 2020-2021 -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program. If not, see . -+ */ -+ -+#ifndef TARGET_LARCH_INSTMAP_H -+#define TARGET_LARCH_INSTMAP_H -+ -+enum { -+ /* fix opcodes */ -+ OPC_LARCH_CLO_W = (0x000004 << 10), -+ OPC_LARCH_CLZ_W = (0x000005 << 10), -+ OPC_LARCH_CLO_D = (0x000008 << 10), -+ OPC_LARCH_CLZ_D = (0x000009 << 10), -+ OPC_LARCH_REVB_2H = (0x00000C << 10), -+ OPC_LARCH_REVB_4H = (0x00000D << 10), -+ OPC_LARCH_REVH_D = (0x000011 << 10), -+ OPC_LARCH_BREV_4B = (0x000012 << 10), -+ OPC_LARCH_BREV_8B = (0x000013 << 10), -+ OPC_LARCH_EXT_WH = (0x000016 << 10), -+ OPC_LARCH_EXT_WB = (0x000017 << 10), -+ -+ OPC_LARCH_ADD_W = (0x00020 << 15), -+ OPC_LARCH_ADD_D = (0x00021 << 15), -+ OPC_LARCH_SUB_W = (0x00022 << 15), -+ OPC_LARCH_SUB_D = (0x00023 << 15), -+ OPC_LARCH_SLT = (0x00024 << 15), -+ OPC_LARCH_SLTU = (0x00025 << 15), -+ OPC_LARCH_MASKEQZ = (0x00026 << 15), -+ OPC_LARCH_MASKNEZ = (0x00027 << 15), -+ OPC_LARCH_NOR = (0x00028 << 15), -+ OPC_LARCH_AND = (0x00029 << 15), -+ OPC_LARCH_OR = (0x0002A << 15), -+ OPC_LARCH_XOR = (0x0002B << 15), -+ OPC_LARCH_SLL_W = (0x0002E << 15), -+ OPC_LARCH_SRL_W = (0x0002F << 15), -+ OPC_LARCH_SRA_W = (0x00030 << 15), -+ OPC_LARCH_SLL_D = (0x00031 << 15), -+ OPC_LARCH_SRL_D = (0x00032 << 15), -+ OPC_LARCH_SRA_D = (0x00033 << 15), -+ OPC_LARCH_ROTR_W = (0x00036 << 15), -+ OPC_LARCH_ROTR_D = (0x00037 << 15), -+ OPC_LARCH_MUL_W = (0x00038 << 15), -+ OPC_LARCH_MULH_W = (0x00039 << 15), -+ OPC_LARCH_MULH_WU = (0x0003A << 15), -+ OPC_LARCH_MUL_D = (0x0003B << 15), -+ OPC_LARCH_MULH_D = (0x0003C << 15), -+ OPC_LARCH_MULH_DU = (0x0003D << 15), -+ OPC_LARCH_DIV_W = (0x00040 << 15), -+ OPC_LARCH_MOD_W = (0x00041 << 15), -+ OPC_LARCH_DIV_WU = (0x00042 << 15), -+ OPC_LARCH_MOD_WU = (0x00043 << 15), -+ OPC_LARCH_DIV_D = (0x00044 << 15), -+ OPC_LARCH_MOD_D = (0x00045 << 15), -+ OPC_LARCH_DIV_DU = (0x00046 << 15), -+ OPC_LARCH_MOD_DU = (0x00047 << 15), -+ OPC_LARCH_SRLI_W = (0x00089 << 15), -+ OPC_LARCH_SRAI_W = (0x00091 << 15), -+ OPC_LARCH_ROTRI_W = (0x00099 << 15), -+ -+ OPC_LARCH_ALSL_W = (0x0002 << 17), -+ OPC_LARCH_ALSL_D = (0x0016 << 17), -+ -+ OPC_LARCH_TRINS_W = (0x003 << 21) | (0x0 << 15), -+ OPC_LARCH_TRPICK_W = (0x003 << 21) | (0x1 << 15), -+}; -+ -+enum { -+ /* float opcodes */ -+ OPC_LARCH_FABS_S = (0x004501 << 10), -+ OPC_LARCH_FABS_D = (0x004502 << 10), -+ OPC_LARCH_FNEG_S = (0x004505 << 10), -+ OPC_LARCH_FNEG_D = (0x004506 << 10), -+ OPC_LARCH_FCLASS_S = (0x00450D << 10), -+ OPC_LARCH_FCLASS_D = (0x00450E << 10), -+ OPC_LARCH_FSQRT_S = (0x004511 << 10), -+ OPC_LARCH_FSQRT_D = (0x004512 << 10), -+ OPC_LARCH_FRECIP_S = (0x004515 << 10), -+ OPC_LARCH_FRECIP_D = (0x004516 << 10), -+ OPC_LARCH_FRSQRT_S = (0x004519 << 10), -+ OPC_LARCH_FRSQRT_D = (0x00451A << 10), -+ OPC_LARCH_FMOV_S = (0x004525 << 10), -+ OPC_LARCH_FMOV_D = (0x004526 << 10), -+ OPC_LARCH_GR2FR_W = (0x004529 << 10), -+ OPC_LARCH_GR2FR_D = (0x00452A << 10), -+ OPC_LARCH_GR2FRH_W = (0x00452B << 10), -+ OPC_LARCH_FR2GR_S = (0x00452D << 10), -+ OPC_LARCH_FR2GR_D = (0x00452E << 10), -+ OPC_LARCH_FRH2GR_S = (0x00452F << 10), -+ -+ OPC_LARCH_FCVT_S_D = (0x004646 << 10), -+ OPC_LARCH_FCVT_D_S = (0x004649 << 10), -+ OPC_LARCH_FTINTRM_W_S = (0x004681 << 10), -+ OPC_LARCH_FTINTRM_W_D = (0x004682 << 10), -+ OPC_LARCH_FTINTRM_L_S = (0x004689 << 10), -+ OPC_LARCH_FTINTRM_L_D = (0x00468A << 10), -+ OPC_LARCH_FTINTRP_W_S = (0x004691 << 10), -+ OPC_LARCH_FTINTRP_W_D = (0x004692 << 10), -+ OPC_LARCH_FTINTRP_L_S = (0x004699 << 10), -+ OPC_LARCH_FTINTRP_L_D = (0x00469A << 10), -+ OPC_LARCH_FTINTRZ_W_S = (0x0046A1 << 10), -+ OPC_LARCH_FTINTRZ_W_D = (0x0046A2 << 10), -+ OPC_LARCH_FTINTRZ_L_S = (0x0046A9 << 10), -+ OPC_LARCH_FTINTRZ_L_D = (0x0046AA << 10), -+ OPC_LARCH_FTINTRNE_W_S = (0x0046B1 << 10), -+ OPC_LARCH_FTINTRNE_W_D = (0x0046B2 << 10), -+ OPC_LARCH_FTINTRNE_L_S = (0x0046B9 << 10), -+ OPC_LARCH_FTINTRNE_L_D = (0x0046BA << 10), -+ OPC_LARCH_FTINT_W_S = (0x0046C1 << 10), -+ OPC_LARCH_FTINT_W_D = (0x0046C2 << 10), -+ OPC_LARCH_FTINT_L_S = (0x0046C9 << 10), -+ OPC_LARCH_FTINT_L_D = (0x0046CA << 10), -+ OPC_LARCH_FFINT_S_W = (0x004744 << 10), -+ OPC_LARCH_FFINT_S_L = (0x004746 << 10), -+ OPC_LARCH_FFINT_D_W = (0x004748 << 10), -+ OPC_LARCH_FFINT_D_L = (0x00474A << 10), -+ OPC_LARCH_FRINT_S = (0x004791 << 10), -+ OPC_LARCH_FRINT_D = (0x004792 << 10), -+ -+ OPC_LARCH_FADD_S = (0x00201 << 15), -+ OPC_LARCH_FADD_D = (0x00202 << 15), -+ OPC_LARCH_FSUB_S = (0x00205 << 15), -+ OPC_LARCH_FSUB_D = (0x00206 << 15), -+ OPC_LARCH_FMUL_S = (0x00209 << 15), -+ OPC_LARCH_FMUL_D = (0x0020A << 15), -+ OPC_LARCH_FDIV_S = (0x0020D << 15), -+ OPC_LARCH_FDIV_D = (0x0020E << 15), -+ OPC_LARCH_FMAX_S = (0x00211 << 15), -+ OPC_LARCH_FMAX_D = (0x00212 << 15), -+ OPC_LARCH_FMIN_S = (0x00215 << 15), -+ OPC_LARCH_FMIN_D = (0x00216 << 15), -+ OPC_LARCH_FMAXA_S = (0x00219 << 15), -+ OPC_LARCH_FMAXA_D = (0x0021A << 15), -+ OPC_LARCH_FMINA_S = (0x0021D << 15), -+ OPC_LARCH_FMINA_D = (0x0021E << 15), -+}; -+ -+enum { -+ /* 12 bit immediate opcodes */ -+ OPC_LARCH_SLTI = (0x008 << 22), -+ OPC_LARCH_SLTIU = (0x009 << 22), -+ OPC_LARCH_ADDI_W = (0x00A << 22), -+ OPC_LARCH_ADDI_D = (0x00B << 22), -+ OPC_LARCH_ANDI = (0x00D << 22), -+ OPC_LARCH_ORI = (0x00E << 22), -+ OPC_LARCH_XORI = (0x00F << 22), -+}; -+ -+enum { -+ /* load/store opcodes */ -+ OPC_LARCH_FLDX_S = (0x07060 << 15), -+ OPC_LARCH_FLDX_D = (0x07068 << 15), -+ OPC_LARCH_FSTX_S = (0x07070 << 15), -+ OPC_LARCH_FSTX_D = (0x07078 << 15), -+ OPC_LARCH_FLDGT_S = (0x070E8 << 15), -+ OPC_LARCH_FLDGT_D = (0x070E9 << 15), -+ OPC_LARCH_FLDLE_S = (0x070EA << 15), -+ OPC_LARCH_FLDLE_D = (0x070EB << 15), -+ OPC_LARCH_FSTGT_S = (0x070EC << 15), -+ OPC_LARCH_FSTGT_D = (0x070ED << 15), -+ OPC_LARCH_FSTLE_S = (0x070EE << 15), -+ OPC_LARCH_FSTLE_D = (0x070EF << 15), -+ -+ OPC_LARCH_LD_B = (0x0A0 << 22), -+ OPC_LARCH_LD_H = (0x0A1 << 22), -+ OPC_LARCH_LD_W = (0x0A2 << 22), -+ OPC_LARCH_LD_D = (0x0A3 << 22), -+ OPC_LARCH_ST_B = (0x0A4 << 22), -+ OPC_LARCH_ST_H = (0x0A5 << 22), -+ OPC_LARCH_ST_W = (0x0A6 << 22), -+ OPC_LARCH_ST_D = (0x0A7 << 22), -+ OPC_LARCH_LD_BU = (0x0A8 << 22), -+ OPC_LARCH_LD_HU = (0x0A9 << 22), -+ OPC_LARCH_LD_WU = (0x0AA << 22), -+ OPC_LARCH_FLD_S = (0x0AC << 22), -+ OPC_LARCH_FST_S = (0x0AD << 22), -+ OPC_LARCH_FLD_D = (0x0AE << 22), -+ OPC_LARCH_FST_D = (0x0AF << 22), -+ -+ OPC_LARCH_LL_W = (0x20 << 24), -+ OPC_LARCH_SC_W = (0x21 << 24), -+ OPC_LARCH_LL_D = (0x22 << 24), -+ OPC_LARCH_SC_D = (0x23 << 24), -+ OPC_LARCH_LDPTR_W = (0x24 << 24), -+ OPC_LARCH_STPTR_W = (0x25 << 24), -+ OPC_LARCH_LDPTR_D = (0x26 << 24), -+ OPC_LARCH_STPTR_D = (0x27 << 24), -+}; -+ -+enum { -+ /* jump opcodes */ -+ OPC_LARCH_BEQZ = (0x10 << 26), -+ OPC_LARCH_BNEZ = (0x11 << 26), -+ OPC_LARCH_B = (0x14 << 26), -+ OPC_LARCH_BEQ = (0x16 << 26), -+ OPC_LARCH_BNE = (0x17 << 26), -+ OPC_LARCH_BLT = (0x18 << 26), -+ OPC_LARCH_BGE = (0x19 << 26), -+ OPC_LARCH_BLTU = (0x1A << 26), -+ OPC_LARCH_BGEU = (0x1B << 26), -+}; -+ -+#endif -diff --git a/target/loongarch64/internal.h b/target/loongarch64/internal.h -new file mode 100644 -index 000000000..43594c5ac ---- /dev/null -+++ b/target/loongarch64/internal.h -@@ -0,0 +1,184 @@ -+#ifndef LOONGARCH_INTERNAL_H -+#define LOONGARCH_INTERNAL_H -+ -+#include "cpu-csr.h" -+ -+/* MMU types, the first four entries have the same layout as the -+ CP0C0_MT field. */ -+enum loongarch_mmu_types { -+ MMU_TYPE_NONE, -+ MMU_TYPE_LS3A5K, /* LISA CSR */ -+}; -+ -+ -+ -+struct loongarch_def_t { -+ const char *name; -+ int32_t CSR_PRid; -+ int32_t FCSR0; -+ int32_t FCSR0_rw_bitmask; -+ int32_t PABITS; -+ CPU_LOONGARCH_CSR -+ uint64_t insn_flags; -+ enum loongarch_mmu_types mmu_type; -+ int cpu_cfg[64]; -+}; -+ -+/* loongarch 3a5000 TLB entry */ -+struct ls3a5k_tlb_t { -+ target_ulong VPN; -+ uint64_t PageMask; /* CSR_TLBIDX[29:24] */ -+ uint32_t PageSize; -+ uint16_t ASID; -+ unsigned int G:1; /* CSR_TLBLO[6] */ -+ -+ unsigned int C0:3; /* CSR_TLBLO[5:4] */ -+ unsigned int C1:3; -+ -+ unsigned int V0:1; /* CSR_TLBLO[0] */ -+ unsigned int V1:1; -+ -+ unsigned int WE0:1; /* CSR_TLBLO[1] */ -+ unsigned int WE1:1; -+ -+ unsigned int XI0:1; /* CSR_TLBLO[62] */ -+ unsigned int XI1:1; -+ -+ unsigned int RI0:1; /* CSR_TLBLO[61] */ -+ unsigned int RI1:1; -+ -+ unsigned int EHINV:1;/* CSR_TLBIDX[31] */ -+ -+ unsigned int PLV0:2; /* CSR_TLBLO[3:2] */ -+ unsigned int PLV1:2; -+ -+ unsigned int RPLV0:1; -+ unsigned int RPLV1:1; /* CSR_TLBLO[63] */ -+ -+ uint64_t PPN0; /* CSR_TLBLO[47:12] */ -+ uint64_t PPN1; /* CSR_TLBLO[47:12] */ -+}; -+typedef struct ls3a5k_tlb_t ls3a5k_tlb_t; -+ -+ -+struct CPULOONGARCHTLBContext { -+ uint32_t nb_tlb; -+ uint32_t tlb_in_use; -+ int (*map_address)(struct CPULOONGARCHState *env, hwaddr *physical, int *prot, -+ target_ulong address, int rw, int access_type); -+ void (*helper_tlbwr)(struct CPULOONGARCHState *env); -+ void (*helper_tlbfill)(struct CPULOONGARCHState *env); -+ void (*helper_tlbsrch)(struct CPULOONGARCHState *env); -+ void (*helper_tlbrd)(struct CPULOONGARCHState *env); -+ void (*helper_tlbclr)(struct CPULOONGARCHState *env); -+ void (*helper_tlbflush)(struct CPULOONGARCHState *env); -+ void (*helper_invtlb)(struct CPULOONGARCHState *env, target_ulong addr, -+ target_ulong info, int op); -+ union { -+ struct { -+ uint64_t ftlb_mask; -+ uint32_t ftlb_size; /* at most : 8 * 256 = 2048 */ -+ uint32_t vtlb_size; /* at most : 64 */ -+ ls3a5k_tlb_t tlb[2048 + 64]; /* at most : 2048 FTLB + 64 VTLB */ -+ } ls3a5k; -+ } mmu; -+}; -+ -+enum { -+ TLBRET_PE = -7, -+ TLBRET_XI = -6, -+ TLBRET_RI = -5, -+ TLBRET_DIRTY = -4, -+ TLBRET_INVALID = -3, -+ TLBRET_NOMATCH = -2, -+ TLBRET_BADADDR = -1, -+ TLBRET_MATCH = 0 -+}; -+ -+ -+extern unsigned int ieee_rm[]; -+ -+static inline void restore_rounding_mode(CPULOONGARCHState *env) -+{ -+ set_float_rounding_mode(ieee_rm[(env->active_fpu.fcsr0 >> FCSR0_RM) & 0x3], -+ &env->active_fpu.fp_status); -+} -+ -+static inline void restore_flush_mode(CPULOONGARCHState *env) -+{ -+ set_flush_to_zero(0, &env->active_fpu.fp_status); -+} -+ -+static inline void restore_fp_status(CPULOONGARCHState *env) -+{ -+ restore_rounding_mode(env); -+ restore_flush_mode(env); -+} -+static inline void compute_hflags(CPULOONGARCHState *env) -+{ -+ env->hflags &= ~(LARCH_HFLAG_64 | LARCH_HFLAG_FPU | LARCH_HFLAG_KSU | -+ LARCH_HFLAG_AWRAP | LARCH_HFLAG_LSX | LARCH_HFLAG_LASX); -+ -+ env->hflags |= (env->CSR_CRMD & CSR_CRMD_PLV); -+ env->hflags |= LARCH_HFLAG_64; -+ -+ if (env->CSR_EUEN & CSR_EUEN_FPEN) { -+ env->hflags |= LARCH_HFLAG_FPU; -+ } -+ if (env->CSR_EUEN & CSR_EUEN_LSXEN) { -+ env->hflags |= LARCH_HFLAG_LSX; -+ } -+ if (env->CSR_EUEN & CSR_EUEN_LASXEN) { -+ env->hflags |= LARCH_HFLAG_LASX; -+ } -+ if (env->CSR_EUEN & CSR_EUEN_LBTEN) { -+ env->hflags |= LARCH_HFLAG_LBT; -+ } -+} -+ -+/* Check if there is pending and not masked out interrupt */ -+static inline bool cpu_loongarch_hw_interrupts_pending(CPULOONGARCHState *env) -+{ -+ int32_t pending; -+ int32_t status; -+ bool r; -+ -+ pending = env->CSR_ESTAT & CSR_ESTAT_IPMASK; -+ status = env->CSR_ECFG & CSR_ECFG_IPMASK; -+ -+ /* Configured with compatibility or VInt (Vectored Interrupts) -+ treats the pending lines as individual interrupt lines, the status -+ lines are individual masks. */ -+ r = (pending & status) != 0; -+ -+ return r; -+} -+ -+ -+/* stabletimer.c */ -+uint32_t cpu_loongarch_get_random_ls3a5k_tlb(uint32_t low, uint32_t high); -+uint64_t cpu_loongarch_get_stable_counter(CPULOONGARCHState *env); -+uint64_t cpu_loongarch_get_stable_timer_ticks(CPULOONGARCHState *env); -+void cpu_loongarch_store_stable_timer_config(CPULOONGARCHState *env, uint64_t value); -+int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, -+ int cpuid, DumpState *s); -+ -+void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -+ -+/* TODO QOM'ify CPU reset and remove */ -+void cpu_state_reset(CPULOONGARCHState *s); -+void cpu_loongarch_realize_env(CPULOONGARCHState *env); -+ -+int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); -+int loongarch_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -+ -+#ifdef CONFIG_TCG -+#include "fpu_helper.h" -+#endif -+ -+#ifndef CONFIG_USER_ONLY -+extern const struct VMStateDescription vmstate_loongarch_cpu; -+hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -+#endif -+ -+#endif -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -new file mode 100644 -index 000000000..404a605eb ---- /dev/null -+++ b/target/loongarch64/kvm.c -@@ -0,0 +1,1622 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * KVM/LOONGARCH: LOONGARCH specific KVM APIs -+ * -+ * Copyright (C) 2012-2014 Imagination Technologies Ltd. -+ * Authors: Sanjay Lal -+*/ -+ -+#include "qemu/osdep.h" -+#include -+ -+#include -+ -+#include "qemu-common.h" -+#include "cpu.h" -+#include "internal.h" -+#include "qemu/error-report.h" -+#include "qemu/timer.h" -+#include "qemu/main-loop.h" -+#include "sysemu/sysemu.h" -+#include "sysemu/kvm.h" -+#include "sysemu/runstate.h" -+#include "sysemu/cpus.h" -+#include "kvm_larch.h" -+#include "exec/memattrs.h" -+#include "exec/gdbstub.h" -+ -+#define DEBUG_KVM 0 -+/* A 16384-byte buffer can hold the 8-byte kvm_msrs header, plus -+ * 2047 kvm_msr_entry structs */ -+#define MSR_BUF_SIZE 16384 -+ -+#define DPRINTF(fmt, ...) \ -+ do { if (DEBUG_KVM) { fprintf(stderr, fmt, ## __VA_ARGS__); } } while (0) -+ -+/* -+ * Define loongarch kvm version. -+ * Add version number when -+ * qemu/kvm interface changed -+ */ -+#define KVM_LOONGARCH_VERSION 1 -+ -+static struct { -+ target_ulong addr; -+ int len; -+ int type; -+} inst_breakpoint[8], data_breakpoint[8]; -+ -+int nb_data_breakpoint = 0, nb_inst_breakpoint = 0; -+static int kvm_loongarch_version_cap; -+ -+/* Hardware breakpoint control register -+ * 4:1 plv0-plv3 enable -+ * 6:5 config virtualization mode -+ * 9:8 load store */ -+static const int type_code[] = { -+ [GDB_BREAKPOINT_HW] = 0x5e, -+ [GDB_WATCHPOINT_READ] = (0x5e | 1 << 8), -+ [GDB_WATCHPOINT_WRITE] = (0x5e | 1 << 9), -+ [GDB_WATCHPOINT_ACCESS] = (0x5e | 1 << 8 | 1 << 9) -+}; -+ -+const KVMCapabilityInfo kvm_arch_required_capabilities[] = { -+ KVM_CAP_LAST_INFO -+}; -+ -+static void kvm_loongarch_update_state(void *opaque, bool running, RunState state); -+static inline int kvm_larch_putq(CPUState *cs, uint64_t reg_id, uint64_t *addr); -+ -+unsigned long kvm_arch_vcpu_id(CPUState *cs) -+{ -+ return cs->cpu_index; -+} -+ -+int kvm_arch_init(MachineState *ms, KVMState *s) -+{ -+ /* LOONGARCH has 128 signals */ -+ kvm_set_sigmask_len(s, 16); -+ -+ kvm_loongarch_version_cap = kvm_check_extension(s, KVM_CAP_LOONGARCH_VZ); -+ -+ if (kvm_loongarch_version_cap != KVM_LOONGARCH_VERSION) { -+ warn_report("QEMU/KVM version not match, qemu_la_version: lvz-%d,\ -+ kvm_la_version: lvz-%d \n", -+ KVM_LOONGARCH_VERSION, kvm_loongarch_version_cap); -+ } -+ return 0; -+} -+ -+int kvm_arch_irqchip_create(KVMState *s) -+{ -+ return 0; -+} -+ -+int kvm_arch_init_vcpu(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ int ret = 0; -+ -+ cpu->cpuStateEntry = qemu_add_vm_change_state_handler(kvm_loongarch_update_state, cs); -+ cpu->kvm_msr_buf = g_malloc0(MSR_BUF_SIZE); -+ DPRINTF("%s\n", __func__); -+ return ret; -+} -+ -+int kvm_arch_destroy_vcpu(CPUState *cs) -+{ -+ return 0; -+} -+ -+static void kvm_msr_buf_reset(LOONGARCHCPU *cpu) -+{ -+ memset(cpu->kvm_msr_buf, 0, MSR_BUF_SIZE); -+} -+ -+static void kvm_msr_entry_add(LOONGARCHCPU *cpu, uint32_t index, uint64_t value) -+{ -+ struct kvm_msrs *msrs = cpu->kvm_msr_buf; -+ void *limit = ((void *)msrs) + MSR_BUF_SIZE; -+ struct kvm_csr_entry *entry = &msrs->entries[msrs->ncsrs]; -+ -+ assert((void *)(entry + 1) <= limit); -+ -+ entry->index = index; -+ entry->reserved = 0; -+ entry->data = value; -+ msrs->ncsrs++; -+} -+ -+void kvm_loongarch_reset_vcpu(LOONGARCHCPU *cpu) -+{ -+ int ret = 0; -+ uint64_t reset = 1; -+ -+ if (CPU(cpu)->kvm_fd > 0) { -+ ret = kvm_larch_putq(CPU(cpu), KVM_REG_LOONGARCH_VCPU_RESET, &reset); -+ if (ret < 0) { -+ error_report("%s reset vcpu failed:%d", __func__, ret); -+ } -+ } -+ -+ DPRINTF("%s\n", __func__); -+} -+ -+void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) -+{ -+ int n; -+ if (kvm_sw_breakpoints_active(cpu)) { -+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; -+ } -+ if (nb_data_breakpoint > 0) { -+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; -+ for (n = 0; n < nb_data_breakpoint; n++) { -+ dbg->arch.data_breakpoint[n].addr = data_breakpoint[n].addr; -+ dbg->arch.data_breakpoint[n].mask = 0; -+ dbg->arch.data_breakpoint[n].asid = 0; -+ dbg->arch.data_breakpoint[n].ctrl = type_code[data_breakpoint[n].type]; -+ } -+ dbg->arch.data_bp_nums = nb_data_breakpoint; -+ } else { -+ dbg->arch.data_bp_nums = 0; -+ } -+ if (nb_inst_breakpoint > 0) { -+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; -+ for (n = 0; n < nb_inst_breakpoint; n++) { -+ dbg->arch.inst_breakpoint[n].addr = inst_breakpoint[n].addr; -+ dbg->arch.inst_breakpoint[n].mask = 0; -+ dbg->arch.inst_breakpoint[n].asid = 0; -+ dbg->arch.inst_breakpoint[n].ctrl = type_code[inst_breakpoint[n].type]; -+ } -+ dbg->arch.inst_bp_nums = nb_inst_breakpoint; -+ } else { -+ dbg->arch.inst_bp_nums = 0; -+ } -+} -+ -+static const unsigned int brk_insn = 0x002b8005; -+ -+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) -+{ -+ DPRINTF("%s\n", __func__); -+ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || -+ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) { -+ error_report("%s failed", __func__); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) -+{ -+ static uint32_t brk; -+ -+ DPRINTF("%s\n", __func__); -+ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) || -+ brk != brk_insn || -+ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) { -+ error_report("%s failed", __func__); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static int find_hw_breakpoint(uint64_t addr, int len, int type) -+{ -+ int n; -+ switch (type) { -+ case GDB_BREAKPOINT_HW: -+ if (nb_inst_breakpoint == 0) { -+ return -1; -+ } -+ for (n = 0; n < nb_inst_breakpoint; n++) { -+ if (inst_breakpoint[n].addr == addr && inst_breakpoint[n].type == type) { -+ return n; -+ } -+ } -+ break; -+ case GDB_WATCHPOINT_WRITE: -+ case GDB_WATCHPOINT_READ: -+ case GDB_WATCHPOINT_ACCESS: -+ if (nb_data_breakpoint == 0) { -+ return -1; -+ } -+ for (n = 0; n < nb_data_breakpoint; n++) { -+ if (data_breakpoint[n].addr == addr && data_breakpoint[n].type == type && -+ data_breakpoint[n].len == len) { -+ return n; -+ } -+ } -+ break; -+ default: -+ return -1; -+ } -+ return -1; -+} -+ -+int kvm_arch_insert_hw_breakpoint(target_ulong addr, -+ target_ulong len, int type) -+{ -+ switch (type) { -+ case GDB_BREAKPOINT_HW: -+ len = 1; -+ if (nb_inst_breakpoint == 8) { -+ return -ENOBUFS; -+ } -+ if (find_hw_breakpoint(addr, len, type) >= 0) { -+ return -EEXIST; -+ } -+ inst_breakpoint[nb_inst_breakpoint].addr = addr; -+ inst_breakpoint[nb_inst_breakpoint].len = len; -+ inst_breakpoint[nb_inst_breakpoint].type = type; -+ nb_inst_breakpoint++; -+ break; -+ case GDB_WATCHPOINT_WRITE: -+ case GDB_WATCHPOINT_READ: -+ case GDB_WATCHPOINT_ACCESS: -+ switch (len) { -+ case 1: -+ case 2: -+ case 4: -+ case 8: -+ if (addr & (len - 1)) { -+ return -EINVAL; -+ } -+ if (nb_data_breakpoint == 8) { -+ return -ENOBUFS; -+ } -+ if (find_hw_breakpoint(addr, len, type) >= 0) { -+ return -EEXIST; -+ } -+ data_breakpoint[nb_data_breakpoint].addr = addr; -+ data_breakpoint[nb_data_breakpoint].len = len; -+ data_breakpoint[nb_data_breakpoint].type = type; -+ nb_data_breakpoint++; -+ break; -+ default: -+ return -EINVAL; -+ } -+ break; -+ default: -+ return -ENOSYS; -+ } -+ return 0; -+} -+ -+int kvm_arch_remove_hw_breakpoint(target_ulong addr, -+ target_ulong len, int type) -+{ -+ int n; -+ n = find_hw_breakpoint(addr, (type == GDB_BREAKPOINT_HW) ? 1 : len, type); -+ if (n < 0) { -+ printf("err not find remove target\n"); -+ return -ENOENT; -+ } -+ switch (type) { -+ case GDB_BREAKPOINT_HW: -+ nb_inst_breakpoint--; -+ inst_breakpoint[n] = inst_breakpoint[nb_inst_breakpoint]; -+ break; -+ case GDB_WATCHPOINT_WRITE: -+ case GDB_WATCHPOINT_READ: -+ case GDB_WATCHPOINT_ACCESS: -+ nb_data_breakpoint--; -+ data_breakpoint[n] = data_breakpoint[nb_data_breakpoint]; -+ break; -+ default: -+ return -1; -+ } -+ return 0; -+} -+ -+void kvm_arch_remove_all_hw_breakpoints(void) -+{ -+ DPRINTF("%s\n", __func__); -+ nb_data_breakpoint = 0; -+ nb_inst_breakpoint = 0; -+} -+ -+static inline int cpu_loongarch_io_interrupts_pending(LOONGARCHCPU *cpu) -+{ -+ CPULOONGARCHState *env = &cpu->env; -+ -+ return env->CSR_ESTAT & (0x1 << 2); -+} -+ -+void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ int r; -+ struct kvm_loongarch_interrupt intr; -+ -+ qemu_mutex_lock_iothread(); -+ -+ if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && -+ cpu_loongarch_io_interrupts_pending(cpu)) { -+ intr.cpu = -1; -+ intr.irq = 2; -+ r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); -+ if (r < 0) { -+ error_report("%s: cpu %d: failed to inject IRQ %x", -+ __func__, cs->cpu_index, intr.irq); -+ } -+ } -+ -+ qemu_mutex_unlock_iothread(); -+} -+ -+MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) -+{ -+ return MEMTXATTRS_UNSPECIFIED; -+} -+ -+int kvm_arch_process_async_events(CPUState *cs) -+{ -+ return cs->halted; -+} -+ -+static CPUWatchpoint hw_watchpoint; -+ -+static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int i; -+ bool ret = false; -+ kvm_cpu_synchronize_state(cs); -+ if (cs->singlestep_enabled) { -+ return true; -+ } -+ if (kvm_find_sw_breakpoint(cs, env->active_tc.PC)) { -+ return true; -+ } -+ /* hw breakpoint */ -+ if (run->debug.arch.exception == EXCCODE_WATCH) { -+ for (i = 0; i < 8; i++) { -+ if (run->debug.arch.fwps & (1 << i)) { -+ ret = true; -+ break; -+ } -+ } -+ for (i = 0; i < 8; i++) { -+ if (run->debug.arch.mwps & (1 << i)) { -+ cs->watchpoint_hit = &hw_watchpoint; -+ hw_watchpoint.vaddr = data_breakpoint[i].addr; -+ switch (data_breakpoint[i].type) { -+ case GDB_WATCHPOINT_READ: -+ ret = true; -+ hw_watchpoint.flags = BP_MEM_READ; -+ break; -+ case GDB_WATCHPOINT_WRITE: -+ ret = true; -+ hw_watchpoint.flags = BP_MEM_WRITE; -+ break; -+ case GDB_WATCHPOINT_ACCESS: -+ ret = true; -+ hw_watchpoint.flags = BP_MEM_ACCESS; -+ break; -+ } -+ } -+ } -+ run->debug.arch.exception = 0; -+ run->debug.arch.fwps = 0; -+ run->debug.arch.mwps = 0; -+ } -+ return ret; -+} -+ -+int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) -+{ -+ int ret; -+ -+ DPRINTF("%s\n", __func__); -+ switch (run->exit_reason) { -+ case KVM_EXIT_HYPERCALL: -+ DPRINTF("handle LOONGARCH hypercall\n"); -+ ret = 0; -+ run->hypercall.ret = ret; -+ break; -+ -+ case KVM_EXIT_DEBUG: -+ ret = 0; -+ if (kvm_loongarch_handle_debug(cs, run)) { -+ ret = EXCP_DEBUG; -+ } -+ break; -+ default: -+ error_report("%s: unknown exit reason %d", -+ __func__, run->exit_reason); -+ ret = -1; -+ break; -+ } -+ -+ return ret; -+} -+ -+bool kvm_arch_stop_on_emulation_error(CPUState *cs) -+{ -+ DPRINTF("%s\n", __func__); -+ return true; -+} -+/* -+#if 0 -+int kvmloongarch_load_kernel(CPUState *env, void *ram_base) -+{ -+ int ret; -+ -+ ret = kvm_vcpu_ioctl(env, KVM_LOAD_KERNEL, ram_base); -+ -+ return ret; -+} -+#endif -+*/ -+void kvm_arch_init_irq_routing(KVMState *s) -+{ -+} -+ -+int kvm_loongarch_set_interrupt(LOONGARCHCPU *cpu, int irq, int level) -+{ -+ CPUState *cs = CPU(cpu); -+ struct kvm_loongarch_interrupt intr; -+ -+ if (!kvm_enabled()) { -+ return 0; -+ } -+ -+ intr.cpu = -1; -+ -+ if (level) { -+ intr.irq = irq; -+ } else { -+ intr.irq = -irq; -+ } -+ -+ kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); -+ -+ return 0; -+} -+ -+int kvm_loongarch_set_ipi_interrupt(LOONGARCHCPU *cpu, int irq, int level) -+{ -+ CPUState *cs = current_cpu; -+ CPUState *dest_cs = CPU(cpu); -+ struct kvm_loongarch_interrupt intr; -+ -+ if (!kvm_enabled()) { -+ return 0; -+ } -+ -+ intr.cpu = dest_cs->cpu_index; -+ -+ if (level) { -+ intr.irq = irq; -+ } else { -+ intr.irq = -irq; -+ } -+ -+ DPRINTF("%s: IRQ: %d\n", __func__, intr.irq); -+ if (!current_cpu) { -+ cs = dest_cs; -+ } -+ kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); -+ -+ return 0; -+} -+ -+static inline int kvm_loongarch_put_one_reg(CPUState *cs, uint64_t reg_id, -+ int32_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_put_one_ureg(CPUState *cs, uint64_t reg_id, -+ uint32_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_put_one_ulreg(CPUState *cs, uint64_t reg_id, -+ target_ulong *addr) -+{ -+ uint64_t val64 = *addr; -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)&val64 -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_put_one_reg64(CPUState *cs, int64_t reg_id, -+ int64_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_larch_putq(CPUState *cs, uint64_t reg_id, -+ uint64_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_get_one_reg(CPUState *cs, uint64_t reg_id, -+ int32_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_get_one_ureg(CPUState *cs, uint64_t reg_id, -+ uint32_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_get_one_ulreg(CPUState *cs, uint64_t reg_id, -+ target_ulong *addr) -+{ -+ int ret; -+ uint64_t val64 = 0; -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)&val64 -+ }; -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+ if (ret >= 0) { -+ *addr = val64; -+ } -+ return ret; -+} -+ -+static inline int kvm_loongarch_get_one_reg64(CPUState *cs, int64_t reg_id, -+ int64_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_larch_getq(CPUState *cs, uint64_t reg_id, -+ uint64_t *addr) -+{ -+ struct kvm_one_reg csrreg = { -+ .id = reg_id, -+ .addr = (uintptr_t)addr -+ }; -+ -+ return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &csrreg); -+} -+ -+static inline int kvm_loongarch_change_one_reg(CPUState *cs, uint64_t reg_id, -+ int32_t *addr, int32_t mask) -+{ -+ int err; -+ int32_t tmp, change; -+ -+ err = kvm_loongarch_get_one_reg(cs, reg_id, &tmp); -+ if (err < 0) { -+ return err; -+ } -+ -+ /* only change bits in mask */ -+ change = (*addr ^ tmp) & mask; -+ if (!change) { -+ return 0; -+ } -+ -+ tmp = tmp ^ change; -+ return kvm_loongarch_put_one_reg(cs, reg_id, &tmp); -+} -+ -+static inline int kvm_loongarch_change_one_reg64(CPUState *cs, uint64_t reg_id, -+ int64_t *addr, int64_t mask) -+{ -+ int err; -+ int64_t tmp, change; -+ -+ err = kvm_loongarch_get_one_reg64(cs, reg_id, &tmp); -+ if (err < 0) { -+ DPRINTF("%s: Failed to get CSR_CONFIG7 (%d)\n", __func__, err); -+ return err; -+ } -+ -+ /* only change bits in mask */ -+ change = (*addr ^ tmp) & mask; -+ if (!change) { -+ return 0; -+ } -+ -+ tmp = tmp ^ change; -+ return kvm_loongarch_put_one_reg64(cs, reg_id, &tmp); -+} -+/* -+ * Handle the VM clock being started or stopped -+ */ -+static void kvm_loongarch_update_state(void *opaque, bool running, RunState state) -+{ -+ CPUState *cs = opaque; -+ int ret; -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ -+ /* -+ * If state is already dirty (synced to QEMU) then the KVM timer state is -+ * already saved and can be restored when it is synced back to KVM. -+ */ -+ if (!running) { -+ ret = kvm_larch_getq(cs, -+ KVM_REG_LOONGARCH_COUNTER, &cpu->counter_value); -+ if (ret < 0) { -+ printf("%s: Failed to get counter_value (%d)\n", __func__, ret); -+ } -+ -+ } else { -+ ret = kvm_larch_putq(cs, KVM_REG_LOONGARCH_COUNTER, -+ &(LOONGARCH_CPU(cs))->counter_value); -+ if (ret < 0) { -+ printf("%s: Failed to put counter_value (%d)\n", __func__, ret); -+ } -+ } -+} -+ -+static int kvm_loongarch_put_fpu_registers(CPUState *cs, int level) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int err, ret = 0; -+ unsigned int i; -+ struct kvm_fpu fpu; -+ -+ fpu.fcsr = env->active_fpu.fcsr0; -+ for (i = 0; i < 32; i++) { -+ memcpy(&fpu.fpr[i], &env->active_fpu.fpr[i], sizeof(struct kvm_fpureg)); -+ } -+ for (i = 0; i < 8; i++) { -+ ((char *)&fpu.fcc)[i] = env->active_fpu.cf[i]; -+ } -+ fpu.vcsr = env->active_fpu.vcsr16; -+ -+ err = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu); -+ if (err < 0) { -+ DPRINTF("%s: Failed to get FPU (%d)\n", __func__, err); -+ ret = err; -+ } -+ -+ return ret; -+} -+ -+static int kvm_loongarch_get_fpu_registers(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int err, ret = 0; -+ unsigned int i; -+ struct kvm_fpu fpu; -+ -+ err = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu); -+ if (err < 0) { -+ DPRINTF("%s: Failed to get FPU (%d)\n", __func__, err); -+ ret = err; -+ } else { -+ env->active_fpu.fcsr0 = fpu.fcsr; -+ for (i = 0; i < 32; i++) { -+ memcpy(&env->active_fpu.fpr[i], &fpu.fpr[i], sizeof(struct kvm_fpureg)); -+ } -+ for (i = 0; i < 8; i++) { -+ env->active_fpu.cf[i] = ((char *)&fpu.fcc)[i]; -+ } -+ env->active_fpu.vcsr16 = fpu.vcsr; -+ } -+ -+ return ret; -+} -+ -+#define KVM_PUT_ONE_UREG64(cs, regidx, addr) \ -+ ({ \ -+ int err; \ -+ uint64_t csrid = 0; \ -+ csrid = (KVM_IOC_CSRID(regidx)); \ -+ err = kvm_larch_putq(cs, csrid, addr); \ -+ if (err < 0) { \ -+ DPRINTF("%s: Failed to put regidx 0x%x err:%d\n", __func__, regidx, err); \ -+ } \ -+ err; \ -+ }) -+ -+ -+static int kvm_loongarch_put_csr_registers(CPUState *cs, int level) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int ret = 0; -+ -+ (void)level; -+ -+ kvm_msr_buf_reset(cpu); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CRMD, env->CSR_CRMD); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRMD, env->CSR_PRMD); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_EUEN, env->CSR_EUEN); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MISC, env->CSR_MISC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ECFG, env->CSR_ECFG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ESTAT, env->CSR_ESTAT); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERA, env->CSR_ERA); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADV, env->CSR_BADV); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADI, env->CSR_BADI); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_EEPN, env->CSR_EEPN); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, env->CSR_TLBIDX); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, env->CSR_TLBEHI); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, env->CSR_TLBELO0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, env->CSR_TLBELO1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GTLBC, env->CSR_GTLBC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TRGP, env->CSR_TRGP); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ASID, env->CSR_ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDL, env->CSR_PGDL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDH, env->CSR_PGDH); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGD, env->CSR_PGD); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, env->CSR_PWCTL0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, env->CSR_PWCTL1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, env->CSR_STLBPGSIZE); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_RVACFG, env->CSR_RVACFG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CPUID, env->CSR_CPUID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, env->CSR_PRCFG1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, env->CSR_PRCFG2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, env->CSR_PRCFG3); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS0, env->CSR_KS0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS1, env->CSR_KS1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS2, env->CSR_KS2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS3, env->CSR_KS3); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS4, env->CSR_KS4); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS5, env->CSR_KS5); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS6, env->CSR_KS6); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS7, env->CSR_KS7); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TMID, env->CSR_TMID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CNTC, env->CSR_CNTC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, env->CSR_TINTCLR); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GSTAT, env->CSR_GSTAT); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCFG, env->CSR_GCFG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GINTC, env->CSR_GINTC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCNTC, env->CSR_GCNTC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, env->CSR_LLBCTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, env->CSR_IMPCTL1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, env->CSR_IMPCTL2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GNMI, env->CSR_GNMI); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, env->CSR_TLBRENT); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, env->CSR_TLBRBADV); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, env->CSR_TLBRERA); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, env->CSR_TLBRSAVE); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, env->CSR_TLBRELO0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, env->CSR_TLBRELO1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, env->CSR_TLBREHI); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, env->CSR_TLBRPRMD); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, env->CSR_ERRCTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, env->CSR_ERRINFO); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, env->CSR_ERRINFO1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRENT, env->CSR_ERRENT); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRERA, env->CSR_ERRERA); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, env->CSR_ERRSAVE); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CTAG, env->CSR_CTAG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, env->CSR_DMWIN0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, env->CSR_DMWIN1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, env->CSR_DMWIN2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, env->CSR_DMWIN3); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, env->CSR_PERFCTRL0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, env->CSR_PERFCNTR0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, env->CSR_PERFCTRL1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, env->CSR_PERFCNTR1); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, env->CSR_PERFCTRL2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, env->CSR_PERFCNTR2); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, env->CSR_PERFCTRL3); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, env->CSR_PERFCNTR3); -+ -+ /* debug */ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPC, env->CSR_MWPC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPS, env->CSR_MWPS); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, env->CSR_DB0ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, env->CSR_DB0MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, env->CSR_DB0CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, env->CSR_DB0ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, env->CSR_DB1ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, env->CSR_DB1MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, env->CSR_DB1CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, env->CSR_DB1ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, env->CSR_DB2ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, env->CSR_DB2MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, env->CSR_DB2CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, env->CSR_DB2ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, env->CSR_DB3ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, env->CSR_DB3MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, env->CSR_DB3CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, env->CSR_DB3ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPC, env->CSR_FWPC); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPS, env->CSR_FWPS); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, env->CSR_IB0ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, env->CSR_IB0MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, env->CSR_IB0CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, env->CSR_IB0ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, env->CSR_IB1ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, env->CSR_IB1MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, env->CSR_IB1CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, env->CSR_IB1ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, env->CSR_IB2ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, env->CSR_IB2MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, env->CSR_IB2CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, env->CSR_IB2ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, env->CSR_IB3ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, env->CSR_IB3MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, env->CSR_IB3CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, env->CSR_IB3ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, env->CSR_IB4ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, env->CSR_IB4MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, env->CSR_IB4CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, env->CSR_IB4ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, env->CSR_IB5ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, env->CSR_IB5MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, env->CSR_IB5CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, env->CSR_IB5ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, env->CSR_IB6ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, env->CSR_IB6MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, env->CSR_IB6CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, env->CSR_IB6ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, env->CSR_IB7ADDR); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, env->CSR_IB7MASK); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, env->CSR_IB7CTL); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, env->CSR_IB7ASID); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DEBUG, env->CSR_DEBUG); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DERA, env->CSR_DERA); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DESAVE, env->CSR_DESAVE); -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_SET_MSRS, cpu->kvm_msr_buf); -+ if (ret < cpu->kvm_msr_buf->ncsrs) { -+ struct kvm_csr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -+ printf("error: failed to set CSR 0x%" PRIx32 " to 0x%" PRIx64"\n", -+ (uint32_t)e->index, (uint64_t)e->data); -+ } -+ -+ /* -+ * timer cfg must be put at last since it is used to enable -+ * guest timer -+ */ -+ ret |= KVM_PUT_ONE_UREG64(cs, LOONGARCH_CSR_TVAL, &env->CSR_TVAL); -+ ret |= KVM_PUT_ONE_UREG64(cs, LOONGARCH_CSR_TCFG, &env->CSR_TCFG); -+ return ret; -+} -+ -+#define KVM_GET_ONE_UREG64(cs, regidx, addr) \ -+ ({ \ -+ int err; \ -+ uint64_t csrid = 0; \ -+ csrid = (KVM_IOC_CSRID(regidx)); \ -+ err = kvm_larch_getq(cs, csrid, addr); \ -+ if (err < 0) { \ -+ DPRINTF("%s: Failed to put regidx 0x%x err:%d\n", __func__, regidx, err); \ -+ } \ -+ err; \ -+ }) -+ -+static int kvm_loongarch_get_csr_registers(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int ret = 0, i; -+ struct kvm_csr_entry *csrs = cpu->kvm_msr_buf->entries; -+ -+ kvm_msr_buf_reset(cpu); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CRMD, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRMD, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_EUEN, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MISC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ECFG, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ESTAT, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERA, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADV, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADI, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_EEPN, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GTLBC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TRGP, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDH, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGD, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_RVACFG, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CPUID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS3, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS4, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS5, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS6, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS7, 0); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TMID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CNTC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GSTAT, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCFG, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GINTC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCNTC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_GNMI, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRENT, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRERA, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_CTAG, 0); -+ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, 0); -+ -+ /* debug */ -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPS, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPC, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPS, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DEBUG, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DERA, 0); -+ kvm_msr_entry_add(cpu, LOONGARCH_CSR_DESAVE, 0); -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, cpu->kvm_msr_buf); -+ if (ret < cpu->kvm_msr_buf->ncsrs) { -+ struct kvm_csr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -+ printf("error: failed to get CSR 0x%" PRIx32"\n", -+ (uint32_t)e->index); -+ } -+ -+ for (i = 0; i < ret; i++) { -+ uint32_t index = csrs[i].index; -+ -+ switch (index) { -+ case LOONGARCH_CSR_CRMD: -+ env->CSR_CRMD = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PRMD: -+ env->CSR_PRMD = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_EUEN: -+ env->CSR_EUEN = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_MISC: -+ env->CSR_MISC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ECFG: -+ env->CSR_ECFG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ESTAT: -+ env->CSR_ESTAT = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERA: -+ env->CSR_ERA = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_BADV: -+ env->CSR_BADV = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_BADI: -+ env->CSR_BADI = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_EEPN: -+ env->CSR_EEPN = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBIDX: -+ env->CSR_TLBIDX = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBEHI: -+ env->CSR_TLBEHI = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBELO0: -+ env->CSR_TLBELO0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBELO1: -+ env->CSR_TLBELO1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GTLBC: -+ env->CSR_GTLBC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TRGP: -+ env->CSR_TRGP = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ASID: -+ env->CSR_ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PGDL: -+ env->CSR_PGDL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PGDH: -+ env->CSR_PGDH = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PGD: -+ env->CSR_PGD = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PWCTL0: -+ env->CSR_PWCTL0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PWCTL1: -+ env->CSR_PWCTL1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_STLBPGSIZE: -+ env->CSR_STLBPGSIZE = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_RVACFG: -+ env->CSR_RVACFG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_CPUID: -+ env->CSR_CPUID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PRCFG1: -+ env->CSR_PRCFG1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PRCFG2: -+ env->CSR_PRCFG2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PRCFG3: -+ env->CSR_PRCFG3 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS0: -+ env->CSR_KS0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS1: -+ env->CSR_KS1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS2: -+ env->CSR_KS2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS3: -+ env->CSR_KS3 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS4: -+ env->CSR_KS4 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS5: -+ env->CSR_KS5 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS6: -+ env->CSR_KS6 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_KS7: -+ env->CSR_KS7 = csrs[i].data; -+ break; -+ -+ case LOONGARCH_CSR_TMID: -+ env->CSR_TMID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_CNTC: -+ env->CSR_CNTC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TINTCLR: -+ env->CSR_TINTCLR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GSTAT: -+ env->CSR_GSTAT = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GCFG: -+ env->CSR_GCFG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GINTC: -+ env->CSR_GINTC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GCNTC: -+ env->CSR_GCNTC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_LLBCTL: -+ env->CSR_LLBCTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IMPCTL1: -+ env->CSR_IMPCTL1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IMPCTL2: -+ env->CSR_IMPCTL2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_GNMI: -+ env->CSR_GNMI = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRENT: -+ env->CSR_TLBRENT = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRBADV: -+ env->CSR_TLBRBADV = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRERA: -+ env->CSR_TLBRERA = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRSAVE: -+ env->CSR_TLBRSAVE = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRELO0: -+ env->CSR_TLBRELO0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRELO1: -+ env->CSR_TLBRELO1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBREHI: -+ env->CSR_TLBREHI = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_TLBRPRMD: -+ env->CSR_TLBRPRMD = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRCTL: -+ env->CSR_ERRCTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRINFO: -+ env->CSR_ERRINFO = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRINFO1: -+ env->CSR_ERRINFO1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRENT: -+ env->CSR_ERRENT = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRERA: -+ env->CSR_ERRERA = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_ERRSAVE: -+ env->CSR_ERRSAVE = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_CTAG: -+ env->CSR_CTAG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DMWIN0: -+ env->CSR_DMWIN0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DMWIN1: -+ env->CSR_DMWIN1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DMWIN2: -+ env->CSR_DMWIN2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DMWIN3: -+ env->CSR_DMWIN3 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCTRL0: -+ env->CSR_PERFCTRL0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCNTR0: -+ env->CSR_PERFCNTR0 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCTRL1: -+ env->CSR_PERFCTRL1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCNTR1: -+ env->CSR_PERFCNTR1 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCTRL2: -+ env->CSR_PERFCTRL2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCNTR2: -+ env->CSR_PERFCNTR2 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCTRL3: -+ env->CSR_PERFCTRL3 = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_PERFCNTR3: -+ env->CSR_PERFCNTR3 = csrs[i].data; -+ break; -+ -+ case LOONGARCH_CSR_MWPC: -+ env->CSR_MWPC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_MWPS: -+ env->CSR_MWPS = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB0ADDR: -+ env->CSR_DB0ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB0MASK: -+ env->CSR_DB0MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB0CTL: -+ env->CSR_DB0CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB0ASID: -+ env->CSR_DB0ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB1ADDR: -+ env->CSR_DB1ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB1MASK: -+ env->CSR_DB1MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB1CTL: -+ env->CSR_DB1CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB1ASID: -+ env->CSR_DB1ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB2ADDR: -+ env->CSR_DB2ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB2MASK: -+ env->CSR_DB2MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB2CTL: -+ env->CSR_DB2CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB2ASID: -+ env->CSR_DB2ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB3ADDR: -+ env->CSR_DB3ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB3MASK: -+ env->CSR_DB3MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB3CTL: -+ env->CSR_DB3CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DB3ASID: -+ env->CSR_DB3ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_FWPC: -+ env->CSR_FWPC = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_FWPS: -+ env->CSR_FWPS = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB0ADDR: -+ env->CSR_IB0ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB0MASK: -+ env->CSR_IB0MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB0CTL: -+ env->CSR_IB0CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB0ASID: -+ env->CSR_IB0ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB1ADDR: -+ env->CSR_IB1ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB1MASK: -+ env->CSR_IB1MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB1CTL: -+ env->CSR_IB1CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB1ASID: -+ env->CSR_IB1ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB2ADDR: -+ env->CSR_IB2ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB2MASK: -+ env->CSR_IB2MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB2CTL: -+ env->CSR_IB2CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB2ASID: -+ env->CSR_IB2ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB3ADDR: -+ env->CSR_IB3ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB3MASK: -+ env->CSR_IB3MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB3CTL: -+ env->CSR_IB3CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB3ASID: -+ env->CSR_IB3ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB4ADDR: -+ env->CSR_IB4ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB4MASK: -+ env->CSR_IB4MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB4CTL: -+ env->CSR_IB4CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB4ASID: -+ env->CSR_IB4ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB5ADDR: -+ env->CSR_IB5ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB5MASK: -+ env->CSR_IB5MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB5CTL: -+ env->CSR_IB5CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB5ASID: -+ env->CSR_IB5ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB6ADDR: -+ env->CSR_IB6ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB6MASK: -+ env->CSR_IB6MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB6CTL: -+ env->CSR_IB6CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB6ASID: -+ env->CSR_IB6ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB7ADDR: -+ env->CSR_IB7ADDR = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB7MASK: -+ env->CSR_IB7MASK = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB7CTL: -+ env->CSR_IB7CTL = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_IB7ASID: -+ env->CSR_IB7ASID = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DEBUG: -+ env->CSR_DEBUG = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DERA: -+ env->CSR_DERA = csrs[i].data; -+ break; -+ case LOONGARCH_CSR_DESAVE: -+ env->CSR_DESAVE = csrs[i].data; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ ret |= KVM_GET_ONE_UREG64(cs, LOONGARCH_CSR_TVAL, &env->CSR_TVAL); -+ ret |= KVM_GET_ONE_UREG64(cs, LOONGARCH_CSR_TCFG, &env->CSR_TCFG); -+ return ret; -+} -+ -+int kvm_loongarch_put_pvtime(LOONGARCHCPU *cpu) -+{ -+ CPULOONGARCHState *env = &cpu->env; -+ int err; -+ struct kvm_device_attr attr = { -+ .group = KVM_LARCH_VCPU_PVTIME_CTRL, -+ .attr = KVM_LARCH_VCPU_PVTIME_IPA, -+ .addr = (uint64_t)&env->st.guest_addr, -+ }; -+ -+ err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr); -+ if (err != 0) { -+ /* It's ok even though kvm has not such attr */ -+ return 0; -+ } -+ -+ err = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_DEVICE_ATTR, attr); -+ if (err != 0) { -+ error_report("PVTIME IPA: KVM_SET_DEVICE_ATTR: %s", strerror(-err)); -+ return err; -+ } -+ -+ return 0; -+} -+ -+int kvm_loongarch_get_pvtime(LOONGARCHCPU *cpu) -+{ -+ CPULOONGARCHState *env = &cpu->env; -+ int err; -+ struct kvm_device_attr attr = { -+ .group = KVM_LARCH_VCPU_PVTIME_CTRL, -+ .attr = KVM_LARCH_VCPU_PVTIME_IPA, -+ .addr = (uint64_t)&env->st.guest_addr, -+ }; -+ -+ err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr); -+ if (err != 0) { -+ /* It's ok even though kvm has not such attr */ -+ return 0; -+ } -+ -+ err = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_DEVICE_ATTR, attr); -+ if (err != 0) { -+ error_report("PVTIME IPA: KVM_GET_DEVICE_ATTR: %s", strerror(-err)); -+ return err; -+ } -+ -+ return 0; -+} -+ -+int kvm_arch_put_registers(CPUState *cs, int level) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ struct kvm_regs regs; -+ int ret; -+ int i; -+ -+ /* Set the registers based on QEMU's view of things */ -+ for (i = 0; i < 32; i++) { -+ regs.gpr[i] = (int64_t)(target_long)env->active_tc.gpr[i]; -+ } -+ -+ regs.pc = (int64_t)(target_long)env->active_tc.PC; -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); -+ -+ if (ret < 0) { -+ return ret; -+ } -+ -+ ret = kvm_loongarch_put_csr_registers(cs, level); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ ret = kvm_loongarch_put_fpu_registers(cs, level); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ return ret; -+} -+ -+int kvm_arch_get_registers(CPUState *cs) -+{ -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ int ret = 0; -+ struct kvm_regs regs; -+ int i; -+ -+ /* Get the current register set as KVM seems it */ -+ ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); -+ -+ if (ret < 0) { -+ return ret; -+ } -+ -+ for (i = 0; i < 32; i++) { -+ env->active_tc.gpr[i] = regs.gpr[i]; -+ } -+ -+ env->active_tc.PC = regs.pc; -+ -+ kvm_loongarch_get_csr_registers(cs); -+ kvm_loongarch_get_fpu_registers(cs); -+ -+ return ret; -+} -+ -+int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, -+ uint64_t address, uint32_t data, PCIDevice *dev) -+{ -+ return 0; -+} -+ -+int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, -+ int vector, PCIDevice *dev) -+{ -+ return 0; -+} -+ -+bool kvm_arch_cpu_check_are_resettable(void) -+{ -+ return true; -+} -+ -+int kvm_arch_release_virq_post(int virq) -+{ -+ return 0; -+} -+ -+int kvm_arch_msi_data_to_gsi(uint32_t data) -+{ -+ abort(); -+} -diff --git a/target/loongarch64/kvm_larch.h b/target/loongarch64/kvm_larch.h -new file mode 100644 -index 000000000..a56026d10 ---- /dev/null -+++ b/target/loongarch64/kvm_larch.h -@@ -0,0 +1,41 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * KVM/LOONGARCH: LOONGARCH specific KVM APIs -+ * -+ * Copyright (C) 2012-2014 Imagination Technologies Ltd. -+ * Authors: Sanjay Lal -+*/ -+ -+#ifndef KVM_LOONGARCH_H -+#define KVM_LOONGARCH_H -+ -+/** -+ * kvm_loongarch_reset_vcpu: -+ * @cpu: LOONGARCHCPU -+ * -+ * Called at reset time to set kernel registers to their initial values. -+ */ -+void kvm_loongarch_reset_vcpu(LOONGARCHCPU *cpu); -+ -+int kvm_loongarch_set_interrupt(LOONGARCHCPU *cpu, int irq, int level); -+int kvm_loongarch_set_ipi_interrupt(LOONGARCHCPU *cpu, int irq, int level); -+ -+int kvm_loongarch_put_pvtime(LOONGARCHCPU *cpu); -+int kvm_loongarch_get_pvtime(LOONGARCHCPU *cpu); -+ -+#ifndef KVM_INTERRUPT_SET -+#define KVM_INTERRUPT_SET -1 -+#endif -+ -+#ifndef KVM_INTERRUPT_UNSET -+#define KVM_INTERRUPT_UNSET -2 -+#endif -+ -+#ifndef KVM_INTERRUPT_SET_LEVEL -+#define KVM_INTERRUPT_SET_LEVEL -3 -+#endif -+ -+#endif /* KVM_LOONGARCH_H */ -diff --git a/target/loongarch64/larch-defs.h b/target/loongarch64/larch-defs.h -new file mode 100644 -index 000000000..d3a61cf25 ---- /dev/null -+++ b/target/loongarch64/larch-defs.h -@@ -0,0 +1,27 @@ -+#ifndef QEMU_LOONGARCH_DEFS_H -+#define QEMU_LOONGARCH_DEFS_H -+ -+/* If we want to use host float regs... */ -+/* #define USE_HOST_FLOAT_REGS */ -+ -+/* Real pages are variable size... */ -+#define TARGET_PAGE_BITS 14 -+ -+#define LOONGARCH_TLB_MAX 2112 -+ -+#define TARGET_LONG_BITS 64 -+#define TARGET_PHYS_ADDR_SPACE_BITS 48 -+#define TARGET_VIRT_ADDR_SPACE_BITS 48 -+ -+/* -+ * bit definitions for insn_flags (ISAs/ASEs flags) -+ * ------------------------------------------------ -+ */ -+#define ISA_LARCH32 0x00000001ULL -+#define ISA_LARCH64 0x00000002ULL -+#define INSN_LOONGARCH 0x00010000ULL -+ -+#define CPU_LARCH32 (ISA_LARCH32) -+#define CPU_LARCH64 (ISA_LARCH32 | ISA_LARCH64) -+ -+#endif /* QEMU_LOONGARCH_DEFS_H */ -diff --git a/target/loongarch64/machine.c b/target/loongarch64/machine.c -new file mode 100644 -index 000000000..b69bca6a9 ---- /dev/null -+++ b/target/loongarch64/machine.c -@@ -0,0 +1,416 @@ -+#include "qemu/osdep.h" -+#include "qemu-common.h" -+#include "cpu.h" -+#include "internal.h" -+#include "hw/hw.h" -+#include "kvm_larch.h" -+#include "migration/cpu.h" -+#include "linux/kvm.h" -+#include "sysemu/kvm.h" -+#include "qemu/error-report.h" -+ -+static int cpu_post_load(void *opaque, int version_id) -+{ -+ LOONGARCHCPU *cpu = opaque; -+ CPULOONGARCHState *env = &cpu->env; -+ int r = 0; -+ -+#ifdef CONFIG_KVM -+ struct kvm_loongarch_vcpu_state vcpu_state; -+ int i; -+ -+ vcpu_state.online_vcpus = cpu->online_vcpus; -+ vcpu_state.is_migrate = cpu->is_migrate; -+ vcpu_state.cpu_freq = cpu->cpu_freq; -+ vcpu_state.count_ctl = cpu->count_ctl; -+ vcpu_state.pending_exceptions = cpu->pending_exceptions; -+ vcpu_state.pending_exceptions_clr = cpu->pending_exceptions_clr; -+ for (i = 0; i < 4; i++) { -+ vcpu_state.core_ext_ioisr[i] = cpu->core_ext_ioisr[i]; -+ } -+ r = kvm_vcpu_ioctl(CPU(cpu), KVM_LARCH_SET_VCPU_STATE, &vcpu_state); -+ if (r) { -+ error_report("set vcpu state failed %d", r); -+ } -+ -+ kvm_loongarch_put_pvtime(cpu); -+#endif -+ -+ restore_fp_status(env); -+ compute_hflags(env); -+ -+ return r; -+} -+ -+static int cpu_pre_save(void *opaque) -+{ -+#ifdef CONFIG_KVM -+ LOONGARCHCPU *cpu = opaque; -+ struct kvm_loongarch_vcpu_state vcpu_state; -+ int i, r = 0; -+ -+ r = kvm_vcpu_ioctl(CPU(cpu), KVM_LARCH_GET_VCPU_STATE, &vcpu_state); -+ if (r < 0) { -+ error_report("get vcpu state failed %d", r); -+ return r; -+ } -+ -+ cpu->online_vcpus = vcpu_state.online_vcpus; -+ cpu->is_migrate = vcpu_state.is_migrate; -+ cpu->cpu_freq = vcpu_state.cpu_freq; -+ cpu->count_ctl = vcpu_state.count_ctl; -+ cpu->pending_exceptions = vcpu_state.pending_exceptions; -+ cpu->pending_exceptions_clr = vcpu_state.pending_exceptions_clr; -+ for (i = 0; i < 4; i++) { -+ cpu->core_ext_ioisr[i] = vcpu_state.core_ext_ioisr[i]; -+ } -+ -+ kvm_loongarch_get_pvtime(cpu); -+#endif -+ return 0; -+} -+ -+/* FPU state */ -+ -+static int get_fpr(QEMUFile *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ fpr_t *v = pv; -+ qemu_get_be64s(f, &v->d); -+ return 0; -+} -+ -+static int put_fpr(QEMUFile *f, void *pv, size_t size, -+ const VMStateField *field, JSONWriter *vmdesc) -+{ -+ fpr_t *v = pv; -+ qemu_put_be64s(f, &v->d); -+ return 0; -+} -+ -+const VMStateInfo vmstate_info_fpr = { -+ .name = "fpr", -+ .get = get_fpr, -+ .put = put_fpr, -+}; -+ -+#define VMSTATE_FPR_ARRAY_V(_f, _s, _n, _v) \ -+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_fpr, fpr_t) -+ -+#define VMSTATE_FPR_ARRAY(_f, _s, _n) \ -+ VMSTATE_FPR_ARRAY_V(_f, _s, _n, 0) -+ -+static VMStateField vmstate_fpu_fields[] = { -+ VMSTATE_FPR_ARRAY(fpr, CPULOONGARCHFPUContext, 32), -+ VMSTATE_UINT32(fcsr0, CPULOONGARCHFPUContext), -+ VMSTATE_END_OF_LIST() -+}; -+ -+const VMStateDescription vmstate_fpu = { -+ .name = "cpu/fpu", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = vmstate_fpu_fields -+}; -+ -+const VMStateDescription vmstate_inactive_fpu = { -+ .name = "cpu/inactive_fpu", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = vmstate_fpu_fields -+}; -+ -+/* TC state */ -+ -+static VMStateField vmstate_tc_fields[] = { -+ VMSTATE_UINTTL_ARRAY(gpr, TCState, 32), -+ VMSTATE_UINTTL(PC, TCState), -+ VMSTATE_END_OF_LIST() -+}; -+ -+const VMStateDescription vmstate_tc = { -+ .name = "cpu/tc", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = vmstate_tc_fields -+}; -+ -+const VMStateDescription vmstate_inactive_tc = { -+ .name = "cpu/inactive_tc", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = vmstate_tc_fields -+}; -+ -+/* TLB state */ -+ -+static int get_tlb(QEMUFile *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ ls3a5k_tlb_t *v = pv; -+ uint32_t flags; -+ -+ qemu_get_betls(f, &v->VPN); -+ qemu_get_be64s(f, &v->PageMask); -+ qemu_get_be32s(f, &v->PageSize); -+ qemu_get_be16s(f, &v->ASID); -+ qemu_get_be32s(f, &flags); -+ v->RPLV1 = (flags >> 21) & 1; -+ v->RPLV0 = (flags >> 20) & 1; -+ v->PLV1 = (flags >> 18) & 3; -+ v->PLV0 = (flags >> 16) & 3; -+ v->EHINV = (flags >> 15) & 1; -+ v->RI1 = (flags >> 14) & 1; -+ v->RI0 = (flags >> 13) & 1; -+ v->XI1 = (flags >> 12) & 1; -+ v->XI0 = (flags >> 11) & 1; -+ v->WE1 = (flags >> 10) & 1; -+ v->WE0 = (flags >> 9) & 1; -+ v->V1 = (flags >> 8) & 1; -+ v->V0 = (flags >> 7) & 1; -+ v->C1 = (flags >> 4) & 7; -+ v->C0 = (flags >> 1) & 7; -+ v->G = (flags >> 0) & 1; -+ qemu_get_be64s(f, &v->PPN0); -+ qemu_get_be64s(f, &v->PPN1); -+ -+ return 0; -+} -+ -+static int put_tlb(QEMUFile *f, void *pv, size_t size, -+ const VMStateField *field, JSONWriter *vmdesc) -+{ -+ ls3a5k_tlb_t *v = pv; -+ -+ uint16_t asid = v->ASID; -+ uint32_t flags = ((v->RPLV1 << 21) | -+ (v->RPLV0 << 20) | -+ (v->PLV1 << 18) | -+ (v->PLV0 << 16) | -+ (v->EHINV << 15) | -+ (v->RI1 << 14) | -+ (v->RI0 << 13) | -+ (v->XI1 << 12) | -+ (v->XI0 << 11) | -+ (v->WE1 << 10) | -+ (v->WE0 << 9) | -+ (v->V1 << 8) | -+ (v->V0 << 7) | -+ (v->C1 << 4) | -+ (v->C0 << 1) | -+ (v->G << 0)); -+ -+ qemu_put_betls(f, &v->VPN); -+ qemu_put_be64s(f, &v->PageMask); -+ qemu_put_be32s(f, &v->PageSize); -+ qemu_put_be16s(f, &asid); -+ qemu_put_be32s(f, &flags); -+ qemu_put_be64s(f, &v->PPN0); -+ qemu_put_be64s(f, &v->PPN1); -+ -+ return 0; -+} -+ -+const VMStateInfo vmstate_info_tlb = { -+ .name = "tlb_entry", -+ .get = get_tlb, -+ .put = put_tlb, -+}; -+ -+#define VMSTATE_TLB_ARRAY_V(_f, _s, _n, _v) \ -+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_tlb, ls3a5k_tlb_t) -+ -+#define VMSTATE_TLB_ARRAY(_f, _s, _n) \ -+ VMSTATE_TLB_ARRAY_V(_f, _s, _n, 0) -+ -+const VMStateDescription vmstate_tlb = { -+ .name = "cpu/tlb", -+ .version_id = 2, -+ .minimum_version_id = 2, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT32(nb_tlb, CPULOONGARCHTLBContext), -+ VMSTATE_UINT32(tlb_in_use, CPULOONGARCHTLBContext), -+ VMSTATE_TLB_ARRAY(mmu.ls3a5k.tlb, CPULOONGARCHTLBContext, LOONGARCH_TLB_MAX), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+/* LOONGARCH CPU state */ -+ -+const VMStateDescription vmstate_loongarch_cpu = { -+ .name = "cpu", -+ .version_id = 15, -+ .minimum_version_id = 15, -+ .post_load = cpu_post_load, -+ .pre_save = cpu_pre_save, -+ .fields = (VMStateField[]) { -+ /* Active TC */ -+ VMSTATE_STRUCT(env.active_tc, LOONGARCHCPU, 1, vmstate_tc, TCState), -+ -+ /* Active FPU */ -+ VMSTATE_STRUCT(env.active_fpu, LOONGARCHCPU, 1, vmstate_fpu, -+ CPULOONGARCHFPUContext), -+ -+ /* TLB */ -+ VMSTATE_STRUCT_POINTER(env.tlb, LOONGARCHCPU, vmstate_tlb, -+ CPULOONGARCHTLBContext), -+ /* CPU metastate */ -+ VMSTATE_UINT32(env.current_tc, LOONGARCHCPU), -+ VMSTATE_INT32(env.error_code, LOONGARCHCPU), -+ VMSTATE_UINTTL(env.btarget, LOONGARCHCPU), -+ VMSTATE_UINTTL(env.bcond, LOONGARCHCPU), -+ -+ VMSTATE_UINT64(env.lladdr, LOONGARCHCPU), -+ -+ /* PV time */ -+ VMSTATE_UINT64(env.st.guest_addr, LOONGARCHCPU), -+ -+ /* Remaining CSR registers */ -+ VMSTATE_UINT64(env.CSR_CRMD, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PRMD, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_EUEN, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_MISC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ECFG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ESTAT, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERA, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_BADV, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_BADI, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_EEPN, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBIDX, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBEHI, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBELO0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBELO1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBWIRED, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GTLBC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TRGP, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PGDL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PGDH, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PGD, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PWCTL0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PWCTL1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_STLBPGSIZE, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_RVACFG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_CPUID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PRCFG1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PRCFG2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PRCFG3, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS3, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS4, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS5, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS6, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_KS7, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TMID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TCFG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TVAL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_CNTC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TINTCLR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GSTAT, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GCFG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GINTC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GCNTC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_LLBCTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IMPCTL1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IMPCTL2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_GNMI, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRENT, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRBADV, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRERA, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRSAVE, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRELO0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRELO1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBREHI, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_TLBRPRMD, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRCTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRINFO, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRINFO1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRENT, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRERA, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_ERRSAVE, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_CTAG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DMWIN0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DMWIN1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DMWIN2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DMWIN3, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCTRL0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCNTR0, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCTRL1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCNTR1, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCTRL2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCNTR2, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCTRL3, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_PERFCNTR3, LOONGARCHCPU), -+ /* debug */ -+ VMSTATE_UINT64(env.CSR_MWPC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_MWPS, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB0ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB0MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB0CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB0ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB1ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB1MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB1CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB1ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB2ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB2MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB2CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB2ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB3ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB3MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB3CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DB3ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_FWPC, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_FWPS, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB0ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB0MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB0CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB0ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB1ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB1MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB1CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB1ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB2ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB2MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB2CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB2ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB3ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB3MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB3CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB3ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB4ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB4MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB4CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB4ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB5ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB5MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB5CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB5ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB6ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB6MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB6CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB6ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB7ADDR, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB7MASK, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB7CTL, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_IB7ASID, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DEBUG, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DERA, LOONGARCHCPU), -+ VMSTATE_UINT64(env.CSR_DESAVE, LOONGARCHCPU), -+ -+ VMSTATE_STRUCT_ARRAY(env.fpus, LOONGARCHCPU, LOONGARCH_FPU_MAX, 1, -+ vmstate_inactive_fpu, CPULOONGARCHFPUContext), -+ VMSTATE_UINT8(online_vcpus, LOONGARCHCPU), -+ VMSTATE_UINT8(is_migrate, LOONGARCHCPU), -+ VMSTATE_UINT64(counter_value, LOONGARCHCPU), -+ VMSTATE_UINT32(cpu_freq, LOONGARCHCPU), -+ VMSTATE_UINT32(count_ctl, LOONGARCHCPU), -+ VMSTATE_UINT64(pending_exceptions, LOONGARCHCPU), -+ VMSTATE_UINT64(pending_exceptions_clr, LOONGARCHCPU), -+ VMSTATE_UINT64_ARRAY(core_ext_ioisr, LOONGARCHCPU, 4), -+ -+ VMSTATE_END_OF_LIST() -+ }, -+}; -diff --git a/target/loongarch64/meson.build b/target/loongarch64/meson.build -new file mode 100644 -index 000000000..6badf4484 ---- /dev/null -+++ b/target/loongarch64/meson.build -@@ -0,0 +1,35 @@ -+loongarch_user_ss = ss.source_set() -+loongarch_softmmu_ss = ss.source_set() -+loongarch_ss = ss.source_set() -+loongarch_ss.add(files( -+ 'cpu.c', -+ 'fpu.c', -+ 'gdbstub.c', -+)) -+ -+gen = [ -+ decodetree.process('insn.decode', extra_args: [ '--decode', 'decode_insn', -+ '--insnwidth', '32' ]) -+] -+ -+loongarch_ss.add(gen) -+loongarch_ss.add(when: 'CONFIG_TCG', if_true: files( -+ 'helper.c', -+ 'translate.c', -+ 'op_helper.c', -+ 'fpu_helper.c', -+ 'tlb_helper.c', -+ 'csr_helper.c', -+)) -+ -+loongarch_softmmu_ss.add(when: 'CONFIG_SOFTMMU', if_true: files( -+ 'machine.c', -+ 'stabletimer.c', -+ 'arch_dump.c', -+)) -+ -+loongarch_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) -+ -+target_arch += {'loongarch64': loongarch_ss} -+target_softmmu_arch += {'loongarch64': loongarch_softmmu_ss} -+target_user_arch += {'loongarch64': loongarch_user_ss} -diff --git a/target/loongarch64/op_helper.c b/target/loongarch64/op_helper.c -new file mode 100644 -index 000000000..9a34c0d25 ---- /dev/null -+++ b/target/loongarch64/op_helper.c -@@ -0,0 +1,533 @@ -+/* -+ * LOONGARCH emulation helpers for qemu. -+ * -+ * Copyright (c) 2004-2005 Jocelyn Mayer -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+#include "qemu/osdep.h" -+#include "qemu/main-loop.h" -+#include "cpu.h" -+#include "internal.h" -+#include "qemu/host-utils.h" -+#include "exec/helper-proto.h" -+#include "exec/exec-all.h" -+#include "exec/cpu_ldst.h" -+#include "sysemu/kvm.h" -+#include "qemu/crc32c.h" -+#include -+#include "hw/irq.h" -+#include "hw/core/cpu.h" -+#include "instmap.h" -+ -+/*****************************************************************************/ -+/* Exceptions processing helpers */ -+ -+void helper_raise_exception_err(CPULOONGARCHState *env, uint32_t exception, -+ int error_code) -+{ -+ do_raise_exception_err(env, exception, error_code, 0); -+} -+ -+void helper_raise_exception(CPULOONGARCHState *env, uint32_t exception) -+{ -+ do_raise_exception(env, exception, GETPC()); -+} -+ -+void helper_raise_exception_debug(CPULOONGARCHState *env) -+{ -+ do_raise_exception(env, EXCP_DEBUG, 0); -+} -+ -+static void raise_exception(CPULOONGARCHState *env, uint32_t exception) -+{ -+ do_raise_exception(env, exception, 0); -+} -+ -+#if defined(CONFIG_USER_ONLY) -+#define HELPER_LD(name, insn, type) \ -+static inline type do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ int mem_idx, uintptr_t retaddr) \ -+{ \ -+ return (type) cpu_##insn##_data_ra(env, addr, retaddr); \ -+} -+#else -+ -+#define HF_SMAP_SHIFT 23 /* CR4.SMAP */ -+#define HF_SMAP_MASK (1 << HF_SMAP_SHIFT) -+#define MMU_KNOSMAP_IDX 2 -+#define HF_CPL_SHIFT 0 -+#define HF_CPL_MASK (3 << HF_CPL_SHIFT) -+#define AC_MASK 0x00040000 -+#define MMU_KSMAP_IDX 0 -+static inline int cpu_mmu_index_kernel(CPULOONGARCHState *env) -+{ -+ return !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP_IDX : -+ ((env->hflags & HF_CPL_MASK) < 3 && (env->hflags & AC_MASK)) -+ ? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX; -+} -+ -+#define cpu_ldl_kernel_ra(e, p, r) \ -+ cpu_ldl_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) -+ -+#define HELPER_LD(name, insn, type) \ -+static inline type do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ int mem_idx, uintptr_t retaddr) \ -+{ \ -+/* \ -+ switch (mem_idx) { \ -+ case 0: return (type) cpu_##insn##_kernel_ra(env, addr, retaddr); \ -+ case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr); \ -+ default: \ -+ case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr); \ -+ case 3: return (type) cpu_##insn##_error_ra(env, addr, retaddr); \ -+ } \ -+*/ \ -+} -+#endif -+#if 0 -+HELPER_LD(lw, ldl, int32_t) -+HELPER_LD(ld, ldq, int64_t) -+#endif -+#undef HELPER_LD -+ -+#if defined(CONFIG_USER_ONLY) -+#define HELPER_ST(name, insn, type) \ -+static inline void do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ type val, int mem_idx, uintptr_t retaddr) \ -+{ \ -+/* \ -+ cpu_##insn##_data_ra(env, addr, val, retaddr); \ -+*/ \ -+} -+#else -+#define HELPER_ST(name, insn, type) \ -+static inline void do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ type val, int mem_idx, uintptr_t retaddr) \ -+{ \ -+/* \ -+ switch (mem_idx) { \ -+ case 0: \ -+ cpu_##insn##_kernel_ra(env, addr, val, retaddr); \ -+ break; \ -+ case 1: \ -+ cpu_##insn##_super_ra(env, addr, val, retaddr); \ -+ break; \ -+ default: \ -+ case 2: \ -+ cpu_##insn##_user_ra(env, addr, val, retaddr); \ -+ break; \ -+ case 3: \ -+ cpu_##insn##_error_ra(env, addr, val, retaddr); \ -+ break; \ -+ } \ -+*/ \ -+} -+#endif -+#if 0 -+HELPER_ST(sb, stb, uint8_t) -+HELPER_ST(sw, stl, uint32_t) -+HELPER_ST(sd, stq, uint64_t) -+#endif -+#undef HELPER_ST -+ -+static inline target_ulong bitswap(target_ulong v) -+{ -+ v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | -+ ((v & (target_ulong)0x5555555555555555ULL) << 1); -+ v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | -+ ((v & (target_ulong)0x3333333333333333ULL) << 2); -+ v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | -+ ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); -+ return v; -+} -+ -+target_ulong helper_dbitswap(target_ulong rt) -+{ -+ return bitswap(rt); -+} -+ -+target_ulong helper_bitswap(target_ulong rt) -+{ -+ return (int32_t)bitswap(rt); -+} -+ -+/* these crc32 functions are based on target/arm/helper-a64.c */ -+target_ulong helper_crc32(target_ulong val, target_ulong m, uint32_t sz) -+{ -+ uint8_t buf[8]; -+ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); -+ -+ m &= mask; -+ stq_le_p(buf, m); -+ return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); -+} -+ -+target_ulong helper_crc32c(target_ulong val, target_ulong m, uint32_t sz) -+{ -+ uint8_t buf[8]; -+ target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); -+ m &= mask; -+ stq_le_p(buf, m); -+ return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); -+} -+ -+#ifndef CONFIG_USER_ONLY -+ -+#define HELPER_LD_ATOMIC(name, insn, almask) \ -+target_ulong helper_##name(CPULOONGARCHState *env, target_ulong arg, int mem_idx) \ -+{ \ -+/* \ -+ if (arg & almask) { \ -+ env->CSR_BADV = arg; \ -+ do_raise_exception(env, EXCP_AdEL, GETPC()); \ -+ } \ -+ env->lladdr = arg; \ -+ env->llval = do_##insn(env, arg, mem_idx, GETPC()); \ -+ return env->llval; \ -+*/ \ -+} -+#if 0 -+HELPER_LD_ATOMIC(ll, lw, 0x3) -+HELPER_LD_ATOMIC(lld, ld, 0x7) -+#endif -+#undef HELPER_LD_ATOMIC -+#endif -+ -+#ifndef CONFIG_USER_ONLY -+void helper_drdtime(CPULOONGARCHState *env, target_ulong rd, target_ulong rs) -+{ -+ env->active_tc.gpr[rd] = cpu_loongarch_get_stable_counter(env); -+ env->active_tc.gpr[rs] = env->CSR_TMID; -+} -+#endif -+ -+#ifndef CONFIG_USER_ONLY -+static void debug_pre_ertn(CPULOONGARCHState *env) -+{ -+ if (qemu_loglevel_mask(CPU_LOG_EXEC)) { -+ qemu_log("ERTN: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx, -+ env->active_tc.PC, env->CSR_ERA); -+ qemu_log("\n"); -+ } -+} -+ -+static void debug_post_ertn(CPULOONGARCHState *env) -+{ -+ if (qemu_loglevel_mask(CPU_LOG_EXEC)) { -+ qemu_log("ERTN: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx, -+ env->active_tc.PC, env->CSR_ERA); -+ } -+} -+ -+static void set_pc(CPULOONGARCHState *env, target_ulong error_pc) -+{ -+ env->active_tc.PC = error_pc & ~(target_ulong)1; -+} -+ -+static inline void exception_return(CPULOONGARCHState *env) -+{ -+ debug_pre_ertn(env); -+ -+ if (cpu_refill_state(env)) { -+ env->CSR_CRMD &= (~0x7); -+ env->CSR_CRMD |= (env->CSR_TLBRPRMD & 0x7); -+ /* Clear Refill flag and set pc */ -+ env->CSR_TLBRERA &= (~0x1); -+ set_pc(env, env->CSR_TLBRERA); -+ if (qemu_loglevel_mask(CPU_LOG_INT)) { -+ qemu_log("%s: TLBRERA 0x%lx\n", __func__, env->CSR_TLBRERA); -+ } -+ } else { -+ env->CSR_CRMD &= (~0x7); -+ env->CSR_CRMD |= (env->CSR_PRMD & 0x7); -+ /* Clear Refill flag and set pc*/ -+ set_pc(env, env->CSR_ERA); -+ if (qemu_loglevel_mask(CPU_LOG_INT)) { -+ qemu_log("%s: ERA 0x%lx\n", __func__, env->CSR_ERA); -+ } -+ } -+ -+ compute_hflags(env); -+ debug_post_ertn(env); -+} -+ -+void helper_ertn(CPULOONGARCHState *env) -+{ -+ exception_return(env); -+ env->lladdr = 1; -+} -+ -+#endif /* !CONFIG_USER_ONLY */ -+ -+void helper_idle(CPULOONGARCHState *env) -+{ -+ CPUState *cs = CPU(loongarch_env_get_cpu(env)); -+ -+ cs->halted = 1; -+ cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); -+ /* Last instruction in the block, PC was updated before -+ - no need to recover PC and icount */ -+ raise_exception(env, EXCP_HLT); -+} -+ -+#if !defined(CONFIG_USER_ONLY) -+ -+void loongarch_cpu_do_unaligned_access(CPUState *cs, vaddr addr, -+ MMUAccessType access_type, -+ int mmu_idx, uintptr_t retaddr) -+{ -+ while(1); -+} -+ -+#endif /* !CONFIG_USER_ONLY */ -+ -+void helper_store_scr(CPULOONGARCHState *env, uint32_t n, target_ulong val) -+{ -+ env->scr[n & 0x3] = val; -+} -+ -+target_ulong helper_load_scr(CPULOONGARCHState *env, uint32_t n) -+{ -+ return env->scr[n & 0x3]; -+} -+ -+/* loongarch assert op */ -+void helper_asrtle_d(CPULOONGARCHState *env, target_ulong rs, target_ulong rt) -+{ -+ if (rs > rt) { -+ do_raise_exception(env, EXCP_AdEL, GETPC()); -+ } -+} -+ -+void helper_asrtgt_d(CPULOONGARCHState *env, target_ulong rs, target_ulong rt) -+{ -+ if (rs <= rt) { -+ do_raise_exception(env, EXCP_AdEL, GETPC()); -+ } -+} -+ -+target_ulong helper_cto_w(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint32_t v = (uint32_t)a0; -+ int temp = 0; -+ -+ while ((v & 0x1) == 1) { -+ temp++; -+ v = v >> 1; -+ } -+ -+ return (target_ulong)temp; -+} -+ -+target_ulong helper_ctz_w(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint32_t v = (uint32_t)a0; -+ -+ if (v == 0) { -+ return 32; -+ } -+ -+ int temp = 0; -+ while ((v & 0x1) == 0) { -+ temp++; -+ v = v >> 1; -+ } -+ -+ return (target_ulong)temp; -+} -+ -+target_ulong helper_cto_d(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint64_t v = a0; -+ int temp = 0; -+ -+ while ((v & 0x1) == 1) { -+ temp++; -+ v = v >> 1; -+ } -+ -+ return (target_ulong)temp; -+} -+ -+target_ulong helper_ctz_d(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint64_t v = a0; -+ -+ if (v == 0) { -+ return 64; -+ } -+ -+ int temp = 0; -+ while ((v & 0x1) == 0) { -+ temp++; -+ v = v >> 1; -+ } -+ -+ return (target_ulong)temp; -+} -+ -+target_ulong helper_bitrev_w(CPULOONGARCHState *env, target_ulong a0) -+{ -+ int32_t v = (int32_t)a0; -+ const int SIZE = 32; -+ uint8_t bytes[SIZE]; -+ -+ int i; -+ for (i = 0; i < SIZE; i++) { -+ bytes[i] = v & 0x1; -+ v = v >> 1; -+ } -+ /* v == 0 */ -+ for (i = 0; i < SIZE; i++) { -+ v = v | ((uint32_t)bytes[i] << (SIZE - 1 - i)); -+ } -+ -+ return (target_ulong)(int32_t)v; -+} -+ -+target_ulong helper_bitrev_d(CPULOONGARCHState *env, target_ulong a0) -+{ -+ uint64_t v = a0; -+ const int SIZE = 64; -+ uint8_t bytes[SIZE]; -+ -+ int i; -+ for (i = 0; i < SIZE; i++) { -+ bytes[i] = v & 0x1; -+ v = v >> 1; -+ } -+ /* v == 0 */ -+ for (i = 0; i < SIZE; i++) { -+ v = v | ((uint64_t)bytes[i] << (SIZE - 1 - i)); -+ } -+ -+ return (target_ulong)v; -+} -+ -+void helper_memtrace_addr(CPULOONGARCHState *env, -+ target_ulong address, uint32_t op) -+{ -+ qemu_log("[cpu %d asid 0x%lx pc 0x%lx] addr 0x%lx op", -+ CPU(loongarch_env_get_cpu(env))->cpu_index, -+ env->CSR_ASID, env->active_tc.PC, address); -+ switch (op) { -+ case OPC_LARCH_LDPTR_D: -+ qemu_log("OPC_LARCH_LDPTR_D"); -+ break; -+ case OPC_LARCH_LD_D: -+ qemu_log("OPC_LARCH_LD_D"); -+ break; -+ case OPC_LARCH_LDPTR_W: -+ qemu_log("OPC_LARCH_LDPTR_W"); -+ break; -+ case OPC_LARCH_LD_W: -+ qemu_log("OPC_LARCH_LD_W"); -+ break; -+ case OPC_LARCH_LD_H: -+ qemu_log("OPC_LARCH_LD_H"); -+ break; -+ case OPC_LARCH_LD_B: -+ qemu_log("OPC_LARCH_LD_B"); -+ break; -+ case OPC_LARCH_LD_WU: -+ qemu_log("OPC_LARCH_LD_WU"); -+ break; -+ case OPC_LARCH_LD_HU: -+ qemu_log("OPC_LARCH_LD_HU"); -+ break; -+ case OPC_LARCH_LD_BU: -+ qemu_log("OPC_LARCH_LD_BU"); -+ break; -+ case OPC_LARCH_STPTR_D: -+ qemu_log("OPC_LARCH_STPTR_D"); -+ break; -+ case OPC_LARCH_ST_D: -+ qemu_log("OPC_LARCH_ST_D"); -+ break; -+ case OPC_LARCH_STPTR_W: -+ qemu_log("OPC_LARCH_STPTR_W"); -+ break; -+ case OPC_LARCH_ST_W: -+ qemu_log("OPC_LARCH_ST_W"); -+ break; -+ case OPC_LARCH_ST_H: -+ qemu_log("OPC_LARCH_ST_H"); -+ break; -+ case OPC_LARCH_ST_B: -+ qemu_log("OPC_LARCH_ST_B"); -+ break; -+ case OPC_LARCH_FLD_S: -+ qemu_log("OPC_LARCH_FLD_S"); -+ break; -+ case OPC_LARCH_FLD_D: -+ qemu_log("OPC_LARCH_FLD_D"); -+ break; -+ case OPC_LARCH_FST_S: -+ qemu_log("OPC_LARCH_FST_S"); -+ break; -+ case OPC_LARCH_FST_D: -+ qemu_log("OPC_LARCH_FST_D"); -+ break; -+ case OPC_LARCH_FLDX_S: -+ qemu_log("OPC_LARCH_FLDX_S"); -+ break; -+ case OPC_LARCH_FLDGT_S: -+ qemu_log("OPC_LARCH_FLDGT_S"); -+ break; -+ case OPC_LARCH_FLDLE_S: -+ qemu_log("OPC_LARCH_FLDLE_S"); -+ break;; -+ case OPC_LARCH_FSTX_S: -+ qemu_log("OPC_LARCH_FSTX_S"); -+ break; -+ case OPC_LARCH_FSTGT_S: -+ qemu_log("OPC_LARCH_FSTGT_S"); -+ break; -+ case OPC_LARCH_FSTLE_S: -+ qemu_log("OPC_LARCH_FSTLE_S"); -+ break; -+ case OPC_LARCH_FLDX_D: -+ qemu_log("OPC_LARCH_FLDX_D"); -+ break; -+ case OPC_LARCH_FLDGT_D: -+ qemu_log("OPC_LARCH_FLDGT_D"); -+ break; -+ case OPC_LARCH_FLDLE_D: -+ qemu_log("OPC_LARCH_FLDLE_D"); -+ break;; -+ case OPC_LARCH_FSTX_D: -+ qemu_log("OPC_LARCH_FSTX_D"); -+ break; -+ case OPC_LARCH_FSTGT_D: -+ qemu_log("OPC_LARCH_FSTGT_D"); -+ break; -+ case OPC_LARCH_FSTLE_D: -+ qemu_log("OPC_LARCH_FSTLE_D"); -+ break; -+ case OPC_LARCH_LL_W: -+ qemu_log("OPC_LARCH_LL_W"); -+ break; -+ case OPC_LARCH_LL_D: -+ qemu_log("OPC_LARCH_LL_D"); -+ break; -+ default: -+ qemu_log("0x%x", op); -+ } -+} -+ -+void helper_memtrace_val(CPULOONGARCHState *env, target_ulong val) -+{ -+ qemu_log("val 0x%lx\n", val); -+} -diff --git a/target/loongarch64/stabletimer.c b/target/loongarch64/stabletimer.c -new file mode 100644 -index 000000000..b86fecf89 ---- /dev/null -+++ b/target/loongarch64/stabletimer.c -@@ -0,0 +1,122 @@ -+/* -+ * QEMU LOONGARCH timer support -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/loongarch/cpudevs.h" -+#include "qemu/timer.h" -+#include "sysemu/kvm.h" -+#include "internal.h" -+#include "hw/irq.h" -+ -+ -+#ifdef DEBUG_TIMER -+#define debug_timer(fmt, args...) printf("%s(%d)-%s -> " #fmt "\n", \ -+ __FILE__, __LINE__, __func__, ##args); -+#else -+#define debug_timer(fmt, args...) -+#endif -+ -+#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */ -+#define STABLETIMER_TICK_MASK 0xfffffffffffcUL -+#define STABLETIMER_ENABLE 0x1UL -+#define STABLETIMER_PERIOD 0x2UL -+ -+/* return random value in [low, high] */ -+uint32_t cpu_loongarch_get_random_ls3a5k_tlb(uint32_t low, uint32_t high) -+{ -+ static uint32_t seed = 5; -+ static uint32_t prev_idx; -+ uint32_t idx; -+ uint32_t nb_rand_tlb = high - low + 1; -+ -+ do { -+ seed = 1103515245 * seed + 12345; -+ idx = (seed >> 16) % nb_rand_tlb + low; -+ } while (idx == prev_idx); -+ prev_idx = idx; -+ -+ return idx; -+} -+ -+/* LOONGARCH timer */ -+uint64_t cpu_loongarch_get_stable_counter(CPULOONGARCHState *env) -+{ -+ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD; -+} -+ -+uint64_t cpu_loongarch_get_stable_timer_ticks(CPULOONGARCHState *env) -+{ -+ uint64_t now, expire; -+ -+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -+ expire = timer_expire_time_ns(env->timer); -+ -+ return (expire - now) / TIMER_PERIOD; -+} -+ -+void cpu_loongarch_store_stable_timer_config(CPULOONGARCHState *env, -+ uint64_t value) -+{ -+ uint64_t now, next; -+ -+ env->CSR_TCFG = value; -+ if (value & STABLETIMER_ENABLE) { -+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -+ next = now + (value & STABLETIMER_TICK_MASK) * TIMER_PERIOD; -+ timer_mod(env->timer, next); -+ } -+ debug_timer("0x%lx 0x%lx now 0x%lx, next 0x%lx", -+ value, env->CSR_TCFG, now, next); -+} -+ -+static void loongarch_stable_timer_cb(void *opaque) -+{ -+ CPULOONGARCHState *env; -+ uint64_t now, next; -+ -+ env = opaque; -+ debug_timer(); -+ if (env->CSR_TCFG & STABLETIMER_PERIOD) { -+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -+ next = now + (env->CSR_TCFG & STABLETIMER_TICK_MASK) * TIMER_PERIOD; -+ timer_mod(env->timer, next); -+ } else { -+ env->CSR_TCFG &= ~STABLETIMER_ENABLE; -+ } -+ -+ qemu_irq_raise(env->irq[IRQ_TIMER]); -+ -+} -+ -+void cpu_loongarch_clock_init(LOONGARCHCPU *cpu) -+{ -+ CPULOONGARCHState *env = &cpu->env; -+ -+ /* -+ * If we're in KVM mode, don't create the periodic timer, that is handled in -+ * kernel. -+ */ -+ if (!kvm_enabled()) { -+ env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, -+ &loongarch_stable_timer_cb, env); -+ } -+} -diff --git a/target/loongarch64/tlb_helper.c b/target/loongarch64/tlb_helper.c -new file mode 100644 -index 000000000..f5e68349a ---- /dev/null -+++ b/target/loongarch64/tlb_helper.c -@@ -0,0 +1,729 @@ -+/* -+ * loongarch tlb emulation helpers for qemu. -+ * -+ * Copyright (c) 2020 -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+#include "qemu/osdep.h" -+#include "qemu/main-loop.h" -+#include "cpu.h" -+#include "internal.h" -+#include "qemu/host-utils.h" -+#include "exec/helper-proto.h" -+#include "exec/exec-all.h" -+#include "exec/cpu_ldst.h" -+ -+#ifndef CONFIG_USER_ONLY -+ -+#define HELPER_LD(name, insn, type) \ -+static inline type do_##name(CPULOONGARCHState *env, target_ulong addr, \ -+ int mem_idx, uintptr_t retaddr) \ -+{ \ -+/* \ -+ switch (mem_idx) { \ -+ case 0: return (type) cpu_##insn##_kernel_ra(env, addr, retaddr); \ -+ case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr); \ -+ default: \ -+ case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr); \ -+ case 3: return (type) cpu_##insn##_error_ra(env, addr, retaddr); \ -+ } \ -+*/ \ -+} -+#if 0 -+HELPER_LD(lw, ldl, int32_t) -+HELPER_LD(ld, ldq, int64_t) -+#endif -+ -+void helper_lddir(CPULOONGARCHState *env, target_ulong base, target_ulong rt, -+ target_ulong level, uint32_t mem_idx) -+{ -+#if 0 -+ target_ulong pointer = env->active_tc.gpr[base]; -+ target_ulong badvaddr; -+ target_ulong index; -+ target_ulong vaddr; -+ int shift; -+ -+ badvaddr = env->CSR_TLBRBADV; -+ -+ /* 0:8B, 1:16B, 2:32B, 3:64B */ -+ shift = (env->CSR_PWCTL0 >> 30) & 0x3; -+ shift = (shift + 1) * 3; -+ -+ switch (level) { -+ case 1: -+ index = (badvaddr >> ((env->CSR_PWCTL0 >> 10) & 0x1f)) & \ -+ ((1 << ((env->CSR_PWCTL0 >> 15) & 0x1f)) - 1); -+ break; -+ case 3: -+ index = (badvaddr >> ((env->CSR_PWCTL1 >> 0) & 0x3f)) & \ -+ ((1 << ((env->CSR_PWCTL1 >> 6) & 0x3f)) - 1); -+ break; -+ default: -+ do_raise_exception(env, EXCP_RI, GETPC()); -+ return; -+ } -+ -+ vaddr = pointer | index << shift; -+ env->active_tc.gpr[rt] = do_ld(env, vaddr, mem_idx, GETPC()); -+ return; -+#endif -+} -+ -+void helper_ldpte(CPULOONGARCHState *env, target_ulong base, target_ulong odd, -+ uint32_t mem_idx) -+{ -+#if 0 -+ target_ulong pointer = env->active_tc.gpr[base]; -+ target_ulong vaddr; -+ target_ulong tmp0 = 1; -+ target_ulong ptindex, ptoffset0, ptoffset1; -+ target_ulong pagesize; -+ target_ulong badv; -+ int shift; -+ bool huge = pointer & LOONGARCH_PAGE_HUGE; -+ -+ if (huge) { -+ /* Huge Page. pointer is paddr */ -+ tmp0 = pointer ^ LOONGARCH_PAGE_HUGE; -+ /* move Global bit */ -+ tmp0 |= ((tmp0 & LOONGARCH_HUGE_GLOBAL) -+ >> (LOONGARCH_HUGE_GLOBAL_SH - CSR_TLBLO0_GLOBAL_SHIFT)); -+ pagesize = (env->CSR_PWCTL0 & 0x1f) + -+ ((env->CSR_PWCTL0 >> 5) & 0x1f) - 1; -+ if (odd) { -+ tmp0 += (1 << pagesize); -+ } -+ } else { -+ /* 0:8B, 1:16B, 2:32B, 3:64B */ -+ shift = (env->CSR_PWCTL0 >> 30) & 0x3; -+ shift = (shift + 1) * 3; -+ badv = env->CSR_TLBRBADV; -+ -+ ptindex = (badv >> (env->CSR_PWCTL0 & 0x1f)) & -+ ((1 << ((env->CSR_PWCTL0 >> 5) & 0x1f)) - 1); -+ ptindex = ptindex & ~0x1; /* clear bit 0 */ -+ ptoffset0 = ptindex << shift; -+ ptoffset1 = (ptindex + 1) << shift; -+ -+ vaddr = pointer | (odd ? ptoffset1 : ptoffset0); -+ tmp0 = do_ld(env, vaddr, mem_idx, GETPC()); -+ pagesize = (env->CSR_PWCTL0 & 0x1f); -+ } -+ if (odd) { -+ env->CSR_TLBRELO1 = tmp0; -+ } else { -+ env->CSR_TLBRELO0 = tmp0; -+ } -+ env->CSR_TLBREHI = env->CSR_TLBREHI & (~0x3f); -+ env->CSR_TLBREHI = env->CSR_TLBREHI | pagesize; -+#endif -+ return; -+} -+ -+target_ulong helper_read_pgd(CPULOONGARCHState *env) -+{ -+ uint64_t badv; -+ -+ assert(env->CSR_TLBRERA & 0x1); -+ -+ if (env->CSR_TLBRERA & 0x1) { -+ badv = env->CSR_TLBRBADV; -+ } else { -+ badv = env->CSR_BADV; -+ } -+ -+ if ((badv >> 63) & 0x1) { -+ return env->CSR_PGDH; -+ } else { -+ return env->CSR_PGDL; -+ } -+} -+ -+/* TLB management */ -+static uint64_t ls3a5k_pagesize_to_mask(int pagesize) -+{ -+ /* 4KB - 1GB */ -+ if (pagesize < 12 && pagesize > 30) { -+ printf("[ERROR] unsupported page size %d\n", pagesize); -+ exit(-1); -+ } -+ -+ return (1 << (pagesize + 1)) - 1; -+} -+ -+static void ls3a5k_fill_tlb_entry(CPULOONGARCHState *env, -+ ls3a5k_tlb_t *tlb, int is_ftlb) -+{ -+ uint64_t page_mask; /* 0000...00001111...1111 */ -+ uint32_t page_size; -+ uint64_t entryhi; -+ uint64_t lo0, lo1; -+ -+ if (env->CSR_TLBRERA & 0x1) { -+ page_size = env->CSR_TLBREHI & 0x3f; -+ entryhi = env->CSR_TLBREHI; -+ lo0 = env->CSR_TLBRELO0; -+ lo1 = env->CSR_TLBRELO1; -+ } else { -+ page_size = (env->CSR_TLBIDX >> CSR_TLBIDX_PS_SHIFT) & 0x3f; -+ entryhi = env->CSR_TLBEHI; -+ lo0 = env->CSR_TLBELO0; -+ lo1 = env->CSR_TLBELO1; -+ } -+ -+ if (page_size == 0) { -+ printf("Warning: page_size is 0\n"); -+ } -+ -+ /* 15-12 11-8 7-4 3-0 -+ * 4KB: 0001 1111 1111 1111 // double 4KB mask [12:0] -+ * 16KB: 0111 1111 1111 1111 // double 16KB mask [14:0] -+ */ -+ if (is_ftlb) { -+ page_mask = env->tlb->mmu.ls3a5k.ftlb_mask; -+ } else { -+ page_mask = ls3a5k_pagesize_to_mask(page_size); -+ } -+ -+ tlb->VPN = entryhi & 0xffffffffe000 & ~page_mask; -+ -+ tlb->ASID = env->CSR_ASID & 0x3ff; /* CSR_ASID[9:0] */ -+ tlb->EHINV = 0; -+ tlb->G = (lo0 >> CSR_TLBLO0_GLOBAL_SHIFT) & /* CSR_TLBLO[6] */ -+ (lo1 >> CSR_TLBLO1_GLOBAL_SHIFT) & 1; -+ -+ tlb->PageMask = page_mask; -+ tlb->PageSize = page_size; -+ -+ tlb->V0 = (lo0 >> CSR_TLBLO0_V_SHIFT) & 0x1; /* [0] */ -+ tlb->WE0 = (lo0 >> CSR_TLBLO0_WE_SHIFT) & 0x1; /* [1] */ -+ tlb->PLV0 = (lo0 >> CSR_TLBLO0_PLV_SHIFT) & 0x3; /* [3:2] */ -+ tlb->C0 = (lo0 >> CSR_TLBLO0_CCA_SHIFT) & 0x3; /* [5:4] */ -+ tlb->PPN0 = (lo0 & 0xfffffffff000 & ~(page_mask >> 1)); -+ tlb->RI0 = (lo0 >> CSR_TLBLO0_RI_SHIFT) & 0x1; /* [61] */ -+ tlb->XI0 = (lo0 >> CSR_TLBLO0_XI_SHIFT) & 0x1; /* [62] */ -+ tlb->RPLV0 = (lo0 >> CSR_TLBLO0_RPLV_SHIFT) & 0x1; /* [63] */ -+ -+ tlb->V1 = (lo1 >> CSR_TLBLO1_V_SHIFT) & 0x1; /* [0] */ -+ tlb->WE1 = (lo1 >> CSR_TLBLO1_WE_SHIFT) & 0x1; /* [1] */ -+ tlb->PLV1 = (lo1 >> CSR_TLBLO1_PLV_SHIFT) & 0x3; /* [3:2] */ -+ tlb->C1 = (lo1 >> CSR_TLBLO1_CCA_SHIFT) & 0x3; /* [5:4] */ -+ tlb->PPN1 = (lo1 & 0xfffffffff000 & ~(page_mask >> 1)); -+ tlb->RI1 = (lo1 >> CSR_TLBLO1_RI_SHIFT) & 0x1; /* [61] */ -+ tlb->XI1 = (lo1 >> CSR_TLBLO1_XI_SHIFT) & 0x1; /* [62] */ -+ tlb->RPLV1 = (lo1 >> CSR_TLBLO1_RPLV_SHIFT) & 0x1; /* [63] */ -+} -+ -+static void ls3a5k_fill_tlb(CPULOONGARCHState *env, int idx, bool tlbwr) -+{ -+ ls3a5k_tlb_t *tlb; -+ -+ tlb = &env->tlb->mmu.ls3a5k.tlb[idx]; -+ if (tlbwr) { -+ if ((env->CSR_TLBIDX >> CSR_TLBIDX_EHINV_SHIFT) & 0x1) { -+ tlb->EHINV = 1; -+ return; -+ } -+ } -+ -+ if (idx < 2048) { -+ ls3a5k_fill_tlb_entry(env, tlb, 1); -+ } else { -+ ls3a5k_fill_tlb_entry(env, tlb, 0); -+ } -+} -+ -+void ls3a5k_flush_vtlb(CPULOONGARCHState *env) -+{ -+ uint32_t ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ uint32_t vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; -+ int i; -+ -+ ls3a5k_tlb_t *tlb; -+ -+ for (i = ftlb_size; i < ftlb_size + vtlb_size; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ tlb->EHINV = 1; -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+void ls3a5k_flush_ftlb(CPULOONGARCHState *env) -+{ -+ uint32_t ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ int i; -+ -+ ls3a5k_tlb_t *tlb; -+ -+ for (i = 0; i < ftlb_size; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ tlb->EHINV = 1; -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+void ls3a5k_helper_tlbclr(CPULOONGARCHState *env) -+{ -+ int i; -+ uint16_t asid; -+ int vsize, fsize, index; -+ int start = 0, end = -1; -+ -+ asid = env->CSR_ASID & 0x3ff; -+ vsize = env->tlb->mmu.ls3a5k.vtlb_size; -+ fsize = env->tlb->mmu.ls3a5k.ftlb_size; -+ index = env->CSR_TLBIDX & CSR_TLBIDX_IDX; -+ -+ if (index < fsize) { -+ /* FTLB. One line per operation */ -+ int set = index % 256; -+ start = set * 8; -+ end = start + 7; -+ } else if (index < (fsize + vsize)) { -+ /* VTLB. All entries */ -+ start = fsize; -+ end = fsize + vsize - 1; -+ } else { -+ /* Ignore */ -+ } -+ -+ for (i = start; i <= end; i++) { -+ ls3a5k_tlb_t *tlb; -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ if (!tlb->G && tlb->ASID == asid) { -+ tlb->EHINV = 1; -+ } -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+void ls3a5k_helper_tlbflush(CPULOONGARCHState *env) -+{ -+ int i; -+ int vsize, fsize, index; -+ int start = 0, end = -1; -+ -+ vsize = env->tlb->mmu.ls3a5k.vtlb_size; -+ fsize = env->tlb->mmu.ls3a5k.ftlb_size; -+ index = env->CSR_TLBIDX & CSR_TLBIDX_IDX; -+ -+ if (index < fsize) { -+ /* FTLB. One line per operation */ -+ int set = index % 256; -+ start = set * 8; -+ end = start + 7; -+ } else if (index < (fsize + vsize)) { -+ /* VTLB. All entries */ -+ start = fsize; -+ end = fsize + vsize - 1; -+ } else { -+ /* Ignore */ -+ } -+ -+ for (i = start; i <= end; i++) { -+ env->tlb->mmu.ls3a5k.tlb[i].EHINV = 1; -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+void ls3a5k_helper_invtlb(CPULOONGARCHState *env, target_ulong addr, -+ target_ulong info, int op) -+{ -+ uint32_t asid = info & 0x3ff; -+ int i; -+ -+ switch (op) { -+ case 0: -+ case 1: -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ env->tlb->mmu.ls3a5k.tlb[i].EHINV = 1; -+ } -+ break; -+ case 4: { -+ int i; -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ struct ls3a5k_tlb_t *tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ -+ if (!tlb->G && tlb->ASID == asid) { -+ tlb->EHINV = 1; -+ } -+ } -+ break; -+ } -+ -+ case 5: { -+ int i; -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ struct ls3a5k_tlb_t *tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ uint64_t vpn = addr & 0xffffffffe000 & ~tlb->PageMask; -+ -+ if (!tlb->G && tlb->ASID == asid && vpn == tlb->VPN) { -+ tlb->EHINV = 1; -+ } -+ } -+ break; -+ } -+ case 6: { -+ int i; -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ struct ls3a5k_tlb_t *tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ uint64_t vpn = addr & 0xffffffffe000 & ~tlb->PageMask; -+ -+ if ((tlb->G || tlb->ASID == asid) && vpn == tlb->VPN) { -+ tlb->EHINV = 1; -+ } -+ } -+ break; -+ } -+ default: -+ helper_raise_exception(env, EXCP_RI); -+ } -+ -+ cpu_loongarch_tlb_flush(env); -+} -+ -+static void ls3a5k_invalidate_tlb_entry(CPULOONGARCHState *env, -+ ls3a5k_tlb_t *tlb) -+{ -+ LOONGARCHCPU *cpu = loongarch_env_get_cpu(env); -+ CPUState *cs = CPU(cpu); -+ target_ulong addr; -+ target_ulong end; -+ target_ulong mask; -+ -+ mask = tlb->PageMask; /* 000...000111...111 */ -+ -+ if (tlb->V0) { -+ addr = tlb->VPN & ~mask; /* xxx...xxx[0]000..0000 */ -+ end = addr | (mask >> 1); /* xxx...xxx[0]111..1111 */ -+ while (addr < end) { -+ tlb_flush_page(cs, addr); -+ addr += TARGET_PAGE_SIZE; -+ } -+ } -+ -+ if (tlb->V1) { -+ /* xxx...xxx[1]000..0000 */ -+ addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); -+ end = addr | mask; /* xxx...xxx[1]111..1111 */ -+ while (addr - 1 < end) { -+ tlb_flush_page(cs, addr); -+ addr += TARGET_PAGE_SIZE; -+ } -+ } -+} -+ -+void ls3a5k_invalidate_tlb(CPULOONGARCHState *env, int idx) -+{ -+ ls3a5k_tlb_t *tlb; -+ int asid = env->CSR_ASID & 0x3ff; -+ tlb = &env->tlb->mmu.ls3a5k.tlb[idx]; -+ if (tlb->G == 0 && tlb->ASID != asid) { -+ return; -+ } -+ ls3a5k_invalidate_tlb_entry(env, tlb); -+} -+ -+void ls3a5k_helper_tlbwr(CPULOONGARCHState *env) -+{ -+ int idx = env->CSR_TLBIDX & CSR_TLBIDX_IDX; /* [11:0] */ -+ -+ /* Convert idx if in FTLB */ -+ if (idx < env->tlb->mmu.ls3a5k.ftlb_size) { -+ /* -+ * 0 3 6 0 1 2 -+ * 1 4 7 => 3 4 5 -+ * 2 5 8 6 7 8 -+ */ -+ int set = idx % 256; -+ int way = idx / 256; -+ idx = set * 8 + way; -+ } -+ ls3a5k_invalidate_tlb(env, idx); -+ ls3a5k_fill_tlb(env, idx, true); -+} -+ -+void ls3a5k_helper_tlbfill(CPULOONGARCHState *env) -+{ -+ uint64_t mask; -+ uint64_t address; -+ int idx; -+ int set, ftlb_idx; -+ -+ uint64_t entryhi; -+ uint32_t pagesize; -+ -+ if (env->CSR_TLBRERA & 0x1) { -+ entryhi = env->CSR_TLBREHI & ~0x3f; -+ pagesize = env->CSR_TLBREHI & 0x3f; -+ } else { -+ entryhi = env->CSR_TLBEHI; -+ pagesize = (env->CSR_TLBIDX >> CSR_TLBIDX_PS_SHIFT) & 0x3f; -+ } -+ -+ uint32_t ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ uint32_t vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; -+ -+ mask = ls3a5k_pagesize_to_mask(pagesize); -+ -+ if (mask == env->tlb->mmu.ls3a5k.ftlb_mask && -+ env->tlb->mmu.ls3a5k.ftlb_size > 0) { -+ /* only write into FTLB */ -+ address = entryhi & 0xffffffffe000; /* [47:13] */ -+ -+ /* choose one set ramdomly */ -+ set = cpu_loongarch_get_random_ls3a5k_tlb(0, 7); -+ -+ /* index in one set */ -+ ftlb_idx = (address >> 15) & 0xff; /* [0,255] */ -+ -+ /* final idx */ -+ idx = ftlb_idx * 8 + set; /* max is 7 + 8 * 255 = 2047 */ -+ } else { -+ /* only write into VTLB */ -+ int wired_nr = env->CSR_TLBWIRED & 0x3f; -+ idx = cpu_loongarch_get_random_ls3a5k_tlb( -+ ftlb_size + wired_nr, ftlb_size + vtlb_size - 1); -+ } -+ -+ ls3a5k_invalidate_tlb(env, idx); -+ ls3a5k_fill_tlb(env, idx, false); -+} -+ -+void ls3a5k_helper_tlbsrch(CPULOONGARCHState *env) -+{ -+ uint64_t mask; -+ uint64_t vpn; -+ uint64_t tag; -+ uint16_t asid; -+ -+ int ftlb_size = env->tlb->mmu.ls3a5k.ftlb_size; -+ int vtlb_size = env->tlb->mmu.ls3a5k.vtlb_size; -+ int i; -+ int ftlb_idx; /* [0,255] 2^8 0xff */ -+ -+ ls3a5k_tlb_t *tlb; -+ -+ asid = env->CSR_ASID & 0x3ff; -+ -+ /* search VTLB */ -+ for (i = ftlb_size; i < ftlb_size + vtlb_size; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[i]; -+ mask = tlb->PageMask; -+ -+ vpn = env->CSR_TLBEHI & 0xffffffffe000 & ~mask; -+ tag = tlb->VPN & ~mask; -+ -+ if ((tlb->G == 1 || tlb->ASID == asid) && vpn == tag && tlb->EHINV != 1) -+ { -+ env->CSR_TLBIDX = (i & 0xfff) | -+ ((tlb->PageSize & 0x3f) << CSR_TLBIDX_PS_SHIFT); -+ goto _MATCH_OUT_; -+ } -+ } -+ -+ if (ftlb_size == 0) { -+ goto _NO_MATCH_OUT_; -+ } -+ -+ /* search FTLB */ -+ mask = env->tlb->mmu.ls3a5k.ftlb_mask; -+ vpn = env->CSR_TLBEHI & 0xffffffffe000 & ~mask; -+ -+ ftlb_idx = (env->CSR_TLBEHI & 0xffffffffe000) >> 15; /* 16 KB */ -+ ftlb_idx = ftlb_idx & 0xff; /* [0,255] */ -+ -+ for (i = 0; i < 8; ++i) { -+ tlb = &env->tlb->mmu.ls3a5k.tlb[ftlb_idx * 8 + i]; -+ tag = tlb->VPN & ~mask; -+ -+ if ((tlb->G == 1 || tlb->ASID == asid) && vpn == tag && tlb->EHINV != 1) -+ { -+ env->CSR_TLBIDX = ((i * 256 + ftlb_idx) & 0xfff) | -+ ((tlb->PageSize & 0x3f) << CSR_TLBIDX_PS_SHIFT); -+ goto _MATCH_OUT_; -+ } -+ } -+ -+_NO_MATCH_OUT_: -+ env->CSR_TLBIDX = 1 << CSR_TLBIDX_EHINV_SHIFT; -+_MATCH_OUT_: -+ return; -+} -+ -+void ls3a5k_helper_tlbrd(CPULOONGARCHState *env) -+{ -+ ls3a5k_tlb_t *tlb; -+ int idx; -+ uint16_t asid; -+ -+ idx = env->CSR_TLBIDX & CSR_TLBIDX_IDX; -+ if (idx < env->tlb->mmu.ls3a5k.ftlb_size) { -+ int set = idx % 256; -+ int way = idx / 256; -+ idx = set * 8 + way; -+ } -+ -+ tlb = &env->tlb->mmu.ls3a5k.tlb[idx]; -+ -+ asid = env->CSR_ASID & 0x3ff; -+ -+ if (asid != tlb->ASID) { -+ cpu_loongarch_tlb_flush(env); -+ } -+ -+ if (tlb->EHINV) { -+ /* invalid TLB entry */ -+ env->CSR_TLBIDX = 1 << CSR_TLBIDX_EHINV_SHIFT; -+ env->CSR_TLBEHI = 0; -+ env->CSR_TLBELO0 = 0; -+ env->CSR_TLBELO1 = 0; -+ } else { -+ /* valid TLB entry */ -+ env->CSR_TLBIDX = (env->CSR_TLBIDX & 0xfff) | -+ ((tlb->PageSize & 0x3f) << CSR_TLBIDX_PS_SHIFT); -+ env->CSR_TLBEHI = tlb->VPN; -+ env->CSR_TLBELO0 = (tlb->V0 << CSR_TLBLO0_V_SHIFT) | -+ (tlb->WE0 << CSR_TLBLO0_WE_SHIFT) | -+ (tlb->PLV0 << CSR_TLBLO0_PLV_SHIFT) | -+ (tlb->C0 << CSR_TLBLO0_CCA_SHIFT) | -+ (tlb->G << CSR_TLBLO0_GLOBAL_SHIFT) | -+ (tlb->PPN0 & 0xfffffffff000) | -+ ((uint64_t)tlb->RI0 << CSR_TLBLO0_RI_SHIFT) | -+ ((uint64_t)tlb->XI0 << CSR_TLBLO0_XI_SHIFT) | -+ ((uint64_t)tlb->RPLV0 << CSR_TLBLO0_RPLV_SHIFT); -+ env->CSR_TLBELO1 = (tlb->V1 << CSR_TLBLO1_V_SHIFT) | -+ (tlb->WE1 << CSR_TLBLO1_WE_SHIFT) | -+ (tlb->PLV1 << CSR_TLBLO1_PLV_SHIFT) | -+ (tlb->C1 << CSR_TLBLO1_CCA_SHIFT) | -+ (tlb->G << CSR_TLBLO0_GLOBAL_SHIFT) | -+ (tlb->PPN1 & 0xfffffffff000) | -+ ((uint64_t)tlb->RI1 << CSR_TLBLO1_RI_SHIFT) | -+ ((uint64_t)tlb->XI1 << CSR_TLBLO1_XI_SHIFT) | -+ ((uint64_t)tlb->RPLV1 << CSR_TLBLO1_RPLV_SHIFT); -+ env->CSR_ASID = (tlb->ASID << CSR_ASID_ASID_SHIFT) | -+ (env->CSR_ASID & 0xff0000); -+ } -+} -+ -+void helper_tlbwr(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbwr(env); -+} -+ -+void helper_tlbfill(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbfill(env); -+} -+ -+void helper_tlbsrch(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbsrch(env); -+} -+ -+void helper_tlbrd(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbrd(env); -+} -+ -+void helper_tlbclr(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbclr(env); -+} -+ -+void helper_tlbflush(CPULOONGARCHState *env) -+{ -+ env->tlb->helper_tlbflush(env); -+} -+ -+void helper_invtlb(CPULOONGARCHState *env, target_ulong addr, target_ulong info, -+ target_ulong op) -+{ -+ env->tlb->helper_invtlb(env, addr, info, op); -+} -+ -+static void ls3a5k_mmu_init(CPULOONGARCHState *env, const loongarch_def_t *def) -+{ -+ /* number of VTLB */ -+ env->tlb->nb_tlb = 64; -+ env->tlb->mmu.ls3a5k.vtlb_size = 64; -+ -+ /* number of FTLB */ -+ env->tlb->nb_tlb += 2048; -+ env->tlb->mmu.ls3a5k.ftlb_size = 2048; -+ env->tlb->mmu.ls3a5k.ftlb_mask = (1 << 15) - 1; /* 16 KB */ -+ /* -+ * page_size | ftlb_mask | party field -+ * ---------------------------------------------------------------- -+ * 4 KB = 12 | ( 1 << 13 ) - 1 = [12:0] | [12] -+ * 16 KB = 14 | ( 1 << 15 ) - 1 = [14:0] | [14] -+ * 64 KB = 16 | ( 1 << 17 ) - 1 = [16:0] | [16] -+ * 256 KB = 18 | ( 1 << 19 ) - 1 = [18:0] | [18] -+ * 1 MB = 20 | ( 1 << 21 ) - 1 = [20:0] | [20] -+ * 4 MB = 22 | ( 1 << 23 ) - 1 = [22:0] | [22] -+ * 16 MB = 24 | ( 1 << 25 ) - 1 = [24:0] | [24] -+ * 64 MB = 26 | ( 1 << 27 ) - 1 = [26:0] | [26] -+ * 256 MB = 28 | ( 1 << 29 ) - 1 = [28:0] | [28] -+ * 1 GB = 30 | ( 1 << 31 ) - 1 = [30:0] | [30] -+ * ---------------------------------------------------------------- -+ * take party field index as @n. eg. For 16 KB, n = 14 -+ * ---------------------------------------------------------------- -+ * tlb->VPN = TLBEHI & 0xffffffffe000[47:13] & ~mask = [47:n+1] -+ * tlb->PPN = TLBLO0 & 0xffffffffe000[47:13] & ~mask = [47:n+1] -+ * tlb->PPN = TLBLO1 & 0xffffffffe000[47:13] & ~mask = [47:n+1] -+ * ---------------------------------------------------------------- -+ * On mapping : -+ * > vpn = address & 0xffffffffe000[47:13] & ~mask = [47:n+1] -+ * > tag = tlb->VPN & ~mask = [47:n+1] -+ * ---------------------------------------------------------------- -+ * physical address = [47:n+1] | [n:0] -+ * physical address = tlb->PPN0 | (address & mask) -+ * physical address = tlb->PPN1 | (address & mask) -+ */ -+ -+ int i; -+ for (i = 0; i < env->tlb->nb_tlb; i++) { -+ env->tlb->mmu.ls3a5k.tlb[i].EHINV = 1; -+ } -+ -+ /* TLB's helper functions */ -+ env->tlb->map_address = &ls3a5k_map_address; -+ env->tlb->helper_tlbwr = ls3a5k_helper_tlbwr; -+ env->tlb->helper_tlbfill = ls3a5k_helper_tlbfill; -+ env->tlb->helper_tlbsrch = ls3a5k_helper_tlbsrch; -+ env->tlb->helper_tlbrd = ls3a5k_helper_tlbrd; -+ env->tlb->helper_tlbclr = ls3a5k_helper_tlbclr; -+ env->tlb->helper_tlbflush = ls3a5k_helper_tlbflush; -+ env->tlb->helper_invtlb = ls3a5k_helper_invtlb; -+} -+ -+void mmu_init(CPULOONGARCHState *env, const loongarch_def_t *def) -+{ -+ env->tlb = g_malloc0(sizeof(CPULOONGARCHTLBContext)); -+ -+ switch (def->mmu_type) { -+ case MMU_TYPE_LS3A5K: -+ ls3a5k_mmu_init(env, def); -+ break; -+ default: -+ cpu_abort(CPU(loongarch_env_get_cpu(env)), "MMU type not supported\n"); -+ } -+} -+#endif /* !CONFIG_USER_ONLY */ -diff --git a/target/loongarch64/trace-events b/target/loongarch64/trace-events -new file mode 100644 -index 000000000..e0bca4f82 ---- /dev/null -+++ b/target/loongarch64/trace-events -@@ -0,0 +1,3 @@ -+# See docs/devel/tracing.txt for syntax documentation. -+ -+# target/loongarch/translate.c -diff --git a/target/loongarch64/trans.inc.c b/target/loongarch64/trans.inc.c -new file mode 100644 -index 000000000..e50670be4 ---- /dev/null -+++ b/target/loongarch64/trans.inc.c -@@ -0,0 +1,3472 @@ -+static bool trans_syscall(DisasContext *ctx, arg_syscall *a) -+{ -+ generate_exception_end(ctx, EXCP_SYSCALL); -+ return true; -+} -+ -+static bool trans_break(DisasContext *ctx, arg_break *a) -+{ -+ generate_exception_end(ctx, EXCP_BREAK); -+ return true; -+} -+ -+static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) -+{ -+ /* -+ * dbcl instruction is not support in tcg -+ */ -+ generate_exception_end(ctx, EXCP_RI); -+ return true; -+} -+ -+static bool trans_addi_w(DisasContext *ctx, arg_addi_w *a) -+{ -+ gen_arith_imm(ctx, OPC_LARCH_ADDI_W, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_addi_d(DisasContext *ctx, arg_addi_d *a) -+{ -+ gen_arith_imm(ctx, OPC_LARCH_ADDI_D, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_slli_d(DisasContext *ctx, arg_slli_d *a) -+{ -+ if (a->rd == 0) { -+ /* Nop */ -+ return true; -+ } -+ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_shli_tl(cpu_gpr[a->rd], t0, a->ui6); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_andi(DisasContext *ctx, arg_andi *a) -+{ -+ gen_logic_imm(ctx, OPC_LARCH_ANDI, a->rd, a->rj, a->ui12); -+ return true; -+} -+ -+static bool trans_srli_d(DisasContext *ctx, arg_srli_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_shri_tl(cpu_gpr[a->rd], t0, a->ui6); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_slli_w(DisasContext *ctx, arg_slli_w *a) -+{ -+ if (a->rd == 0) { -+ /* Nop */ -+ return true; -+ } -+ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_shli_tl(t0, t0, a->ui5); -+ tcg_gen_ext32s_tl(cpu_gpr[a->rd], t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) -+{ -+ if (a->rj != 0) { -+ tcg_gen_addi_tl(cpu_gpr[a->rd], cpu_gpr[a->rj], a->si16 << 16); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->si16 << 16); -+ } -+ return true; -+} -+ -+static bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a) -+{ -+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->si20 << 12); -+ return true; -+} -+ -+static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) -+{ -+ TCGv_i64 t0, t1; -+ t0 = tcg_temp_new_i64(); -+ t1 = tcg_temp_new_i64(); -+ -+ tcg_gen_movi_tl(t0, a->si20); -+ tcg_gen_concat_tl_i64(t1, cpu_gpr[a->rd], t0); -+ gen_store_gpr(t1, a->rd); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_pcaddi(DisasContext *ctx, arg_pcaddi *a) -+{ -+ target_ulong pc = ctx->base.pc_next; -+ target_ulong addr = pc + (a->si20 << 2); -+ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); -+ return true; -+} -+ -+static bool trans_pcalau12i(DisasContext *ctx, arg_pcalau12i *a) -+{ -+ target_ulong pc = ctx->base.pc_next; -+ target_ulong addr = (pc + (a->si20 << 12)) & ~0xfff; -+ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); -+ return true; -+} -+ -+static bool trans_pcaddu12i(DisasContext *ctx, arg_pcaddu12i *a) -+{ -+ target_ulong pc = ctx->base.pc_next; -+ target_ulong addr = pc + (a->si20 << 12); -+ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); -+ return true; -+} -+ -+static bool trans_pcaddu18i(DisasContext *ctx, arg_pcaddu18i *a) -+{ -+ target_ulong pc = ctx->base.pc_next; -+ target_ulong addr = pc + ((target_ulong)(a->si20) << 18); -+ tcg_gen_movi_tl(cpu_gpr[a->rd], addr); -+ return true; -+} -+ -+static bool trans_slti(DisasContext *ctx, arg_slti *a) -+{ -+ gen_slt_imm(ctx, OPC_LARCH_SLTI, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_sltui(DisasContext *ctx, arg_sltui *a) -+{ -+ gen_slt_imm(ctx, OPC_LARCH_SLTIU, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ gen_load_gpr(t1, a->rj); -+ -+ tcg_gen_movi_tl(t0, a->si12); -+ tcg_gen_shli_tl(t0, t0, 52); -+ tcg_gen_andi_tl(t1, t1, 0xfffffffffffffU); -+ tcg_gen_or_tl(cpu_gpr[a->rd], t0, t1); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ori(DisasContext *ctx, arg_ori *a) -+{ -+ gen_logic_imm(ctx, OPC_LARCH_ORI, a->rd, a->rj, a->ui12); -+ return true; -+} -+ -+static bool trans_xori(DisasContext *ctx, arg_xori *a) -+{ -+ gen_logic_imm(ctx, OPC_LARCH_XORI, a->rd, a->rj, a->ui12); -+ return true; -+} -+ -+static bool trans_bstrins_d(DisasContext *ctx, arg_bstrins_d *a) -+{ -+ int lsb = a->lsbd; -+ int msb = a->msbd; -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ if (lsb > msb) { -+ return false; -+ } -+ -+ gen_load_gpr(t1, a->rj); -+ gen_load_gpr(t0, a->rd); -+ tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); -+ gen_store_gpr(t0, a->rd); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_bstrpick_d(DisasContext *ctx, arg_bstrpick_d *a) -+{ -+ int lsb = a->lsbd; -+ int msb = a->msbd; -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ if (lsb > msb) { -+ return false; -+ } -+ -+ gen_load_gpr(t1, a->rj); -+ gen_load_gpr(t0, a->rd); -+ tcg_gen_extract_tl(t0, t1, lsb, msb - lsb + 1); -+ gen_store_gpr(t0, a->rd); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_bstrins_w(DisasContext *ctx, arg_bstrins_w *a) -+{ -+ gen_bitops(ctx, OPC_LARCH_TRINS_W, a->rd, a->rj, a->lsbw, a->msbw); -+ return true; -+} -+ -+static bool trans_bstrpick_w(DisasContext *ctx, arg_bstrpick_w *a) -+{ -+ if (a->lsbw > a->msbw) { -+ return false; -+ } -+ gen_bitops(ctx, OPC_LARCH_TRPICK_W, -+ a->rd, a->rj, a->lsbw, a->msbw - a->lsbw); -+ return true; -+} -+ -+static bool trans_ldptr_w(DisasContext *ctx, arg_ldptr_w *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LDPTR_W, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_stptr_w(DisasContext *ctx, arg_stptr_w *a) -+{ -+ gen_st(ctx, OPC_LARCH_STPTR_W, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_ldptr_d(DisasContext *ctx, arg_ldptr_d *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LDPTR_D, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_stptr_d(DisasContext *ctx, arg_stptr_d *a) -+{ -+ gen_st(ctx, OPC_LARCH_STPTR_D, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_ld_b(DisasContext *ctx, arg_ld_b *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_B, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_h(DisasContext *ctx, arg_ld_h *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_H, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_w(DisasContext *ctx, arg_ld_w *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_W, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_d(DisasContext *ctx, arg_ld_d *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_D, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_st_b(DisasContext *ctx, arg_st_b *a) -+{ -+ gen_st(ctx, OPC_LARCH_ST_B, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_st_h(DisasContext *ctx, arg_st_h *a) -+{ -+ gen_st(ctx, OPC_LARCH_ST_H, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_st_w(DisasContext *ctx, arg_st_w *a) -+{ -+ gen_st(ctx, OPC_LARCH_ST_W, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_st_d(DisasContext *ctx, arg_st_d *a) -+{ -+ gen_st(ctx, OPC_LARCH_ST_D, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_bu(DisasContext *ctx, arg_ld_bu *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_BU, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_hu(DisasContext *ctx, arg_ld_hu *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_HU, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ld_wu(DisasContext *ctx, arg_ld_wu *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LD_WU, a->rd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_preld(DisasContext *ctx, arg_preld *a) -+{ -+ /* Treat as NOP. */ -+ return true; -+} -+ -+static bool trans_ll_w(DisasContext *ctx, arg_ll_w *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LL_W, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a) -+{ -+ gen_st_cond(ctx, a->rd, a->rj, a->si14 << 2, MO_TESL, false); -+ return true; -+} -+ -+static bool trans_ll_d(DisasContext *ctx, arg_ll_d *a) -+{ -+ gen_ld(ctx, OPC_LARCH_LL_D, a->rd, a->rj, a->si14 << 2); -+ return true; -+} -+ -+static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a) -+{ -+ gen_st_cond(ctx, a->rd, a->rj, a->si14 << 2, MO_TEQ, false); -+ return true; -+} -+ -+static bool trans_fld_s(DisasContext *ctx, arg_fld_s *a) -+{ -+ gen_fp_ldst(ctx, OPC_LARCH_FLD_S, a->fd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_fst_s(DisasContext *ctx, arg_fst_s *a) -+{ -+ gen_fp_ldst(ctx, OPC_LARCH_FST_S, a->fd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_fld_d(DisasContext *ctx, arg_fld_d *a) -+{ -+ gen_fp_ldst(ctx, OPC_LARCH_FLD_D, a->fd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_fst_d(DisasContext *ctx, arg_fst_d *a) -+{ -+ gen_fp_ldst(ctx, OPC_LARCH_FST_D, a->fd, a->rj, a->si12); -+ return true; -+} -+ -+static bool trans_ldx_b(DisasContext *ctx, arg_ldx_b *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_SB); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_h(DisasContext *ctx, arg_ldx_h *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TESW | ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_w(DisasContext *ctx, arg_ldx_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TESL | ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_ldx_d(DisasContext *ctx, arg_ldx_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEQ | ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_stx_b(DisasContext *ctx, arg_stx_b *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ gen_load_gpr(t1, a->rd); -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_8); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_stx_h(DisasContext *ctx, arg_stx_h *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ gen_load_gpr(t1, a->rd); -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUW | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_stx_w(DisasContext *ctx, arg_stx_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ gen_load_gpr(t1, a->rd); -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_stx_d(DisasContext *ctx, arg_stx_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ gen_load_gpr(t1, a->rd); -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_bu(DisasContext *ctx, arg_ldx_bu *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_hu(DisasContext *ctx, arg_ldx_hu *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEUW | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_ldx_wu(DisasContext *ctx, arg_ldx_wu *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); -+ tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t1, a->rd); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_fldx_s(DisasContext *ctx, arg_fldx_s *a) -+{ -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDX_S, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fldx_d(DisasContext *ctx, arg_fldx_d *a) -+{ -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDX_D, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstx_s(DisasContext *ctx, arg_fstx_s *a) -+{ -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTX_S, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstx_d(DisasContext *ctx, arg_fstx_d *a) -+{ -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTX_D, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+#define TRANS_AM_W(name, op) \ -+static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ -+{ \ -+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ -+ printf("%s: warning, register equal\n", __func__); \ -+ return false; \ -+ } \ -+ int mem_idx = ctx->mem_idx; \ -+ TCGv addr = tcg_temp_new(); \ -+ TCGv val = tcg_temp_new(); \ -+ TCGv ret = tcg_temp_new(); \ -+\ -+ gen_load_gpr(addr, a->rj); \ -+ gen_load_gpr(val, a->rk); \ -+ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TESL | \ -+ ctx->default_tcg_memop_mask); \ -+ gen_store_gpr(ret, a->rd); \ -+\ -+ tcg_temp_free(addr); \ -+ tcg_temp_free(val); \ -+ tcg_temp_free(ret); \ -+ return true; \ -+} -+#define TRANS_AM_D(name, op) \ -+static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ -+{ \ -+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ -+ printf("%s: warning, register equal\n", __func__); \ -+ return false; \ -+ } \ -+ int mem_idx = ctx->mem_idx; \ -+ TCGv addr = tcg_temp_new(); \ -+ TCGv val = tcg_temp_new(); \ -+ TCGv ret = tcg_temp_new(); \ -+\ -+ gen_load_gpr(addr, a->rj); \ -+ gen_load_gpr(val, a->rk); \ -+ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TEQ | \ -+ ctx->default_tcg_memop_mask); \ -+ gen_store_gpr(ret, a->rd); \ -+\ -+ tcg_temp_free(addr); \ -+ tcg_temp_free(val); \ -+ tcg_temp_free(ret); \ -+ return true; \ -+} -+#define TRANS_AM(name, op) \ -+ TRANS_AM_W(name##_w, op) \ -+ TRANS_AM_D(name##_d, op) -+TRANS_AM(amswap, xchg) /* trans_amswap_w, trans_amswap_d */ -+TRANS_AM(amadd, fetch_add) /* trans_amadd_w, trans_amadd_d */ -+TRANS_AM(amand, fetch_and) /* trans_amand_w, trans_amand_d */ -+TRANS_AM(amor, fetch_or) /* trans_amor_w, trans_amor_d */ -+TRANS_AM(amxor, fetch_xor) /* trans_amxor_w, trans_amxor_d */ -+TRANS_AM(ammax, fetch_smax) /* trans_ammax_w, trans_ammax_d */ -+TRANS_AM(ammin, fetch_smin) /* trans_ammin_w, trans_ammin_d */ -+TRANS_AM_W(ammax_wu, fetch_umax) /* trans_ammax_wu */ -+TRANS_AM_D(ammax_du, fetch_umax) /* trans_ammax_du */ -+TRANS_AM_W(ammin_wu, fetch_umin) /* trans_ammin_wu */ -+TRANS_AM_D(ammin_du, fetch_umin) /* trans_ammin_du */ -+#undef TRANS_AM -+#undef TRANS_AM_W -+#undef TRANS_AM_D -+ -+#define TRANS_AM_DB_W(name, op) \ -+static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ -+{ \ -+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ -+ printf("%s: warning, register equal\n", __func__); \ -+ return false; \ -+ } \ -+ int mem_idx = ctx->mem_idx; \ -+ TCGv addr = tcg_temp_new(); \ -+ TCGv val = tcg_temp_new(); \ -+ TCGv ret = tcg_temp_new(); \ -+\ -+ gen_sync(0x10); /* TCG_MO_ALL */ \ -+ gen_load_gpr(addr, a->rj); \ -+ gen_load_gpr(val, a->rk); \ -+ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TESL | \ -+ ctx->default_tcg_memop_mask); \ -+ gen_store_gpr(ret, a->rd); \ -+\ -+ tcg_temp_free(addr); \ -+ tcg_temp_free(val); \ -+ tcg_temp_free(ret); \ -+ return true; \ -+} -+#define TRANS_AM_DB_D(name, op) \ -+static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ -+{ \ -+ if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ -+ printf("%s: warning, register equal\n", __func__); \ -+ return false; \ -+ } \ -+ int mem_idx = ctx->mem_idx; \ -+ TCGv addr = tcg_temp_new(); \ -+ TCGv val = tcg_temp_new(); \ -+ TCGv ret = tcg_temp_new(); \ -+\ -+ gen_sync(0x10); /* TCG_MO_ALL */ \ -+ gen_load_gpr(addr, a->rj); \ -+ gen_load_gpr(val, a->rk); \ -+ tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TEQ | \ -+ ctx->default_tcg_memop_mask); \ -+ gen_store_gpr(ret, a->rd); \ -+\ -+ tcg_temp_free(addr); \ -+ tcg_temp_free(val); \ -+ tcg_temp_free(ret); \ -+ return true; \ -+} -+#define TRANS_AM_DB(name, op) \ -+ TRANS_AM_DB_W(name##_db_w, op) \ -+ TRANS_AM_DB_D(name##_db_d, op) -+TRANS_AM_DB(amswap, xchg) /* trans_amswap_db_w, trans_amswap_db_d */ -+TRANS_AM_DB(amadd, fetch_add) /* trans_amadd_db_w, trans_amadd_db_d */ -+TRANS_AM_DB(amand, fetch_and) /* trans_amand_db_w, trans_amand_db_d */ -+TRANS_AM_DB(amor, fetch_or) /* trans_amor_db_w, trans_amor_db_d */ -+TRANS_AM_DB(amxor, fetch_xor) /* trans_amxor_db_w, trans_amxor_db_d */ -+TRANS_AM_DB(ammax, fetch_smax) /* trans_ammax_db_w, trans_ammax_db_d */ -+TRANS_AM_DB(ammin, fetch_smin) /* trans_ammin_db_w, trans_ammin_db_d */ -+TRANS_AM_DB_W(ammax_db_wu, fetch_umax) /* trans_ammax_db_wu */ -+TRANS_AM_DB_D(ammax_db_du, fetch_umax) /* trans_ammax_db_du */ -+TRANS_AM_DB_W(ammin_db_wu, fetch_umin) /* trans_ammin_db_wu */ -+TRANS_AM_DB_D(ammin_db_du, fetch_umin) /* trans_ammin_db_du */ -+#undef TRANS_AM_DB -+#undef TRANS_AM_DB_W -+#undef TRANS_AM_DB_D -+ -+static bool trans_dbar(DisasContext *ctx, arg_dbar * a) -+{ -+ gen_sync(a->whint); -+ return true; -+} -+ -+static bool trans_ibar(DisasContext *ctx, arg_ibar *a) -+{ -+ /* -+ * FENCE_I is a no-op in QEMU, -+ * however we need to end the translation block -+ */ -+ ctx->base.is_jmp = DISAS_STOP; -+ return true; -+} -+ -+#define ASRTGT \ -+do { \ -+ TCGv t1 = tcg_temp_new(); \ -+ TCGv t2 = tcg_temp_new(); \ -+ gen_load_gpr(t1, a->rj); \ -+ gen_load_gpr(t2, a->rk); \ -+ gen_helper_asrtgt_d(cpu_env, t1, t2); \ -+ tcg_temp_free(t1); \ -+ tcg_temp_free(t2); \ -+} while (0) -+ -+#define ASRTLE \ -+do {\ -+ TCGv t1 = tcg_temp_new(); \ -+ TCGv t2 = tcg_temp_new(); \ -+ gen_load_gpr(t1, a->rj); \ -+ gen_load_gpr(t2, a->rk); \ -+ gen_helper_asrtle_d(cpu_env, t1, t2); \ -+ tcg_temp_free(t1); \ -+ tcg_temp_free(t2); \ -+} while (0) -+ -+static bool trans_fldgt_s(DisasContext *ctx, arg_fldgt_s *a) -+{ -+ ASRTGT; -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDGT_S, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fldgt_d(DisasContext *ctx, arg_fldgt_d *a) -+{ -+ ASRTGT; -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDGT_D, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fldle_s(DisasContext *ctx, arg_fldle_s *a) -+{ -+ ASRTLE; -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDLE_S, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fldle_d(DisasContext *ctx, arg_fldle_d *a) -+{ -+ ASRTLE; -+ gen_flt3_ldst(ctx, OPC_LARCH_FLDLE_D, a->fd, 0, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstgt_s(DisasContext *ctx, arg_fstgt_s *a) -+{ -+ ASRTGT; -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTGT_S, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstgt_d(DisasContext *ctx, arg_fstgt_d *a) -+{ -+ ASRTGT; -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTGT_D, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstle_s(DisasContext *ctx, arg_fstle_s *a) -+{ -+ ASRTLE; -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTLE_S, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_fstle_d(DisasContext *ctx, arg_fstle_d *a) -+{ -+ ASRTLE; -+ gen_flt3_ldst(ctx, OPC_LARCH_FSTLE_D, 0, a->fd, a->rj, a->rk); -+ return true; -+} -+ -+#define DECL_ARG(name) \ -+ arg_ ## name arg = { \ -+ .rd = a->rd, \ -+ .rj = a->rj, \ -+ .rk = a->rk, \ -+ }; -+ -+static bool trans_ldgt_b(DisasContext *ctx, arg_ldgt_b *a) -+{ -+ ASRTGT; -+ DECL_ARG(ldx_b) -+ trans_ldx_b(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldgt_h(DisasContext *ctx, arg_ldgt_h *a) -+{ -+ ASRTGT; -+ DECL_ARG(ldx_h) -+ trans_ldx_h(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldgt_w(DisasContext *ctx, arg_ldgt_w *a) -+{ -+ ASRTGT; -+ DECL_ARG(ldx_w) -+ trans_ldx_w(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldgt_d(DisasContext *ctx, arg_ldgt_d *a) -+{ -+ ASRTGT; -+ DECL_ARG(ldx_d) -+ trans_ldx_d(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldle_b(DisasContext *ctx, arg_ldle_b *a) -+{ -+ ASRTLE; -+ DECL_ARG(ldx_b) -+ trans_ldx_b(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldle_h(DisasContext *ctx, arg_ldle_h *a) -+{ -+ ASRTLE; -+ DECL_ARG(ldx_h) -+ trans_ldx_h(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldle_w(DisasContext *ctx, arg_ldle_w *a) -+{ -+ ASRTLE; -+ DECL_ARG(ldx_w) -+ trans_ldx_w(ctx, &arg); -+ return true; -+} -+ -+static bool trans_ldle_d(DisasContext *ctx, arg_ldle_d *a) -+{ -+ ASRTLE; -+ DECL_ARG(ldx_d) -+ trans_ldx_d(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stgt_b(DisasContext *ctx, arg_stgt_b *a) -+{ -+ ASRTGT; -+ DECL_ARG(stx_b) -+ trans_stx_b(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stgt_h(DisasContext *ctx, arg_stgt_h *a) -+{ -+ ASRTGT; -+ DECL_ARG(stx_h) -+ trans_stx_h(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stgt_w(DisasContext *ctx, arg_stgt_w *a) -+{ -+ ASRTGT; -+ DECL_ARG(stx_w) -+ trans_stx_w(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stgt_d(DisasContext *ctx, arg_stgt_d *a) -+{ -+ ASRTGT; -+ DECL_ARG(stx_d) -+ trans_stx_d(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stle_b(DisasContext *ctx, arg_stle_b *a) -+{ -+ ASRTLE; -+ DECL_ARG(stx_b) -+ trans_stx_b(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stle_h(DisasContext *ctx, arg_stle_h *a) -+{ -+ ASRTLE; -+ DECL_ARG(stx_h) -+ trans_stx_h(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stle_w(DisasContext *ctx, arg_stle_w *a) -+{ -+ ASRTLE; -+ DECL_ARG(stx_w) -+ trans_stx_w(ctx, &arg); -+ return true; -+} -+ -+static bool trans_stle_d(DisasContext *ctx, arg_stle_d *a) -+{ -+ ASRTLE; -+ DECL_ARG(stx_d) -+ trans_stx_d(ctx, &arg); -+ return true; -+} -+ -+#undef ASRTGT -+#undef ASRTLE -+#undef DECL_ARG -+ -+static bool trans_beqz(DisasContext *ctx, arg_beqz *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BEQZ, 4, a->rj, 0, a->offs21 << 2); -+ return true; -+} -+ -+static bool trans_bnez(DisasContext *ctx, arg_bnez *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BNEZ, 4, a->rj, 0, a->offs21 << 2); -+ return true; -+} -+ -+static bool trans_bceqz(DisasContext *ctx, arg_bceqz *a) -+{ -+ TCGv_i32 cj = tcg_const_i32(a->cj); -+ TCGv v0 = tcg_temp_new(); -+ TCGv v1 = tcg_const_i64(0); -+ -+ gen_helper_movcf2reg(v0, cpu_env, cj); -+ tcg_gen_setcond_tl(TCG_COND_EQ, bcond, v0, v1); -+ ctx->hflags |= LARCH_HFLAG_BC; -+ ctx->btarget = ctx->base.pc_next + (a->offs21 << 2); -+ -+ tcg_temp_free_i32(cj); -+ tcg_temp_free(v0); -+ tcg_temp_free(v1); -+ return true; -+} -+ -+static bool trans_bcnez(DisasContext *ctx, arg_bcnez *a) -+{ -+ TCGv_i32 cj = tcg_const_i32(a->cj); -+ TCGv v0 = tcg_temp_new(); -+ TCGv v1 = tcg_const_i64(0); -+ -+ gen_helper_movcf2reg(v0, cpu_env, cj); -+ tcg_gen_setcond_tl(TCG_COND_NE, bcond, v0, v1); -+ ctx->hflags |= LARCH_HFLAG_BC; -+ ctx->btarget = ctx->base.pc_next + (a->offs21 << 2); -+ -+ tcg_temp_free_i32(cj); -+ tcg_temp_free(v0); -+ tcg_temp_free(v1); -+ return true; -+} -+ -+static bool trans_b(DisasContext *ctx, arg_b *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_B, 4, 0, 0, a->offs << 2); -+ return true; -+} -+ -+static bool trans_bl(DisasContext *ctx, arg_bl *a) -+{ -+ ctx->btarget = ctx->base.pc_next + (a->offs << 2); -+ tcg_gen_movi_tl(cpu_gpr[1], ctx->base.pc_next + 4); -+ ctx->hflags |= LARCH_HFLAG_B; -+ gen_branch(ctx, 4); -+ return true; -+} -+ -+static bool trans_blt(DisasContext *ctx, arg_blt *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BLT, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_bge(DisasContext *ctx, arg_bge *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BGE, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_bltu(DisasContext *ctx, arg_bltu *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BLTU, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BGEU, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_beq(DisasContext *ctx, arg_beq *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BEQ, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_bne(DisasContext *ctx, arg_bne *a) -+{ -+ gen_compute_branch(ctx, OPC_LARCH_BNE, 4, a->rj, a->rd, a->offs16 << 2); -+ return true; -+} -+ -+static bool trans_jirl(DisasContext *ctx, arg_jirl *a) -+{ -+ gen_base_offset_addr(ctx, btarget, a->rj, a->offs16 << 2); -+ if (a->rd != 0) { -+ tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->base.pc_next + 4); -+ } -+ ctx->hflags |= LARCH_HFLAG_BR; -+ gen_branch(ctx, 4); -+ -+ return true; -+} -+ -+#define TRANS_F4FR(name, fmt, op, bits) \ -+static bool trans_ ## name ## _ ## fmt(DisasContext *ctx, \ -+ arg_##name##_##fmt * a) \ -+{ \ -+ check_cp1_enabled(ctx); \ -+ TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \ -+ TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \ -+ TCGv_i ## bits fp2 = tcg_temp_new_i ## bits(); \ -+ TCGv_i ## bits fp3 = tcg_temp_new_i ## bits(); \ -+ check_cp1_enabled(ctx); \ -+ gen_load_fpr ## bits(ctx, fp0, a->fj); \ -+ gen_load_fpr ## bits(ctx, fp1, a->fk); \ -+ gen_load_fpr ## bits(ctx, fp2, a->fa); \ -+ gen_helper_float_ ## op ## _ ## fmt(fp3, \ -+ cpu_env, fp0, fp1, fp2); \ -+ gen_store_fpr ## bits(ctx, fp3, a->fd); \ -+ tcg_temp_free_i ## bits(fp3); \ -+ tcg_temp_free_i ## bits(fp2); \ -+ tcg_temp_free_i ## bits(fp1); \ -+ tcg_temp_free_i ## bits(fp0); \ -+ return true; \ -+} -+ -+TRANS_F4FR(fmadd , s, maddf , 32) /* trans_fmadd_s */ -+TRANS_F4FR(fmadd , d, maddf , 64) /* trans_fmadd_d */ -+TRANS_F4FR(fmsub , s, msubf , 32) /* trans_fmsub_s */ -+TRANS_F4FR(fmsub , d, msubf , 64) /* trans_fmsub_d */ -+TRANS_F4FR(fnmadd, s, nmaddf, 32) /* trans_fnmadd_s */ -+TRANS_F4FR(fnmadd, d, nmaddf, 64) /* trans_fnmadd_d */ -+TRANS_F4FR(fnmsub, s, nmsubf, 32) /* trans_fnmsub_s */ -+TRANS_F4FR(fnmsub, d, nmsubf, 64) /* trans_fnmsub_d */ -+#undef TRANS_F4FR -+ -+static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s * a) -+{ -+ gen_farith(ctx, OPC_LARCH_FADD_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FADD_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FSUB_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FSUB_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMUL_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMUL_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FDIV_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FDIV_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMAX_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMAX_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMIN_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMIN_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmaxa_s(DisasContext *ctx, arg_fmaxa_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMAXA_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmaxa_d(DisasContext *ctx, arg_fmaxa_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMAXA_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmina_s(DisasContext *ctx, arg_fmina_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMINA_S, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmina_d(DisasContext *ctx, arg_fmina_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMINA_D, a->fk, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fscaleb_s(DisasContext *ctx, arg_fscaleb_s *a) -+{ -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr32(ctx, fp0, a->fj); -+ gen_load_fpr32(ctx, fp1, a->fk); -+ gen_helper_float_exp2_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, a->fd); -+ tcg_temp_free_i32(fp0); -+ return true; -+} -+ -+static bool trans_fscaleb_d(DisasContext *ctx, arg_fscaleb_d *a) -+{ -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fp0, a->fj); -+ gen_load_fpr64(ctx, fp1, a->fk); -+ gen_helper_float_exp2_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, a->fd); -+ tcg_temp_free_i64(fp0); -+ return true; -+} -+ -+static bool trans_fcopysign_s(DisasContext *ctx, arg_fcopysign_s *a) -+{ -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ TCGv_i32 fp2 = tcg_temp_new_i32(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr32(ctx, fp0, a->fj); -+ gen_load_fpr32(ctx, fp1, a->fk); -+ tcg_gen_deposit_i32(fp2, fp1, fp0, 0, 31); -+ gen_store_fpr32(ctx, fp2, a->fd); -+ -+ tcg_temp_free_i32(fp2); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ return true; -+} -+ -+static bool trans_fcopysign_d(DisasContext *ctx, arg_fcopysign_d *a) -+{ -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ TCGv_i64 fp2 = tcg_temp_new_i64(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fp0, a->fj); -+ gen_load_fpr64(ctx, fp1, a->fk); -+ tcg_gen_deposit_i64(fp2, fp1, fp0, 0, 63); -+ gen_store_fpr64(ctx, fp2, a->fd); -+ -+ tcg_temp_free_i64(fp2); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ return true; -+} -+ -+static bool trans_fabs_s(DisasContext *ctx, arg_fabs_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FABS_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fabs_d(DisasContext *ctx, arg_fabs_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FABS_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fneg_s(DisasContext *ctx, arg_fneg_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FNEG_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FNEG_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_flogb_s(DisasContext *ctx, arg_flogb_s *a) -+{ -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr32(ctx, fp0, a->fj); -+ gen_helper_float_logb_s(fp1, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp1, a->fd); -+ -+ tcg_temp_free_i32(fp0); -+ tcg_temp_free_i32(fp1); -+ return true; -+} -+ -+static bool trans_flogb_d(DisasContext *ctx, arg_flogb_d *a) -+{ -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fp0, a->fj); -+ gen_helper_float_logb_d(fp1, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp1, a->fd); -+ -+ tcg_temp_free_i64(fp0); -+ tcg_temp_free_i64(fp1); -+ return true; -+} -+ -+static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FCLASS_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FCLASS_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FSQRT_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FSQRT_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frecip_s(DisasContext *ctx, arg_frecip_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRECIP_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frecip_d(DisasContext *ctx, arg_frecip_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRECIP_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frsqrt_s(DisasContext *ctx, arg_frsqrt_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRSQRT_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frsqrt_d(DisasContext *ctx, arg_frsqrt_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRSQRT_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmov_s(DisasContext *ctx, arg_fmov_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMOV_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fmov_d(DisasContext *ctx, arg_fmov_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FMOV_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_movgr2fr_w(DisasContext *ctx, arg_movgr2fr_w *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_GR2FR_W, a->rj, a->fd); -+ return true; -+} -+ -+static bool trans_movgr2fr_d(DisasContext *ctx, arg_movgr2fr_d *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_GR2FR_D, a->rj, a->fd); -+ return true; -+} -+ -+static bool trans_movgr2frh_w(DisasContext *ctx, arg_movgr2frh_w *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_GR2FRH_W, a->rj, a->fd); -+ return true; -+} -+ -+static bool trans_movfr2gr_s(DisasContext *ctx, arg_movfr2gr_s *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_FR2GR_S, a->rd, a->fj); -+ return true; -+} -+ -+static bool trans_movfr2gr_d(DisasContext *ctx, arg_movfr2gr_d *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_FR2GR_D, a->rd, a->fj); -+ return true; -+} -+ -+static bool trans_movfrh2gr_s(DisasContext *ctx, arg_movfrh2gr_s *a) -+{ -+ gen_cp1(ctx, OPC_LARCH_FRH2GR_S, a->rd, a->fj); -+ return true; -+} -+ -+static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ check_cp1_enabled(ctx); -+ gen_load_gpr(t0, a->rj); -+ save_cpu_state(ctx, 0); -+ { -+ TCGv_i32 fs_tmp = tcg_const_i32(a->fcsrd); -+ gen_helper_0e2i(movgr2fcsr, t0, fs_tmp, a->rj); -+ tcg_temp_free_i32(fs_tmp); -+ } -+ /* Stop translation as we may have changed hflags */ -+ ctx->base.is_jmp = DISAS_STOP; -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_helper_1e0i(movfcsr2gr, t0, a->fcsrs); -+ gen_store_gpr(t0, a->rd); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) -+{ -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i32 cd = tcg_const_i32(a->cd); -+ -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fp0, a->fj); -+ gen_helper_movreg2cf(cpu_env, cd, fp0); -+ -+ tcg_temp_free_i64(fp0); -+ tcg_temp_free_i32(cd); -+ return true; -+} -+ -+static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv_i32 cj = tcg_const_i32(a->cj); -+ -+ check_cp1_enabled(ctx); -+ gen_helper_movcf2reg(t0, cpu_env, cj); -+ gen_store_fpr64(ctx, t0, a->fd); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv_i32 cd = tcg_const_i32(a->cd); -+ -+ check_cp1_enabled(ctx); -+ gen_load_gpr(t0, a->rj); -+ gen_helper_movreg2cf(cpu_env, cd, t0); -+ -+ tcg_temp_free(t0); -+ tcg_temp_free_i32(cd); -+ return true; -+} -+ -+static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) -+{ -+ TCGv_i32 cj = tcg_const_i32(a->cj); -+ -+ check_cp1_enabled(ctx); -+ gen_helper_movcf2reg(cpu_gpr[a->rd], cpu_env, cj); -+ -+ tcg_temp_free_i32(cj); -+ return true; -+} -+ -+static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FCVT_S_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FCVT_D_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrm_w_s(DisasContext *ctx, arg_ftintrm_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRM_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrm_w_d(DisasContext *ctx, arg_ftintrm_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRM_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrm_l_s(DisasContext *ctx, arg_ftintrm_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRM_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrm_l_d(DisasContext *ctx, arg_ftintrm_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRM_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrp_w_s(DisasContext *ctx, arg_ftintrp_w_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRP_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrp_w_d(DisasContext *ctx, arg_ftintrp_w_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRP_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrp_l_s(DisasContext *ctx, arg_ftintrp_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRP_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrp_l_d(DisasContext *ctx, arg_ftintrp_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRP_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrz_w_s(DisasContext *ctx, arg_ftintrz_w_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRZ_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrz_w_d(DisasContext *ctx, arg_ftintrz_w_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRZ_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrz_l_s(DisasContext *ctx, arg_ftintrz_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRZ_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrz_l_d(DisasContext *ctx, arg_ftintrz_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRZ_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrne_w_s(DisasContext *ctx, arg_ftintrne_w_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRNE_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrne_w_d(DisasContext *ctx, arg_ftintrne_w_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRNE_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrne_l_s(DisasContext *ctx, arg_ftintrne_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRNE_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftintrne_l_d(DisasContext *ctx, arg_ftintrne_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINTRNE_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftint_w_s(DisasContext *ctx, arg_ftint_w_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINT_W_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftint_w_d(DisasContext *ctx, arg_ftint_w_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINT_W_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftint_l_s(DisasContext *ctx, arg_ftint_l_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINT_L_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ftint_l_d(DisasContext *ctx, arg_ftint_l_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FTINT_L_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ffint_s_w(DisasContext *ctx, arg_ffint_s_w *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FFINT_S_W, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ffint_s_l(DisasContext *ctx, arg_ffint_s_l *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FFINT_S_L, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ffint_d_w(DisasContext *ctx, arg_ffint_d_w *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FFINT_D_W, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_ffint_d_l(DisasContext *ctx, arg_ffint_d_l *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FFINT_D_L, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frint_s(DisasContext *ctx, arg_frint_s *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRINT_S, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_frint_d(DisasContext *ctx, arg_frint_d *a) -+{ -+ gen_farith(ctx, OPC_LARCH_FRINT_D, 0, a->fj, a->fd, 0); -+ return true; -+} -+ -+static bool trans_alsl_w(DisasContext *ctx, arg_alsl_w *a) -+{ -+ gen_lsa(ctx, OPC_LARCH_ALSL_W, a->rd, a->rj, a->rk, a->sa2); -+ return true; -+} -+ -+static bool trans_alsl_wu(DisasContext *ctx, arg_alsl_wu *a) -+{ -+ TCGv t0, t1; -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ gen_load_gpr(t1, a->rk); -+ tcg_gen_shli_tl(t0, t0, a->sa2 + 1); -+ tcg_gen_add_tl(t0, t0, t1); -+ tcg_gen_ext32u_tl(cpu_gpr[a->rd], t0); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ -+ return true; -+} -+ -+static bool trans_alsl_d(DisasContext *ctx, arg_alsl_d *a) -+{ -+ check_larch_64(ctx); -+ gen_lsa(ctx, OPC_LARCH_ALSL_D, a->rd, a->rj, a->rk, a->sa2); -+ return true; -+} -+ -+static bool trans_bytepick_w(DisasContext *ctx, arg_bytepick_w *a) -+{ -+ gen_align(ctx, 32, a->rd, a->rj, a->rk, a->sa2); -+ return true; -+} -+ -+static bool trans_bytepick_d(DisasContext *ctx, arg_bytepick_d *a) -+{ -+ check_larch_64(ctx); -+ gen_align(ctx, 64, a->rd, a->rj, a->rk, a->sa3); -+ return true; -+} -+ -+static bool trans_add_w(DisasContext *ctx, arg_add_w *a) -+{ -+ gen_arith(ctx, OPC_LARCH_ADD_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_sub_w(DisasContext *ctx, arg_sub_w *a) -+{ -+ gen_arith(ctx, OPC_LARCH_SUB_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_add_d(DisasContext *ctx, arg_add_d *a) -+{ -+ gen_arith(ctx, OPC_LARCH_ADD_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_sub_d(DisasContext *ctx, arg_sub_d *a) -+{ -+ check_larch_64(ctx); -+ gen_arith(ctx, OPC_LARCH_SUB_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_slt(DisasContext *ctx, arg_slt *a) -+{ -+ gen_slt(ctx, OPC_LARCH_SLT, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_sltu(DisasContext *ctx, arg_sltu *a) -+{ -+ gen_slt(ctx, OPC_LARCH_SLTU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_maskeqz(DisasContext *ctx, arg_maskeqz *a) -+{ -+ gen_cond_move(ctx, OPC_LARCH_MASKEQZ, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_masknez(DisasContext *ctx, arg_masknez *a) -+{ -+ gen_cond_move(ctx, OPC_LARCH_MASKNEZ, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_nor(DisasContext *ctx, arg_nor *a) -+{ -+ gen_logic(ctx, OPC_LARCH_NOR, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_and(DisasContext *ctx, arg_and *a) -+{ -+ gen_logic(ctx, OPC_LARCH_AND, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_or(DisasContext *ctx, arg_or *a) -+{ -+ gen_logic(ctx, OPC_LARCH_OR, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_xor(DisasContext *ctx, arg_xor *a) -+{ -+ gen_logic(ctx, OPC_LARCH_XOR, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_orn(DisasContext *ctx, arg_orn *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rk); -+ tcg_gen_not_tl(t0, t0); -+ tcg_gen_or_tl(cpu_gpr[a->rd], cpu_gpr[a->rj], t0); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_andn(DisasContext *ctx, arg_andn *a) -+{ -+ TCGv t0, t1; -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rk); -+ gen_load_gpr(t1, a->rj); -+ tcg_gen_not_tl(t0, t0); -+ tcg_gen_and_tl(cpu_gpr[a->rd], t1, t0); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+static bool trans_sll_w(DisasContext *ctx, arg_sll_w *a) -+{ -+ gen_shift(ctx, OPC_LARCH_SLL_W, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_srl_w(DisasContext *ctx, arg_srl_w *a) -+{ -+ gen_shift(ctx, OPC_LARCH_SRL_W, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_sra_w(DisasContext *ctx, arg_sra_w *a) -+{ -+ gen_shift(ctx, OPC_LARCH_SRA_W, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_sll_d(DisasContext *ctx, arg_sll_d *a) -+{ -+ check_larch_64(ctx); -+ gen_shift(ctx, OPC_LARCH_SLL_D, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_srl_d(DisasContext *ctx, arg_srl_d *a) -+{ -+ check_larch_64(ctx); -+ gen_shift(ctx, OPC_LARCH_SRL_D, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_sra_d(DisasContext *ctx, arg_sra_d *a) -+{ -+ check_larch_64(ctx); -+ gen_shift(ctx, OPC_LARCH_SRA_D, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_rotr_w(DisasContext *ctx, arg_rotr_w *a) -+{ -+ gen_shift(ctx, OPC_LARCH_ROTR_W, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_rotr_d(DisasContext *ctx, arg_rotr_d *a) -+{ -+ check_larch_64(ctx); -+ gen_shift(ctx, OPC_LARCH_ROTR_D, a->rd, a->rk, a->rj); -+ return true; -+} -+ -+static bool trans_crc_w_b_w(DisasContext *ctx, arg_crc_w_b_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 1, 0); -+ return true; -+} -+ -+static bool trans_crc_w_h_w(DisasContext *ctx, arg_crc_w_h_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 2, 0); -+ return true; -+} -+ -+static bool trans_crc_w_w_w(DisasContext *ctx, arg_crc_w_w_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 4, 0); -+ return true; -+} -+ -+static bool trans_crc_w_d_w(DisasContext *ctx, arg_crc_w_d_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 8, 0); -+ return true; -+} -+ -+static bool trans_crcc_w_b_w(DisasContext *ctx, arg_crcc_w_b_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 1, 1); -+ return true; -+} -+ -+static bool trans_crcc_w_h_w(DisasContext *ctx, arg_crcc_w_h_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 2, 1); -+ return true; -+} -+ -+static bool trans_crcc_w_w_w(DisasContext *ctx, arg_crcc_w_w_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 4, 1); -+ return true; -+} -+ -+static bool trans_crcc_w_d_w(DisasContext *ctx, arg_crcc_w_d_w *a) -+{ -+ gen_crc32(ctx, a->rd, a->rj, a->rk, 8, 1); -+ return true; -+} -+ -+static bool trans_mul_w(DisasContext *ctx, arg_mul_w *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MUL_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulh_w(DisasContext *ctx, arg_mulh_w *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MULH_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulh_wu(DisasContext *ctx, arg_mulh_wu *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MULH_WU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mul_d(DisasContext *ctx, arg_mul_d *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MUL_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulh_d(DisasContext *ctx, arg_mulh_d *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MULH_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulh_du(DisasContext *ctx, arg_mulh_du *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MULH_DU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mulw_d_w(DisasContext *ctx, arg_mulw_d_w *a) -+{ -+ TCGv_i64 t0 = tcg_temp_new_i64(); -+ TCGv_i64 t1 = tcg_temp_new_i64(); -+ TCGv_i64 t2 = tcg_temp_new_i64(); -+ gen_load_gpr(t0, a->rj); -+ gen_load_gpr(t1, a->rk); -+ tcg_gen_ext32s_i64(t0, t0); -+ tcg_gen_ext32s_i64(t1, t1); -+ tcg_gen_mul_i64(t2, t0, t1); -+ gen_store_gpr(t2, a->rd); -+ tcg_temp_free_i64(t0); -+ tcg_temp_free_i64(t1); -+ tcg_temp_free_i64(t2); -+ return true; -+} -+ -+static bool trans_mulw_d_wu(DisasContext *ctx, arg_mulw_d_wu *a) -+{ -+ TCGv_i64 t0 = tcg_temp_new_i64(); -+ TCGv_i64 t1 = tcg_temp_new_i64(); -+ TCGv_i64 t2 = tcg_temp_new_i64(); -+ gen_load_gpr(t0, a->rj); -+ gen_load_gpr(t1, a->rk); -+ tcg_gen_ext32u_i64(t0, t0); -+ tcg_gen_ext32u_i64(t1, t1); -+ tcg_gen_mul_i64(t2, t0, t1); -+ gen_store_gpr(t2, a->rd); -+ tcg_temp_free_i64(t0); -+ tcg_temp_free_i64(t1); -+ tcg_temp_free_i64(t2); -+ return true; -+} -+ -+static bool trans_div_w(DisasContext *ctx, arg_div_w *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_DIV_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mod_w(DisasContext *ctx, arg_mod_w *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MOD_W, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_div_wu(DisasContext *ctx, arg_div_wu *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_DIV_WU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mod_wu(DisasContext *ctx, arg_mod_wu *a) -+{ -+ gen_r6_muldiv(ctx, OPC_LARCH_MOD_WU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_div_d(DisasContext *ctx, arg_div_d *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_DIV_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mod_d(DisasContext *ctx, arg_mod_d *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MOD_D, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_div_du(DisasContext *ctx, arg_div_du *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_DIV_DU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+static bool trans_mod_du(DisasContext *ctx, arg_mod_du *a) -+{ -+ check_larch_64(ctx); -+ gen_r6_muldiv(ctx, OPC_LARCH_MOD_DU, a->rd, a->rj, a->rk); -+ return true; -+} -+ -+/* do not update CP0.BadVaddr */ -+static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a) -+{ -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_temp_new(); -+ gen_load_gpr(t1, a->rj); -+ gen_load_gpr(t2, a->rk); -+ gen_helper_asrtle_d(cpu_env, t1, t2); -+ tcg_temp_free(t1); -+ tcg_temp_free(t2); -+ return true; -+} -+ -+/* do not update CP0.BadVaddr */ -+static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) -+{ -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_temp_new(); -+ gen_load_gpr(t1, a->rj); -+ gen_load_gpr(t2, a->rk); -+ gen_helper_asrtgt_d(cpu_env, t1, t2); -+ tcg_temp_free(t1); -+ tcg_temp_free(t2); -+ return true; -+} -+ -+#ifdef CONFIG_USER_ONLY -+static bool trans_gr2scr(DisasContext *ctx, arg_gr2scr *a) -+{ -+ return false; -+} -+ -+static bool trans_scr2gr(DisasContext *ctx, arg_scr2gr *a) -+{ -+ return false; -+} -+#else -+static bool trans_gr2scr(DisasContext *ctx, arg_gr2scr *a) -+{ -+ TCGv_i32 sd = tcg_const_i32(a->sd); -+ TCGv val = tcg_temp_new(); -+ check_lbt_enabled(ctx); -+ gen_load_gpr(val, a->rj); -+ gen_helper_store_scr(cpu_env, sd, val); -+ tcg_temp_free_i32(sd); -+ tcg_temp_free(val); -+ return true; -+} -+ -+static bool trans_scr2gr(DisasContext *ctx, arg_scr2gr *a) -+{ -+ if (a->rd == 0) { -+ /* Nop */ -+ return true; -+ } -+ -+ TCGv_i32 tsj = tcg_const_i32(a->sj); -+ check_lbt_enabled(ctx); -+ gen_helper_load_scr(cpu_gpr[a->rd], cpu_env, tsj); -+ tcg_temp_free_i32(tsj); -+ return true; -+} -+#endif -+ -+static bool trans_clo_w(DisasContext *ctx, arg_clo_w *a) -+{ -+ gen_cl(ctx, OPC_LARCH_CLO_W, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_clz_w(DisasContext *ctx, arg_clz_w *a) -+{ -+ gen_cl(ctx, OPC_LARCH_CLZ_W, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_cto_w(DisasContext *ctx, arg_cto_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ gen_helper_cto_w(cpu_gpr[a->rd], cpu_env, t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_ctz_w(DisasContext *ctx, arg_ctz_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ gen_helper_ctz_w(cpu_gpr[a->rd], cpu_env, t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_clo_d(DisasContext *ctx, arg_clo_d *a) -+{ -+ check_larch_64(ctx); -+ gen_cl(ctx, OPC_LARCH_CLO_D, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_clz_d(DisasContext *ctx, arg_clz_d *a) -+{ -+ check_larch_64(ctx); -+ gen_cl(ctx, OPC_LARCH_CLZ_D, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_cto_d(DisasContext *ctx, arg_cto_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ gen_helper_cto_d(cpu_gpr[a->rd], cpu_env, t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_ctz_d(DisasContext *ctx, arg_ctz_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, a->rj); -+ gen_helper_ctz_d(cpu_gpr[a->rd], cpu_env, t0); -+ -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_revb_2h(DisasContext *ctx, arg_revb_2h *a) -+{ -+ gen_bshfl(ctx, OPC_LARCH_REVB_2H, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revb_4h(DisasContext *ctx, arg_revb_4h *a) -+{ -+ check_larch_64(ctx); -+ gen_bshfl(ctx, OPC_LARCH_REVB_4H, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revb_2w(DisasContext *ctx, arg_revb_2w *a) -+{ -+ handle_rev32(ctx, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revb_d(DisasContext *ctx, arg_revb_d *a) -+{ -+ handle_rev64(ctx, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revh_2w(DisasContext *ctx, arg_revh_2w *a) -+{ -+ handle_rev16(ctx, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_revh_d(DisasContext *ctx, arg_revh_d *a) -+{ -+ check_larch_64(ctx); -+ gen_bshfl(ctx, OPC_LARCH_REVH_D, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_bitrev_4b(DisasContext *ctx, arg_bitrev_4b *a) -+{ -+ gen_bitswap(ctx, OPC_LARCH_BREV_4B, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_bitrev_8b(DisasContext *ctx, arg_bitrev_8b *a) -+{ -+ check_larch_64(ctx); -+ gen_bitswap(ctx, OPC_LARCH_BREV_8B, a->rd, a->rj); -+ return true; -+} -+ -+static bool trans_bitrev_w(DisasContext *ctx, arg_bitrev_w *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ gen_helper_bitrev_w(cpu_gpr[a->rd], cpu_env, t0); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_bitrev_d(DisasContext *ctx, arg_bitrev_d *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ gen_helper_bitrev_d(cpu_gpr[a->rd], cpu_env, t0); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_ext_w_h(DisasContext *ctx, arg_ext_w_h *a) -+{ -+ gen_bshfl(ctx, OPC_LARCH_EXT_WH, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_ext_w_b(DisasContext *ctx, arg_ext_w_b *a) -+{ -+ gen_bshfl(ctx, OPC_LARCH_EXT_WB, a->rj, a->rd); -+ return true; -+} -+ -+static bool trans_srli_w(DisasContext *ctx, arg_srli_w *a) -+{ -+ gen_shift_imm(ctx, OPC_LARCH_SRLI_W, a->rd, a->rj, a->ui5); -+ return true; -+} -+ -+static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) -+{ -+ gen_shift_imm(ctx, OPC_LARCH_SRAI_W, a->rd, a->rj, a->ui5); -+ return true; -+} -+ -+static bool trans_srai_d(DisasContext *ctx, arg_srai_d *a) -+{ -+ TCGv t0; -+ check_larch_64(ctx); -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_sari_tl(cpu_gpr[a->rd], t0, a->ui6); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_rotri_w(DisasContext *ctx, arg_rotri_w *a) -+{ -+ gen_shift_imm(ctx, OPC_LARCH_ROTRI_W, a->rd, a->rj, a->ui5); -+ return true; -+} -+ -+static bool trans_rotri_d(DisasContext *ctx, arg_rotri_d *a) -+{ -+ TCGv t0; -+ check_larch_64(ctx); -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ tcg_gen_rotri_tl(cpu_gpr[a->rd], t0, a->ui6); -+ tcg_temp_free(t0); -+ return true; -+} -+ -+static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) -+{ -+ check_cp1_enabled(ctx); -+ gen_fcmp_s(ctx, a->fcond, a->fk, a->fj, a->cd); -+ return true; -+} -+ -+static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) -+{ -+ check_cp1_enabled(ctx); -+ gen_fcmp_d(ctx, a->fcond, a->fk, a->fj, a->cd); -+ return true; -+} -+ -+static bool trans_fsel(DisasContext *ctx, arg_fsel *a) -+{ -+ TCGv_i64 fj = tcg_temp_new_i64(); -+ TCGv_i64 fk = tcg_temp_new_i64(); -+ TCGv_i64 fd = tcg_temp_new_i64(); -+ TCGv_i32 ca = tcg_const_i32(a->ca); -+ check_cp1_enabled(ctx); -+ gen_load_fpr64(ctx, fj, a->fj); -+ gen_load_fpr64(ctx, fk, a->fk); -+ gen_helper_fsel(fd, cpu_env, fj, fk, ca); -+ gen_store_fpr64(ctx, fd, a->fd); -+ tcg_temp_free_i64(fj); -+ tcg_temp_free_i64(fk); -+ tcg_temp_free_i64(fd); -+ tcg_temp_free_i32(ca); -+ return true; -+} -+ -+#include "cpu-csr.h" -+ -+#ifdef CONFIG_USER_ONLY -+ -+static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) -+{ -+ return false; -+} -+ -+#else -+ -+ -+#define GEN_CSRRQ_CASE(name) \ -+ do { \ -+ case LOONGARCH_CSR_ ## name: \ -+ gen_csr_rdq(ctx, cpu_gpr[rd], LOONGARCH_CSR_ ## name);\ -+ } while (0) -+ -+static bool trans_csrrd(DisasContext *ctx, unsigned rd, unsigned csr) -+{ -+ switch (csr) { -+ GEN_CSRRQ_CASE(CRMD); -+ break; -+ GEN_CSRRQ_CASE(PRMD); -+ break; -+ GEN_CSRRQ_CASE(EUEN); -+ break; -+ GEN_CSRRQ_CASE(MISC); -+ break; -+ GEN_CSRRQ_CASE(ECFG); -+ break; -+ GEN_CSRRQ_CASE(ESTAT); -+ break; -+ GEN_CSRRQ_CASE(ERA); -+ break; -+ GEN_CSRRQ_CASE(BADV); -+ break; -+ GEN_CSRRQ_CASE(BADI); -+ break; -+ GEN_CSRRQ_CASE(EEPN); -+ break; -+ GEN_CSRRQ_CASE(TLBIDX); -+ break; -+ GEN_CSRRQ_CASE(TLBEHI); -+ break; -+ GEN_CSRRQ_CASE(TLBELO0); -+ break; -+ GEN_CSRRQ_CASE(TLBELO1); -+ break; -+ GEN_CSRRQ_CASE(TLBWIRED); -+ break; -+ GEN_CSRRQ_CASE(GTLBC); -+ break; -+ GEN_CSRRQ_CASE(TRGP); -+ break; -+ GEN_CSRRQ_CASE(ASID); -+ break; -+ GEN_CSRRQ_CASE(PGDL); -+ break; -+ GEN_CSRRQ_CASE(PGDH); -+ break; -+ case LOONGARCH_CSR_PGD: -+ gen_helper_read_pgd(cpu_gpr[rd], cpu_env); -+ break; -+ GEN_CSRRQ_CASE(PWCTL0); -+ break; -+ GEN_CSRRQ_CASE(PWCTL1); -+ break; -+ GEN_CSRRQ_CASE(STLBPGSIZE); -+ break; -+ GEN_CSRRQ_CASE(RVACFG); -+ break; -+ GEN_CSRRQ_CASE(CPUID); -+ break; -+ GEN_CSRRQ_CASE(PRCFG1); -+ break; -+ GEN_CSRRQ_CASE(PRCFG2); -+ break; -+ GEN_CSRRQ_CASE(PRCFG3); -+ break; -+ GEN_CSRRQ_CASE(KS0); -+ break; -+ GEN_CSRRQ_CASE(KS1); -+ break; -+ GEN_CSRRQ_CASE(KS2); -+ break; -+ GEN_CSRRQ_CASE(KS3); -+ break; -+ GEN_CSRRQ_CASE(KS4); -+ break; -+ GEN_CSRRQ_CASE(KS5); -+ break; -+ GEN_CSRRQ_CASE(KS6); -+ break; -+ GEN_CSRRQ_CASE(KS7); -+ break; -+ GEN_CSRRQ_CASE(KS8); -+ break; -+ GEN_CSRRQ_CASE(TMID); -+ break; -+ GEN_CSRRQ_CASE(TCFG); -+ break; -+ GEN_CSRRQ_CASE(TVAL); -+ break; -+ GEN_CSRRQ_CASE(CNTC); -+ break; -+ GEN_CSRRQ_CASE(TINTCLR); -+ break; -+ GEN_CSRRQ_CASE(GSTAT); -+ break; -+ GEN_CSRRQ_CASE(GCFG); -+ break; -+ GEN_CSRRQ_CASE(GINTC); -+ break; -+ GEN_CSRRQ_CASE(GCNTC); -+ break; -+ GEN_CSRRQ_CASE(LLBCTL); -+ break; -+ GEN_CSRRQ_CASE(IMPCTL1); -+ break; -+ GEN_CSRRQ_CASE(IMPCTL2); -+ break; -+ GEN_CSRRQ_CASE(GNMI); -+ break; -+ GEN_CSRRQ_CASE(TLBRENT); -+ break; -+ GEN_CSRRQ_CASE(TLBRBADV); -+ break; -+ GEN_CSRRQ_CASE(TLBRERA); -+ break; -+ GEN_CSRRQ_CASE(TLBRSAVE); -+ break; -+ GEN_CSRRQ_CASE(TLBRELO0); -+ break; -+ GEN_CSRRQ_CASE(TLBRELO1); -+ break; -+ GEN_CSRRQ_CASE(TLBREHI); -+ break; -+ GEN_CSRRQ_CASE(TLBRPRMD); -+ break; -+ GEN_CSRRQ_CASE(ERRCTL); -+ break; -+ GEN_CSRRQ_CASE(ERRINFO); -+ break; -+ GEN_CSRRQ_CASE(ERRINFO1); -+ break; -+ GEN_CSRRQ_CASE(ERRENT); -+ break; -+ GEN_CSRRQ_CASE(ERRERA); -+ break; -+ GEN_CSRRQ_CASE(ERRSAVE); -+ break; -+ GEN_CSRRQ_CASE(CTAG); -+ break; -+ GEN_CSRRQ_CASE(DMWIN0); -+ break; -+ GEN_CSRRQ_CASE(DMWIN1); -+ break; -+ GEN_CSRRQ_CASE(DMWIN2); -+ break; -+ GEN_CSRRQ_CASE(DMWIN3); -+ break; -+ GEN_CSRRQ_CASE(PERFCTRL0); -+ break; -+ GEN_CSRRQ_CASE(PERFCNTR0); -+ break; -+ GEN_CSRRQ_CASE(PERFCTRL1); -+ break; -+ GEN_CSRRQ_CASE(PERFCNTR1); -+ break; -+ GEN_CSRRQ_CASE(PERFCTRL2); -+ break; -+ GEN_CSRRQ_CASE(PERFCNTR2); -+ break; -+ GEN_CSRRQ_CASE(PERFCTRL3); -+ break; -+ GEN_CSRRQ_CASE(PERFCNTR3); -+ break; -+ /* debug */ -+ GEN_CSRRQ_CASE(MWPC); -+ break; -+ GEN_CSRRQ_CASE(MWPS); -+ break; -+ GEN_CSRRQ_CASE(DB0ADDR); -+ break; -+ GEN_CSRRQ_CASE(DB0MASK); -+ break; -+ GEN_CSRRQ_CASE(DB0CTL); -+ break; -+ GEN_CSRRQ_CASE(DB0ASID); -+ break; -+ GEN_CSRRQ_CASE(DB1ADDR); -+ break; -+ GEN_CSRRQ_CASE(DB1MASK); -+ break; -+ GEN_CSRRQ_CASE(DB1CTL); -+ break; -+ GEN_CSRRQ_CASE(DB1ASID); -+ break; -+ GEN_CSRRQ_CASE(DB2ADDR); -+ break; -+ GEN_CSRRQ_CASE(DB2MASK); -+ break; -+ GEN_CSRRQ_CASE(DB2CTL); -+ break; -+ GEN_CSRRQ_CASE(DB2ASID); -+ break; -+ GEN_CSRRQ_CASE(DB3ADDR); -+ break; -+ GEN_CSRRQ_CASE(DB3MASK); -+ break; -+ GEN_CSRRQ_CASE(DB3CTL); -+ break; -+ GEN_CSRRQ_CASE(DB3ASID); -+ break; -+ GEN_CSRRQ_CASE(FWPC); -+ break; -+ GEN_CSRRQ_CASE(FWPS); -+ break; -+ GEN_CSRRQ_CASE(IB0ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB0MASK); -+ break; -+ GEN_CSRRQ_CASE(IB0CTL); -+ break; -+ GEN_CSRRQ_CASE(IB0ASID); -+ break; -+ GEN_CSRRQ_CASE(IB1ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB1MASK); -+ break; -+ GEN_CSRRQ_CASE(IB1CTL); -+ break; -+ GEN_CSRRQ_CASE(IB1ASID); -+ break; -+ GEN_CSRRQ_CASE(IB2ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB2MASK); -+ break; -+ GEN_CSRRQ_CASE(IB2CTL); -+ break; -+ GEN_CSRRQ_CASE(IB2ASID); -+ break; -+ GEN_CSRRQ_CASE(IB3ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB3MASK); -+ break; -+ GEN_CSRRQ_CASE(IB3CTL); -+ break; -+ GEN_CSRRQ_CASE(IB3ASID); -+ break; -+ GEN_CSRRQ_CASE(IB4ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB4MASK); -+ break; -+ GEN_CSRRQ_CASE(IB4CTL); -+ break; -+ GEN_CSRRQ_CASE(IB4ASID); -+ break; -+ GEN_CSRRQ_CASE(IB5ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB5MASK); -+ break; -+ GEN_CSRRQ_CASE(IB5CTL); -+ break; -+ GEN_CSRRQ_CASE(IB5ASID); -+ break; -+ GEN_CSRRQ_CASE(IB6ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB6MASK); -+ break; -+ GEN_CSRRQ_CASE(IB6CTL); -+ break; -+ GEN_CSRRQ_CASE(IB6ASID); -+ break; -+ GEN_CSRRQ_CASE(IB7ADDR); -+ break; -+ GEN_CSRRQ_CASE(IB7MASK); -+ break; -+ GEN_CSRRQ_CASE(IB7CTL); -+ break; -+ GEN_CSRRQ_CASE(IB7ASID); -+ break; -+ GEN_CSRRQ_CASE(DEBUG); -+ break; -+ GEN_CSRRQ_CASE(DERA); -+ break; -+ GEN_CSRRQ_CASE(DESAVE); -+ break; -+ default: -+ return false; -+ } -+ -+ #undef GEN_CSRRQ_CASE -+ -+ return true; -+} -+ -+#define GEN_CSRWQ_CASE(name) \ -+do { \ -+ case LOONGARCH_CSR_ ## name: \ -+ gen_csr_wrq(ctx, cpu_gpr[rd], LOONGARCH_CSR_ ## name); \ -+} while (0) -+ -+static bool trans_csrwr(DisasContext *ctx, unsigned rd, unsigned csr) -+{ -+ -+ switch (csr) { -+ case LOONGARCH_CSR_CRMD: -+ save_cpu_state(ctx, 1); -+ gen_csr_wrq(ctx, cpu_gpr[rd], LOONGARCH_CSR_CRMD); -+ gen_save_pc(ctx->base.pc_next + 4); -+ ctx->base.is_jmp = DISAS_EXIT; -+ break; -+ GEN_CSRWQ_CASE(PRMD); -+ break; -+ case LOONGARCH_CSR_EUEN: -+ gen_csr_wrq(ctx, cpu_gpr[rd], LOONGARCH_CSR_EUEN); -+ /* Stop translation */ -+ gen_save_pc(ctx->base.pc_next + 4); -+ ctx->base.is_jmp = DISAS_EXIT; -+ break; -+ GEN_CSRWQ_CASE(MISC); -+ break; -+ GEN_CSRWQ_CASE(ECFG); -+ break; -+ GEN_CSRWQ_CASE(ESTAT); -+ break; -+ GEN_CSRWQ_CASE(ERA); -+ break; -+ GEN_CSRWQ_CASE(BADV); -+ break; -+ GEN_CSRWQ_CASE(BADI); -+ break; -+ GEN_CSRWQ_CASE(EEPN); -+ break; -+ GEN_CSRWQ_CASE(TLBIDX); -+ break; -+ GEN_CSRWQ_CASE(TLBEHI); -+ break; -+ GEN_CSRWQ_CASE(TLBELO0); -+ break; -+ GEN_CSRWQ_CASE(TLBELO1); -+ break; -+ GEN_CSRWQ_CASE(TLBWIRED); -+ break; -+ GEN_CSRWQ_CASE(GTLBC); -+ break; -+ GEN_CSRWQ_CASE(TRGP); -+ break; -+ GEN_CSRWQ_CASE(ASID); -+ break; -+ GEN_CSRWQ_CASE(PGDL); -+ break; -+ GEN_CSRWQ_CASE(PGDH); -+ break; -+ GEN_CSRWQ_CASE(PGD); -+ break; -+ GEN_CSRWQ_CASE(PWCTL0); -+ break; -+ GEN_CSRWQ_CASE(PWCTL1); -+ break; -+ GEN_CSRWQ_CASE(STLBPGSIZE); -+ break; -+ GEN_CSRWQ_CASE(RVACFG); -+ break; -+ GEN_CSRWQ_CASE(CPUID); -+ break; -+ GEN_CSRWQ_CASE(PRCFG1); -+ break; -+ GEN_CSRWQ_CASE(PRCFG2); -+ break; -+ GEN_CSRWQ_CASE(PRCFG3); -+ break; -+ GEN_CSRWQ_CASE(KS0); -+ break; -+ GEN_CSRWQ_CASE(KS1); -+ break; -+ GEN_CSRWQ_CASE(KS2); -+ break; -+ GEN_CSRWQ_CASE(KS3); -+ break; -+ GEN_CSRWQ_CASE(KS4); -+ break; -+ GEN_CSRWQ_CASE(KS5); -+ break; -+ GEN_CSRWQ_CASE(KS6); -+ break; -+ GEN_CSRWQ_CASE(KS7); -+ break; -+ GEN_CSRWQ_CASE(KS8); -+ break; -+ GEN_CSRWQ_CASE(TMID); -+ break; -+ GEN_CSRWQ_CASE(TCFG); -+ break; -+ GEN_CSRWQ_CASE(TVAL); -+ break; -+ GEN_CSRWQ_CASE(CNTC); -+ break; -+ GEN_CSRWQ_CASE(TINTCLR); -+ break; -+ GEN_CSRWQ_CASE(GSTAT); -+ break; -+ GEN_CSRWQ_CASE(GCFG); -+ break; -+ GEN_CSRWQ_CASE(GINTC); -+ break; -+ GEN_CSRWQ_CASE(GCNTC); -+ break; -+ GEN_CSRWQ_CASE(LLBCTL); -+ break; -+ GEN_CSRWQ_CASE(IMPCTL1); -+ break; -+ GEN_CSRWQ_CASE(IMPCTL2); -+ break; -+ GEN_CSRWQ_CASE(GNMI); -+ break; -+ GEN_CSRWQ_CASE(TLBRENT); -+ break; -+ GEN_CSRWQ_CASE(TLBRBADV); -+ break; -+ GEN_CSRWQ_CASE(TLBRERA); -+ break; -+ GEN_CSRWQ_CASE(TLBRSAVE); -+ break; -+ GEN_CSRWQ_CASE(TLBRELO0); -+ break; -+ GEN_CSRWQ_CASE(TLBRELO1); -+ break; -+ GEN_CSRWQ_CASE(TLBREHI); -+ break; -+ GEN_CSRWQ_CASE(TLBRPRMD); -+ break; -+ GEN_CSRWQ_CASE(ERRCTL); -+ break; -+ GEN_CSRWQ_CASE(ERRINFO); -+ break; -+ GEN_CSRWQ_CASE(ERRINFO1); -+ break; -+ GEN_CSRWQ_CASE(ERRENT); -+ break; -+ GEN_CSRWQ_CASE(ERRERA); -+ break; -+ GEN_CSRWQ_CASE(ERRSAVE); -+ break; -+ GEN_CSRWQ_CASE(CTAG); -+ break; -+ GEN_CSRWQ_CASE(DMWIN0); -+ break; -+ GEN_CSRWQ_CASE(DMWIN1); -+ break; -+ GEN_CSRWQ_CASE(DMWIN2); -+ break; -+ GEN_CSRWQ_CASE(DMWIN3); -+ break; -+ GEN_CSRWQ_CASE(PERFCTRL0); -+ break; -+ GEN_CSRWQ_CASE(PERFCNTR0); -+ break; -+ GEN_CSRWQ_CASE(PERFCTRL1); -+ break; -+ GEN_CSRWQ_CASE(PERFCNTR1); -+ break; -+ GEN_CSRWQ_CASE(PERFCTRL2); -+ break; -+ GEN_CSRWQ_CASE(PERFCNTR2); -+ break; -+ GEN_CSRWQ_CASE(PERFCTRL3); -+ break; -+ GEN_CSRWQ_CASE(PERFCNTR3); -+ break; -+ /* debug */ -+ GEN_CSRWQ_CASE(MWPC); -+ break; -+ GEN_CSRWQ_CASE(MWPS); -+ break; -+ GEN_CSRWQ_CASE(DB0ADDR); -+ break; -+ GEN_CSRWQ_CASE(DB0MASK); -+ break; -+ GEN_CSRWQ_CASE(DB0CTL); -+ break; -+ GEN_CSRWQ_CASE(DB0ASID); -+ break; -+ GEN_CSRWQ_CASE(DB1ADDR); -+ break; -+ GEN_CSRWQ_CASE(DB1MASK); -+ break; -+ GEN_CSRWQ_CASE(DB1CTL); -+ break; -+ GEN_CSRWQ_CASE(DB1ASID); -+ break; -+ GEN_CSRWQ_CASE(DB2ADDR); -+ break; -+ GEN_CSRWQ_CASE(DB2MASK); -+ break; -+ GEN_CSRWQ_CASE(DB2CTL); -+ break; -+ GEN_CSRWQ_CASE(DB2ASID); -+ break; -+ GEN_CSRWQ_CASE(DB3ADDR); -+ break; -+ GEN_CSRWQ_CASE(DB3MASK); -+ break; -+ GEN_CSRWQ_CASE(DB3CTL); -+ break; -+ GEN_CSRWQ_CASE(DB3ASID); -+ break; -+ GEN_CSRWQ_CASE(FWPC); -+ break; -+ GEN_CSRWQ_CASE(FWPS); -+ break; -+ GEN_CSRWQ_CASE(IB0ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB0MASK); -+ break; -+ GEN_CSRWQ_CASE(IB0CTL); -+ break; -+ GEN_CSRWQ_CASE(IB0ASID); -+ break; -+ GEN_CSRWQ_CASE(IB1ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB1MASK); -+ break; -+ GEN_CSRWQ_CASE(IB1CTL); -+ break; -+ GEN_CSRWQ_CASE(IB1ASID); -+ break; -+ GEN_CSRWQ_CASE(IB2ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB2MASK); -+ break; -+ GEN_CSRWQ_CASE(IB2CTL); -+ break; -+ GEN_CSRWQ_CASE(IB2ASID); -+ break; -+ GEN_CSRWQ_CASE(IB3ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB3MASK); -+ break; -+ GEN_CSRWQ_CASE(IB3CTL); -+ break; -+ GEN_CSRWQ_CASE(IB3ASID); -+ break; -+ GEN_CSRWQ_CASE(IB4ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB4MASK); -+ break; -+ GEN_CSRWQ_CASE(IB4CTL); -+ break; -+ GEN_CSRWQ_CASE(IB4ASID); -+ break; -+ GEN_CSRWQ_CASE(IB5ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB5MASK); -+ break; -+ GEN_CSRWQ_CASE(IB5CTL); -+ break; -+ GEN_CSRWQ_CASE(IB5ASID); -+ break; -+ GEN_CSRWQ_CASE(IB6ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB6MASK); -+ break; -+ GEN_CSRWQ_CASE(IB6CTL); -+ break; -+ GEN_CSRWQ_CASE(IB6ASID); -+ break; -+ GEN_CSRWQ_CASE(IB7ADDR); -+ break; -+ GEN_CSRWQ_CASE(IB7MASK); -+ break; -+ GEN_CSRWQ_CASE(IB7CTL); -+ break; -+ GEN_CSRWQ_CASE(IB7ASID); -+ break; -+ GEN_CSRWQ_CASE(DEBUG); -+ break; -+ GEN_CSRWQ_CASE(DERA); -+ break; -+ GEN_CSRWQ_CASE(DESAVE); -+ break; -+ default: -+ return false; -+ } -+ -+ #undef GEN_CSRWQ_CASE -+ -+ return true; -+} -+ -+#define GEN_CSRXQ_CASE(name) \ -+do { \ -+ case LOONGARCH_CSR_ ## name: \ -+ if (rd == 0) { \ -+ gen_csr_xchgq(ctx, zero, cpu_gpr[rj], \ -+ LOONGARCH_CSR_ ## name); \ -+ } else { \ -+ gen_csr_xchgq(ctx, cpu_gpr[rd], cpu_gpr[rj], \ -+ LOONGARCH_CSR_ ## name); \ -+ } \ -+} while (0) -+ -+static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) -+{ -+ unsigned rd, rj, csr; -+ TCGv zero = tcg_const_tl(0); -+ rd = a->rd; -+ rj = a->rj; -+ csr = a->csr; -+ -+ if (rj == 0) { -+ return trans_csrrd(ctx, rd, csr); -+ } else if (rj == 1) { -+ return trans_csrwr(ctx, rd, csr); -+ } -+ -+ switch (csr) { -+ case LOONGARCH_CSR_CRMD: -+ save_cpu_state(ctx, 1); -+ if (rd == 0) { -+ gen_csr_xchgq(ctx, zero, cpu_gpr[rj], LOONGARCH_CSR_CRMD); -+ } else { -+ gen_csr_xchgq(ctx, cpu_gpr[rd], cpu_gpr[rj], LOONGARCH_CSR_CRMD); -+ } -+ gen_save_pc(ctx->base.pc_next + 4); -+ ctx->base.is_jmp = DISAS_EXIT; -+ break; -+ -+ GEN_CSRXQ_CASE(PRMD); -+ break; -+ case LOONGARCH_CSR_EUEN: -+ if (rd == 0) { -+ gen_csr_xchgq(ctx, zero, cpu_gpr[rj], LOONGARCH_CSR_EUEN); -+ } else { -+ gen_csr_xchgq(ctx, cpu_gpr[rd], cpu_gpr[rj], LOONGARCH_CSR_EUEN); -+ } -+ /* Stop translation */ -+ gen_save_pc(ctx->base.pc_next + 4); -+ ctx->base.is_jmp = DISAS_EXIT; -+ break; -+ GEN_CSRXQ_CASE(MISC); -+ break; -+ GEN_CSRXQ_CASE(ECFG); -+ break; -+ GEN_CSRXQ_CASE(ESTAT); -+ break; -+ GEN_CSRXQ_CASE(ERA); -+ break; -+ GEN_CSRXQ_CASE(BADV); -+ break; -+ GEN_CSRXQ_CASE(BADI); -+ break; -+ GEN_CSRXQ_CASE(EEPN); -+ break; -+ GEN_CSRXQ_CASE(TLBIDX); -+ break; -+ GEN_CSRXQ_CASE(TLBEHI); -+ break; -+ GEN_CSRXQ_CASE(TLBELO0); -+ break; -+ GEN_CSRXQ_CASE(TLBELO1); -+ break; -+ GEN_CSRXQ_CASE(TLBWIRED); -+ break; -+ GEN_CSRXQ_CASE(GTLBC); -+ break; -+ GEN_CSRXQ_CASE(TRGP); -+ break; -+ GEN_CSRXQ_CASE(ASID); -+ break; -+ GEN_CSRXQ_CASE(PGDL); -+ break; -+ GEN_CSRXQ_CASE(PGDH); -+ break; -+ GEN_CSRXQ_CASE(PGD); -+ break; -+ GEN_CSRXQ_CASE(PWCTL0); -+ break; -+ GEN_CSRXQ_CASE(PWCTL1); -+ break; -+ GEN_CSRXQ_CASE(STLBPGSIZE); -+ break; -+ GEN_CSRXQ_CASE(RVACFG); -+ break; -+ GEN_CSRXQ_CASE(CPUID); -+ break; -+ GEN_CSRXQ_CASE(PRCFG1); -+ break; -+ GEN_CSRXQ_CASE(PRCFG2); -+ break; -+ GEN_CSRXQ_CASE(PRCFG3); -+ break; -+ GEN_CSRXQ_CASE(KS0); -+ break; -+ GEN_CSRXQ_CASE(KS1); -+ break; -+ GEN_CSRXQ_CASE(KS2); -+ break; -+ GEN_CSRXQ_CASE(KS3); -+ break; -+ GEN_CSRXQ_CASE(KS4); -+ break; -+ GEN_CSRXQ_CASE(KS5); -+ break; -+ GEN_CSRXQ_CASE(KS6); -+ break; -+ GEN_CSRXQ_CASE(KS7); -+ break; -+ GEN_CSRXQ_CASE(KS8); -+ break; -+ GEN_CSRXQ_CASE(TMID); -+ break; -+ GEN_CSRXQ_CASE(TCFG); -+ break; -+ GEN_CSRXQ_CASE(TVAL); -+ break; -+ GEN_CSRXQ_CASE(CNTC); -+ break; -+ GEN_CSRXQ_CASE(TINTCLR); -+ break; -+ GEN_CSRXQ_CASE(GSTAT); -+ break; -+ GEN_CSRXQ_CASE(GCFG); -+ break; -+ GEN_CSRXQ_CASE(GINTC); -+ break; -+ GEN_CSRXQ_CASE(GCNTC); -+ break; -+ GEN_CSRXQ_CASE(LLBCTL); -+ break; -+ GEN_CSRXQ_CASE(IMPCTL1); -+ break; -+ GEN_CSRXQ_CASE(IMPCTL2); -+ break; -+ GEN_CSRXQ_CASE(GNMI); -+ break; -+ GEN_CSRXQ_CASE(TLBRENT); -+ break; -+ GEN_CSRXQ_CASE(TLBRBADV); -+ break; -+ GEN_CSRXQ_CASE(TLBRERA); -+ break; -+ GEN_CSRXQ_CASE(TLBRSAVE); -+ break; -+ GEN_CSRXQ_CASE(TLBRELO0); -+ break; -+ GEN_CSRXQ_CASE(TLBRELO1); -+ break; -+ GEN_CSRXQ_CASE(TLBREHI); -+ break; -+ GEN_CSRXQ_CASE(TLBRPRMD); -+ break; -+ GEN_CSRXQ_CASE(ERRCTL); -+ break; -+ GEN_CSRXQ_CASE(ERRINFO); -+ break; -+ GEN_CSRXQ_CASE(ERRINFO1); -+ break; -+ GEN_CSRXQ_CASE(ERRENT); -+ break; -+ GEN_CSRXQ_CASE(ERRERA); -+ break; -+ GEN_CSRXQ_CASE(ERRSAVE); -+ break; -+ GEN_CSRXQ_CASE(CTAG); -+ break; -+ GEN_CSRXQ_CASE(DMWIN0); -+ break; -+ GEN_CSRXQ_CASE(DMWIN1); -+ break; -+ GEN_CSRXQ_CASE(DMWIN2); -+ break; -+ GEN_CSRXQ_CASE(DMWIN3); -+ break; -+ GEN_CSRXQ_CASE(PERFCTRL0); -+ break; -+ GEN_CSRXQ_CASE(PERFCNTR0); -+ break; -+ GEN_CSRXQ_CASE(PERFCTRL1); -+ break; -+ GEN_CSRXQ_CASE(PERFCNTR1); -+ break; -+ GEN_CSRXQ_CASE(PERFCTRL2); -+ break; -+ GEN_CSRXQ_CASE(PERFCNTR2); -+ break; -+ GEN_CSRXQ_CASE(PERFCTRL3); -+ break; -+ GEN_CSRXQ_CASE(PERFCNTR3); -+ break; -+ /* debug */ -+ GEN_CSRXQ_CASE(MWPC); -+ break; -+ GEN_CSRXQ_CASE(MWPS); -+ break; -+ GEN_CSRXQ_CASE(DB0ADDR); -+ break; -+ GEN_CSRXQ_CASE(DB0MASK); -+ break; -+ GEN_CSRXQ_CASE(DB0CTL); -+ break; -+ GEN_CSRXQ_CASE(DB0ASID); -+ break; -+ GEN_CSRXQ_CASE(DB1ADDR); -+ break; -+ GEN_CSRXQ_CASE(DB1MASK); -+ break; -+ GEN_CSRXQ_CASE(DB1CTL); -+ break; -+ GEN_CSRXQ_CASE(DB1ASID); -+ break; -+ GEN_CSRXQ_CASE(DB2ADDR); -+ break; -+ GEN_CSRXQ_CASE(DB2MASK); -+ break; -+ GEN_CSRXQ_CASE(DB2CTL); -+ break; -+ GEN_CSRXQ_CASE(DB2ASID); -+ break; -+ GEN_CSRXQ_CASE(DB3ADDR); -+ break; -+ GEN_CSRXQ_CASE(DB3MASK); -+ break; -+ GEN_CSRXQ_CASE(DB3CTL); -+ break; -+ GEN_CSRXQ_CASE(DB3ASID); -+ break; -+ GEN_CSRXQ_CASE(FWPC); -+ break; -+ GEN_CSRXQ_CASE(FWPS); -+ break; -+ GEN_CSRXQ_CASE(IB0ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB0MASK); -+ break; -+ GEN_CSRXQ_CASE(IB0CTL); -+ break; -+ GEN_CSRXQ_CASE(IB0ASID); -+ break; -+ GEN_CSRXQ_CASE(IB1ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB1MASK); -+ break; -+ GEN_CSRXQ_CASE(IB1CTL); -+ break; -+ GEN_CSRXQ_CASE(IB1ASID); -+ break; -+ GEN_CSRXQ_CASE(IB2ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB2MASK); -+ break; -+ GEN_CSRXQ_CASE(IB2CTL); -+ break; -+ GEN_CSRXQ_CASE(IB2ASID); -+ break; -+ GEN_CSRXQ_CASE(IB3ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB3MASK); -+ break; -+ GEN_CSRXQ_CASE(IB3CTL); -+ break; -+ GEN_CSRXQ_CASE(IB3ASID); -+ break; -+ GEN_CSRXQ_CASE(IB4ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB4MASK); -+ break; -+ GEN_CSRXQ_CASE(IB4CTL); -+ break; -+ GEN_CSRXQ_CASE(IB4ASID); -+ break; -+ GEN_CSRXQ_CASE(IB5ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB5MASK); -+ break; -+ GEN_CSRXQ_CASE(IB5CTL); -+ break; -+ GEN_CSRXQ_CASE(IB5ASID); -+ break; -+ GEN_CSRXQ_CASE(IB6ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB6MASK); -+ break; -+ GEN_CSRXQ_CASE(IB6CTL); -+ break; -+ GEN_CSRXQ_CASE(IB6ASID); -+ break; -+ GEN_CSRXQ_CASE(IB7ADDR); -+ break; -+ GEN_CSRXQ_CASE(IB7MASK); -+ break; -+ GEN_CSRXQ_CASE(IB7CTL); -+ break; -+ GEN_CSRXQ_CASE(IB7ASID); -+ break; -+ GEN_CSRXQ_CASE(DEBUG); -+ break; -+ GEN_CSRXQ_CASE(DERA); -+ break; -+ GEN_CSRXQ_CASE(DESAVE); -+ break; -+ default: -+ return false; -+ } -+ -+ #undef GEN_CSRXQ_CASE -+ tcg_temp_free(zero); -+ return true; -+} -+ -+#endif -+ -+static bool trans_cacop(DisasContext *ctx, arg_cacop *a) -+{ -+ /* Treat as NOP. */ -+ return true; -+} -+ -+#ifdef CONFIG_USER_ONLY -+ -+static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) -+{ -+ return false; -+} -+ -+static bool trans_lddir(DisasContext *ctx, arg_lddir *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_b(DisasContext *ctx, arg_iocsrrd_b *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_h(DisasContext *ctx, arg_iocsrrd_h *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_w(DisasContext *ctx, arg_iocsrrd_w *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_d(DisasContext *ctx, arg_iocsrrd_d *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_b(DisasContext *ctx, arg_iocsrwr_b *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_h(DisasContext *ctx, arg_iocsrwr_h *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_w(DisasContext *ctx, arg_iocsrwr_w *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a) -+{ -+ return false; -+} -+#else -+ -+static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) -+{ -+ TCGv t0, t1; -+ TCGv_i32 t2; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->seq); -+ t2 = tcg_const_i32(ctx->mem_idx); -+ gen_helper_ldpte(cpu_env, t0, t1, t2); -+ -+ return true; -+} -+ -+static bool trans_lddir(DisasContext *ctx, arg_lddir *a) -+{ -+ TCGv t0, t1, t2; -+ TCGv_i32 t3; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ t2 = tcg_const_tl(a->level); -+ t3 = tcg_const_i32(ctx->mem_idx); -+ gen_helper_lddir(cpu_env, t0, t1, t2, t3); -+ -+ return true; -+} -+ -+static bool trans_iocsrrd_b(DisasContext *ctx, arg_iocsrrd_b *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_h(DisasContext *ctx, arg_iocsrrd_h *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrrd_w(DisasContext *ctx, arg_iocsrrd_w *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_LD_W); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+ -+static bool trans_iocsrrd_d(DisasContext *ctx, arg_iocsrrd_d *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_LD_D); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+ -+static bool trans_iocsrwr_b(DisasContext *ctx, arg_iocsrwr_b *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_ST_B); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+ -+static bool trans_iocsrwr_h(DisasContext *ctx, arg_iocsrwr_h *a) -+{ -+ return false; -+} -+ -+static bool trans_iocsrwr_w(DisasContext *ctx, arg_iocsrwr_w *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_ST_W); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+ -+static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a) -+{ -+ TCGv_i32 iocsr_op = tcg_const_i32(OPC_LARCH_ST_D); -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rj); -+ t1 = tcg_const_tl(a->rd); -+ gen_helper_iocsr(cpu_env, t0, t1, iocsr_op); -+ return true; -+} -+#endif /* !CONFIG_USER_ONLY */ -+ -+ -+#ifdef CONFIG_USER_ONLY -+ -+#define GEN_FALSE_TRANS(name) \ -+static bool trans_##name(DisasContext *ctx, arg_##name * a) \ -+{ \ -+ return false; \ -+} -+ -+GEN_FALSE_TRANS(tlbclr) -+GEN_FALSE_TRANS(invtlb) -+GEN_FALSE_TRANS(tlbflush) -+GEN_FALSE_TRANS(tlbsrch) -+GEN_FALSE_TRANS(tlbrd) -+GEN_FALSE_TRANS(tlbwr) -+GEN_FALSE_TRANS(tlbfill) -+GEN_FALSE_TRANS(ertn) -+ -+#else -+ -+static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) -+{ -+ gen_helper_tlbclr(cpu_env); -+ return true; -+} -+ -+static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) -+{ -+ gen_helper_tlbflush(cpu_env); -+ return true; -+} -+ -+static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) -+{ -+ TCGv addr = tcg_temp_new(); -+ TCGv info = tcg_temp_new(); -+ TCGv op = tcg_const_tl(a->invop); -+ -+ gen_load_gpr(addr, a->addr); -+ gen_load_gpr(info, a->info); -+ gen_helper_invtlb(cpu_env, addr, info, op); -+ -+ tcg_temp_free(addr); -+ tcg_temp_free(info); -+ tcg_temp_free(op); -+ return true; -+} -+ -+static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a) -+{ -+ gen_helper_tlbsrch(cpu_env); -+ return true; -+} -+ -+static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a) -+{ -+ gen_helper_tlbrd(cpu_env); -+ return true; -+} -+ -+static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) -+{ -+ gen_helper_tlbwr(cpu_env); -+ return true; -+} -+ -+static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) -+{ -+ gen_helper_tlbfill(cpu_env); -+ return true; -+} -+ -+static bool trans_ertn(DisasContext *ctx, arg_ertn *a) -+{ -+ gen_helper_ertn(cpu_env); -+ ctx->base.is_jmp = DISAS_EXIT; -+ return true; -+} -+ -+#endif /* CONFIG_USER_ONLY */ -+ -+static bool trans_idle(DisasContext *ctx, arg_idle *a) -+{ -+ ctx->base.pc_next += 4; -+ save_cpu_state(ctx, 1); -+ ctx->base.pc_next -= 4; -+ gen_helper_idle(cpu_env); -+ ctx->base.is_jmp = DISAS_NORETURN; -+ return true; -+} -+ -+#ifdef CONFIG_USER_ONLY -+ -+static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) -+{ -+ /* Nop */ -+ return true; -+} -+ -+#else -+ -+static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) -+{ -+ TCGv t0, t1; -+ t0 = tcg_const_tl(a->rd); -+ t1 = tcg_const_tl(a->rj); -+ gen_helper_drdtime(cpu_env, t0, t1); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return true; -+} -+ -+#endif -+ -+static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) -+{ -+ TCGv t0 = tcg_temp_new(); -+ gen_load_gpr(t0, a->rj); -+ gen_helper_cpucfg(cpu_gpr[a->rd], cpu_env, t0); -+ tcg_temp_free(t0); -+ return true; -+} -diff --git a/target/loongarch64/translate.c b/target/loongarch64/translate.c -new file mode 100644 -index 000000000..fe122e4c3 ---- /dev/null -+++ b/target/loongarch64/translate.c -@@ -0,0 +1,2892 @@ -+/* -+ * LOONGARCH emulation for QEMU - main translation routines -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "cpu.h" -+#include "internal.h" -+#include "disas/disas.h" -+#include "exec/exec-all.h" -+#include "tcg/tcg-op.h" -+#include "exec/cpu_ldst.h" -+#include "hw/loongarch/cpudevs.h" -+ -+#include "exec/helper-proto.h" -+#include "exec/helper-gen.h" -+#include "semihosting/semihost.h" -+ -+#include "trace-tcg.h" -+#include "exec/translator.h" -+#include "exec/log.h" -+ -+#include "instmap.h" -+ -+#define LARCH_DEBUG_DISAS 0 -+ -+/* Values for the fmt field in FP instructions */ -+enum { -+ /* 0 - 15 are reserved */ -+ FMT_S = 16, /* single fp */ -+ FMT_D = 17, /* double fp */ -+}; -+ -+/* global register indices */ -+static TCGv cpu_gpr[32], cpu_PC; -+static TCGv btarget, bcond; -+static TCGv cpu_lladdr, cpu_llval; -+static TCGv_i32 hflags; -+static TCGv_i32 fpu_fcsr0; -+static TCGv_i64 fpu_f64[32]; -+ -+#include "exec/gen-icount.h" -+ -+#define gen_helper_0e0i(name, arg) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg); \ -+ gen_helper_##name(cpu_env, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_0e1i(name, arg1, arg2) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ -+ gen_helper_##name(cpu_env, arg1, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_1e0i(name, ret, arg1) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg1); \ -+ gen_helper_##name(ret, cpu_env, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_1e1i(name, ret, arg1, arg2) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ -+ gen_helper_##name(ret, cpu_env, arg1, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_0e2i(name, arg1, arg2, arg3) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ -+ gen_helper_##name(cpu_env, arg1, arg2, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_1e2i(name, ret, arg1, arg2, arg3) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ -+ gen_helper_##name(ret, cpu_env, arg1, arg2, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+#define gen_helper_0e3i(name, arg1, arg2, arg3, arg4) do { \ -+ TCGv_i32 helper_tmp = tcg_const_i32(arg4); \ -+ gen_helper_##name(cpu_env, arg1, arg2, arg3, helper_tmp); \ -+ tcg_temp_free_i32(helper_tmp); \ -+ } while (0) -+ -+typedef struct DisasContext { -+ DisasContextBase base; -+ target_ulong saved_pc; -+ target_ulong page_start; -+ uint32_t opcode; -+ uint64_t insn_flags; -+ /* Routine used to access memory */ -+ int mem_idx; -+ MemOp default_tcg_memop_mask; -+ uint32_t hflags, saved_hflags; -+ target_ulong btarget; -+} DisasContext; -+ -+#define DISAS_STOP DISAS_TARGET_0 -+#define DISAS_EXIT DISAS_TARGET_1 -+ -+#define LOG_DISAS(...) \ -+ do { \ -+ if (LARCH_DEBUG_DISAS) { \ -+ qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \ -+ } \ -+ } while (0) -+ -+#define LARCH_INVAL(op) \ -+ do { \ -+ if (LARCH_DEBUG_DISAS) { \ -+ qemu_log_mask(CPU_LOG_TB_IN_ASM, \ -+ TARGET_FMT_lx ": %08x Invalid %s %03x %03x %03x\n", \ -+ ctx->base.pc_next, ctx->opcode, op, \ -+ ctx->opcode >> 26, ctx->opcode & 0x3F, \ -+ ((ctx->opcode >> 16) & 0x1F)); \ -+ } \ -+ } while (0) -+ -+/* General purpose registers moves. */ -+static inline void gen_load_gpr(TCGv t, int reg) -+{ -+ if (reg == 0) { -+ tcg_gen_movi_tl(t, 0); -+ } else { -+ tcg_gen_mov_tl(t, cpu_gpr[reg]); -+ } -+} -+ -+static inline void gen_store_gpr(TCGv t, int reg) -+{ -+ if (reg != 0) { -+ tcg_gen_mov_tl(cpu_gpr[reg], t); -+ } -+} -+ -+/* Moves to/from shadow registers. */ -+/* Tests */ -+static inline void gen_save_pc(target_ulong pc) -+{ -+ tcg_gen_movi_tl(cpu_PC, pc); -+} -+ -+static inline void save_cpu_state(DisasContext *ctx, int do_save_pc) -+{ -+ LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); -+ if (do_save_pc && ctx->base.pc_next != ctx->saved_pc) { -+ gen_save_pc(ctx->base.pc_next); -+ ctx->saved_pc = ctx->base.pc_next; -+ } -+ if (ctx->hflags != ctx->saved_hflags) { -+ tcg_gen_movi_i32(hflags, ctx->hflags); -+ ctx->saved_hflags = ctx->hflags; -+ switch (ctx->hflags & LARCH_HFLAG_BMASK) { -+ case LARCH_HFLAG_BR: -+ break; -+ case LARCH_HFLAG_BC: -+ case LARCH_HFLAG_B: -+ tcg_gen_movi_tl(btarget, ctx->btarget); -+ break; -+ } -+ } -+} -+ -+static inline void restore_cpu_state(CPULOONGARCHState *env, DisasContext *ctx) -+{ -+ ctx->saved_hflags = ctx->hflags; -+ switch (ctx->hflags & LARCH_HFLAG_BMASK) { -+ case LARCH_HFLAG_BR: -+ break; -+ case LARCH_HFLAG_BC: -+ case LARCH_HFLAG_B: -+ ctx->btarget = env->btarget; -+ break; -+ } -+} -+ -+static inline void generate_exception_err(DisasContext *ctx, int excp, int err) -+{ -+ TCGv_i32 texcp = tcg_const_i32(excp); -+ TCGv_i32 terr = tcg_const_i32(err); -+ save_cpu_state(ctx, 1); -+ gen_helper_raise_exception_err(cpu_env, texcp, terr); -+ tcg_temp_free_i32(terr); -+ tcg_temp_free_i32(texcp); -+ ctx->base.is_jmp = DISAS_NORETURN; -+} -+ -+static inline void generate_exception_end(DisasContext *ctx, int excp) -+{ -+ generate_exception_err(ctx, excp, 0); -+} -+ -+/* Floating point register moves. */ -+static void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) -+{ -+ tcg_gen_extrl_i64_i32(t, fpu_f64[reg]); -+} -+ -+static void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) -+{ -+ TCGv_i64 t64; -+ t64 = tcg_temp_new_i64(); -+ tcg_gen_extu_i32_i64(t64, t); -+ tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 0, 32); -+ tcg_temp_free_i64(t64); -+} -+ -+static void gen_load_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) -+{ -+ tcg_gen_extrh_i64_i32(t, fpu_f64[reg]); -+} -+ -+static void gen_store_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) -+{ -+ TCGv_i64 t64 = tcg_temp_new_i64(); -+ tcg_gen_extu_i32_i64(t64, t); -+ tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 32, 32); -+ tcg_temp_free_i64(t64); -+} -+ -+static void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) -+{ -+ tcg_gen_mov_i64(t, fpu_f64[reg]); -+} -+ -+static void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) -+{ -+ tcg_gen_mov_i64(fpu_f64[reg], t); -+} -+ -+static inline int get_fp_bit(int cc) -+{ -+ if (cc) { -+ return 24 + cc; -+ } else { -+ return 23; -+ } -+} -+ -+/* Addresses computation */ -+static inline void gen_op_addr_add(DisasContext *ctx, -+ TCGv ret, TCGv arg0, TCGv arg1) -+{ -+ tcg_gen_add_tl(ret, arg0, arg1); -+ -+ if (ctx->hflags & LARCH_HFLAG_AWRAP) { -+ tcg_gen_ext32s_i64(ret, ret); -+ } -+} -+ -+static inline void gen_op_addr_addi(DisasContext *ctx, TCGv ret, TCGv base, -+ target_long ofs) -+{ -+ tcg_gen_addi_tl(ret, base, ofs); -+ -+ if (ctx->hflags & LARCH_HFLAG_AWRAP) { -+ tcg_gen_ext32s_i64(ret, ret); -+ } -+} -+ -+/* Sign-extract the low 32-bits to a target_long. */ -+static inline void gen_move_low32(TCGv ret, TCGv_i64 arg) -+{ -+ tcg_gen_ext32s_i64(ret, arg); -+} -+ -+/* Sign-extract the high 32-bits to a target_long. */ -+static inline void gen_move_high32(TCGv ret, TCGv_i64 arg) -+{ -+ tcg_gen_sari_i64(ret, arg, 32); -+} -+ -+static inline void check_cp1_enabled(DisasContext *ctx) -+{ -+#ifndef CONFIG_USER_ONLY -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_FPU))) { -+ generate_exception_err(ctx, EXCP_FPDIS, 1); -+ } -+#endif -+} -+ -+static inline void check_lsx_enabled(DisasContext *ctx) -+{ -+#ifndef CONFIG_USER_ONLY -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_LSX))) { -+ generate_exception_err(ctx, EXCP_LSXDIS, 1); -+ } -+#endif -+} -+ -+static inline void check_lasx_enabled(DisasContext *ctx) -+{ -+#ifndef CONFIG_USER_ONLY -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_LASX))) { -+ generate_exception_err(ctx, EXCP_LASXDIS, 1); -+ } -+#endif -+} -+ -+static inline void check_lbt_enabled(DisasContext *ctx) -+{ -+#ifndef CONFIG_USER_ONLY -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_LBT))) { -+ generate_exception_err(ctx, EXCP_BTDIS, 1); -+ } -+#endif -+} -+ -+/* This code generates a "reserved instruction" exception if the -+ CPU does not support the instruction set corresponding to flags. */ -+static inline void check_insn(DisasContext *ctx, uint64_t flags) -+{ -+ if (unlikely(!(ctx->insn_flags & flags))) { -+ generate_exception_end(ctx, EXCP_RI); -+ } -+} -+ -+/* This code generates a "reserved instruction" exception if the -+ CPU has corresponding flag set which indicates that the instruction -+ has been removed. */ -+static inline void check_insn_opc_removed(DisasContext *ctx, uint64_t flags) -+{ -+ if (unlikely(ctx->insn_flags & flags)) { -+ generate_exception_end(ctx, EXCP_RI); -+ } -+} -+ -+/* -+ * The Linux kernel traps certain reserved instruction exceptions to -+ * emulate the corresponding instructions. QEMU is the kernel in user -+ * mode, so those traps are emulated by accepting the instructions. -+ * -+ * A reserved instruction exception is generated for flagged CPUs if -+ * QEMU runs in system mode. -+ */ -+static inline void check_insn_opc_user_only(DisasContext *ctx, uint64_t flags) -+{ -+#ifndef CONFIG_USER_ONLY -+ check_insn_opc_removed(ctx, flags); -+#endif -+} -+ -+/* This code generates a "reserved instruction" exception if 64-bit -+ instructions are not enabled. */ -+static inline void check_larch_64(DisasContext *ctx) -+{ -+ if (unlikely(!(ctx->hflags & LARCH_HFLAG_64))) { -+ generate_exception_end(ctx, EXCP_RI); -+ } -+} -+ -+/* Define small wrappers for gen_load_fpr* so that we have a uniform -+ calling interface for 32 and 64-bit FPRs. No sense in changing -+ all callers for gen_load_fpr32 when we need the CTX parameter for -+ this one use. */ -+#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(ctx, x, y) -+#define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y) -+#define FCOP_CONDNS(fmt, ifmt, bits, STORE) \ -+static inline void gen_fcmp_ ## fmt(DisasContext *ctx, int n, \ -+ int ft, int fs, int cd) \ -+{ \ -+ TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \ -+ TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \ -+ TCGv_i32 fcc = tcg_const_i32(cd); \ -+ check_cp1_enabled(ctx); \ -+ gen_ldcmp_fpr ## bits(ctx, fp0, fs); \ -+ gen_ldcmp_fpr ## bits(ctx, fp1, ft); \ -+ switch (n) { \ -+ case 0: \ -+ gen_helper_cmp_ ## fmt ## _af(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 1: \ -+ gen_helper_cmp_ ## fmt ## _saf(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 2: \ -+ gen_helper_cmp_ ## fmt ## _lt(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 3: \ -+ gen_helper_cmp_ ## fmt ## _slt(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 4: \ -+ gen_helper_cmp_ ## fmt ## _eq(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 5: \ -+ gen_helper_cmp_ ## fmt ## _seq(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 6: \ -+ gen_helper_cmp_ ## fmt ## _le(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 7: \ -+ gen_helper_cmp_ ## fmt ## _sle(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 8: \ -+ gen_helper_cmp_ ## fmt ## _un(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 9: \ -+ gen_helper_cmp_ ## fmt ## _sun(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 10: \ -+ gen_helper_cmp_ ## fmt ## _ult(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 11: \ -+ gen_helper_cmp_ ## fmt ## _sult(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 12: \ -+ gen_helper_cmp_ ## fmt ## _ueq(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 13: \ -+ gen_helper_cmp_ ## fmt ## _sueq(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 14: \ -+ gen_helper_cmp_ ## fmt ## _ule(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 15: \ -+ gen_helper_cmp_ ## fmt ## _sule(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 16: \ -+ gen_helper_cmp_ ## fmt ## _ne(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 17: \ -+ gen_helper_cmp_ ## fmt ## _sne(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 20: \ -+ gen_helper_cmp_ ## fmt ## _or(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 21: \ -+ gen_helper_cmp_ ## fmt ## _sor(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 24: \ -+ gen_helper_cmp_ ## fmt ## _une(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ case 25: \ -+ gen_helper_cmp_ ## fmt ## _sune(fp0, cpu_env, fp0, fp1); \ -+ break; \ -+ default: \ -+ abort(); \ -+ } \ -+ STORE; \ -+ tcg_temp_free_i ## bits(fp0); \ -+ tcg_temp_free_i ## bits(fp1); \ -+ tcg_temp_free_i32(fcc); \ -+} -+ -+FCOP_CONDNS(d, FMT_D, 64, gen_helper_movreg2cf_i64(cpu_env, fcc, fp0)) -+FCOP_CONDNS(s, FMT_S, 32, gen_helper_movreg2cf_i32(cpu_env, fcc, fp0)) -+#undef FCOP_CONDNS -+#undef gen_ldcmp_fpr32 -+#undef gen_ldcmp_fpr64 -+ -+/* load/store instructions. */ -+#ifdef CONFIG_USER_ONLY -+#define OP_LD_ATOMIC(insn, fname) \ -+static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \ -+ DisasContext *ctx) \ -+{ \ -+ TCGv t0 = tcg_temp_new(); \ -+ tcg_gen_mov_tl(t0, arg1); \ -+ tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ -+ tcg_gen_st_tl(t0, cpu_env, \ -+ offsetof(CPULOONGARCHState, lladdr)); \ -+ tcg_gen_st_tl(ret, cpu_env, \ -+ offsetof(CPULOONGARCHState, llval)); \ -+ tcg_temp_free(t0); \ -+} -+#else -+#define OP_LD_ATOMIC(insn, fname) \ -+static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \ -+ DisasContext *ctx) \ -+{ \ -+ gen_helper_1e1i(insn, ret, arg1, mem_idx); \ -+} -+#endif -+#if 0 -+OP_LD_ATOMIC(ll, ld32s); -+OP_LD_ATOMIC(lld, ld64); -+#endif -+#undef OP_LD_ATOMIC -+ -+static void gen_base_offset_addr(DisasContext *ctx, TCGv addr, -+ int base, int offset) -+{ -+ if (base == 0) { -+ tcg_gen_movi_tl(addr, offset); -+ } else if (offset == 0) { -+ gen_load_gpr(addr, base); -+ } else { -+ tcg_gen_movi_tl(addr, offset); -+ gen_op_addr_add(ctx, addr, cpu_gpr[base], addr); -+ } -+} -+ -+/* Load */ -+static void gen_ld(DisasContext *ctx, uint32_t opc, -+ int rt, int base, int offset) -+{ -+ TCGv t0; -+ int mem_idx = ctx->mem_idx; -+ -+ t0 = tcg_temp_new(); -+ gen_base_offset_addr(ctx, t0, base, offset); -+ -+ switch (opc) { -+ case OPC_LARCH_LD_WU: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LDPTR_D: -+ case OPC_LARCH_LD_D: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LL_D: -+#if 0 -+ op_ld_lld(t0, t0, mem_idx, ctx); -+#endif -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LDPTR_W: -+ case OPC_LARCH_LD_W: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESL | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LD_H: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESW | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LD_HU: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUW | -+ ctx->default_tcg_memop_mask); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LD_B: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_SB); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LD_BU: -+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_UB); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_LL_W: -+#if 0 -+ op_ld_ll(t0, t0, mem_idx, ctx); -+#endif -+ gen_store_gpr(t0, rt); -+ break; -+ } -+ -+ tcg_temp_free(t0); -+} -+ -+/* Store */ -+static void gen_st(DisasContext *ctx, uint32_t opc, int rt, -+ int base, int offset) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ int mem_idx = ctx->mem_idx; -+ -+ gen_base_offset_addr(ctx, t0, base, offset); -+ gen_load_gpr(t1, rt); -+ -+ switch (opc) { -+ case OPC_LARCH_STPTR_D: -+ case OPC_LARCH_ST_D: -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ break; -+ case OPC_LARCH_STPTR_W: -+ case OPC_LARCH_ST_W: -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ break; -+ case OPC_LARCH_ST_H: -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUW | -+ ctx->default_tcg_memop_mask); -+ break; -+ case OPC_LARCH_ST_B: -+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_8); -+ break; -+ } -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+/* Store conditional */ -+static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset, -+ MemOp tcg_mo, bool eva) -+{ -+ TCGv addr, t0, val; -+ TCGLabel *l1 = gen_new_label(); -+ TCGLabel *done = gen_new_label(); -+ -+ t0 = tcg_temp_new(); -+ addr = tcg_temp_new(); -+ /* compare the address against that of the preceeding LL */ -+ gen_base_offset_addr(ctx, addr, base, offset); -+ tcg_gen_brcond_tl(TCG_COND_EQ, addr, cpu_lladdr, l1); -+ tcg_temp_free(addr); -+ tcg_gen_movi_tl(t0, 0); -+ gen_store_gpr(t0, rt); -+ tcg_gen_br(done); -+ -+ gen_set_label(l1); -+ /* generate cmpxchg */ -+ val = tcg_temp_new(); -+ gen_load_gpr(val, rt); -+ tcg_gen_atomic_cmpxchg_tl(t0, cpu_lladdr, cpu_llval, val, -+ eva ? LARCH_HFLAG_UM : ctx->mem_idx, tcg_mo); -+ tcg_gen_setcond_tl(TCG_COND_EQ, t0, t0, cpu_llval); -+ gen_store_gpr(t0, rt); -+ tcg_temp_free(val); -+ -+ gen_set_label(done); -+ tcg_temp_free(t0); -+} -+ -+/* Load and store */ -+static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft, -+ TCGv t0) -+{ -+ /* Don't do NOP if destination is zero: we must perform the actual -+ memory access. */ -+ switch (opc) { -+ case OPC_LARCH_FLD_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL | -+ ctx->default_tcg_memop_mask); -+ gen_store_fpr32(ctx, fp0, ft); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FST_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, ft); -+ tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FLD_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ gen_store_fpr64(ctx, fp0, ft); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FST_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, ft); -+ tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ | -+ ctx->default_tcg_memop_mask); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ default: -+ LARCH_INVAL("flt_ldst"); -+ generate_exception_end(ctx, EXCP_RI); -+ break; -+ } -+} -+ -+static void gen_fp_ldst(DisasContext *ctx, uint32_t op, int rt, -+ int rs, int16_t imm) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ check_cp1_enabled(ctx); -+ gen_base_offset_addr(ctx, t0, rs, imm); -+ gen_flt_ldst(ctx, op, rt, t0); -+ tcg_temp_free(t0); -+} -+ -+/* Arithmetic with immediate operand */ -+static void gen_arith_imm(DisasContext *ctx, uint32_t opc, -+ int rt, int rs, int imm) -+{ -+ target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ -+ -+ if (rt == 0) { -+ /* If no destination, treat it as a NOP. -+ For addi, we must generate the overflow exception when needed. */ -+ return; -+ } -+ switch (opc) { -+ case OPC_LARCH_ADDI_W: -+ if (rs != 0) { -+ tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], uimm); -+ } -+ break; -+ case OPC_LARCH_ADDI_D: -+ if (rs != 0) { -+ tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], uimm); -+ } -+ break; -+ } -+} -+ -+/* Logic with immediate operand */ -+static void gen_logic_imm(DisasContext *ctx, uint32_t opc, -+ int rt, int rs, int16_t imm) -+{ -+ target_ulong uimm; -+ -+ if (rt == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ uimm = (uint16_t)imm; -+ switch (opc) { -+ case OPC_LARCH_ANDI: -+ if (likely(rs != 0)) { -+ tcg_gen_andi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], 0); -+ } -+ break; -+ case OPC_LARCH_ORI: -+ if (rs != 0) { -+ tcg_gen_ori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], uimm); -+ } -+ break; -+ case OPC_LARCH_XORI: -+ if (likely(rs != 0)) { -+ tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rt], uimm); -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+/* Set on less than with immediate operand */ -+static void gen_slt_imm(DisasContext *ctx, uint32_t opc, -+ int rt, int rs, int16_t imm) -+{ -+ target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ -+ TCGv t0; -+ -+ if (rt == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ switch (opc) { -+ case OPC_LARCH_SLTI: -+ tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rt], t0, uimm); -+ break; -+ case OPC_LARCH_SLTIU: -+ tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, uimm); -+ break; -+ } -+ tcg_temp_free(t0); -+} -+ -+/* Shifts with immediate operand */ -+static void gen_shift_imm(DisasContext *ctx, uint32_t opc, -+ int rt, int rs, int16_t imm) -+{ -+ target_ulong uimm = ((uint16_t)imm) & 0x1f; -+ TCGv t0; -+ -+ if (rt == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ switch (opc) { -+ case OPC_LARCH_SRAI_W: -+ tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm); -+ break; -+ case OPC_LARCH_SRLI_W: -+ if (uimm != 0) { -+ tcg_gen_ext32u_tl(t0, t0); -+ tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm); -+ } else { -+ tcg_gen_ext32s_tl(cpu_gpr[rt], t0); -+ } -+ break; -+ case OPC_LARCH_ROTRI_W: -+ if (uimm != 0) { -+ TCGv_i32 t1 = tcg_temp_new_i32(); -+ -+ tcg_gen_trunc_tl_i32(t1, t0); -+ tcg_gen_rotri_i32(t1, t1, uimm); -+ tcg_gen_ext_i32_tl(cpu_gpr[rt], t1); -+ tcg_temp_free_i32(t1); -+ } else { -+ tcg_gen_ext32s_tl(cpu_gpr[rt], t0); -+ } -+ break; -+ } -+ tcg_temp_free(t0); -+} -+ -+/* Arithmetic */ -+static void gen_arith(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. -+ For add & sub, we must generate the -+ overflow exception when needed. */ -+ return; -+ } -+ -+ switch (opc) { -+ case OPC_LARCH_ADD_W: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_SUB_W: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_ADD_D: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_SUB_D: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ } -+} -+ -+/* Conditional move */ -+static void gen_cond_move(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ TCGv t0, t1, t2; -+ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rt); -+ t1 = tcg_const_tl(0); -+ t2 = tcg_temp_new(); -+ gen_load_gpr(t2, rs); -+ switch (opc) { -+ case OPC_LARCH_MASKEQZ: -+ tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[rd], t0, t1, t2, t1); -+ break; -+ case OPC_LARCH_MASKNEZ: -+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr[rd], t0, t1, t2, t1); -+ break; -+ } -+ tcg_temp_free(t2); -+ tcg_temp_free(t1); -+ tcg_temp_free(t0); -+} -+ -+/* Logic */ -+static void gen_logic(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ switch (opc) { -+ case OPC_LARCH_AND: -+ if (likely(rs != 0 && rt != 0)) { -+ tcg_gen_and_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_NOR: -+ if (rs != 0 && rt != 0) { -+ tcg_gen_nor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], ~((target_ulong)0)); -+ } -+ break; -+ case OPC_LARCH_OR: -+ if (likely(rs != 0 && rt != 0)) { -+ tcg_gen_or_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ case OPC_LARCH_XOR: -+ if (likely(rs != 0 && rt != 0)) { -+ tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); -+ } else if (rs == 0 && rt != 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); -+ } else if (rs != 0 && rt == 0) { -+ tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); -+ } else { -+ tcg_gen_movi_tl(cpu_gpr[rd], 0); -+ } -+ break; -+ } -+} -+ -+/* Set on lower than */ -+static void gen_slt(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ TCGv t0, t1; -+ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ switch (opc) { -+ case OPC_LARCH_SLT: -+ tcg_gen_setcond_tl(TCG_COND_LT, cpu_gpr[rd], t0, t1); -+ break; -+ case OPC_LARCH_SLTU: -+ tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t0, t1); -+ break; -+ } -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+/* Shifts */ -+static void gen_shift(DisasContext *ctx, uint32_t opc, -+ int rd, int rs, int rt) -+{ -+ TCGv t0, t1; -+ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. -+ For add & sub, we must generate the -+ overflow exception when needed. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ switch (opc) { -+ case OPC_LARCH_SLL_W: -+ tcg_gen_andi_tl(t0, t0, 0x1f); -+ tcg_gen_shl_tl(t0, t1, t0); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_SRA_W: -+ tcg_gen_andi_tl(t0, t0, 0x1f); -+ tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); -+ break; -+ case OPC_LARCH_SRL_W: -+ tcg_gen_ext32u_tl(t1, t1); -+ tcg_gen_andi_tl(t0, t0, 0x1f); -+ tcg_gen_shr_tl(t0, t1, t0); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_ROTR_W: -+ { -+ TCGv_i32 t2 = tcg_temp_new_i32(); -+ TCGv_i32 t3 = tcg_temp_new_i32(); -+ -+ tcg_gen_trunc_tl_i32(t2, t0); -+ tcg_gen_trunc_tl_i32(t3, t1); -+ tcg_gen_andi_i32(t2, t2, 0x1f); -+ tcg_gen_rotr_i32(t2, t3, t2); -+ tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); -+ tcg_temp_free_i32(t2); -+ tcg_temp_free_i32(t3); -+ } -+ break; -+ case OPC_LARCH_SLL_D: -+ tcg_gen_andi_tl(t0, t0, 0x3f); -+ tcg_gen_shl_tl(cpu_gpr[rd], t1, t0); -+ break; -+ case OPC_LARCH_SRA_D: -+ tcg_gen_andi_tl(t0, t0, 0x3f); -+ tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); -+ break; -+ case OPC_LARCH_SRL_D: -+ tcg_gen_andi_tl(t0, t0, 0x3f); -+ tcg_gen_shr_tl(cpu_gpr[rd], t1, t0); -+ break; -+ case OPC_LARCH_ROTR_D: -+ tcg_gen_andi_tl(t0, t0, 0x3f); -+ tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0); -+ break; -+ } -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+static inline void gen_r6_ld(target_long addr, int reg, int memidx, -+ MemOp memop) -+{ -+ TCGv t0 = tcg_const_tl(addr); -+ tcg_gen_qemu_ld_tl(t0, t0, memidx, memop); -+ gen_store_gpr(t0, reg); -+ tcg_temp_free(t0); -+} -+ -+static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt) -+{ -+ TCGv t0, t1; -+ -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ -+ switch (opc) { -+ case OPC_LARCH_DIV_W: -+ { -+ TCGv t2 = tcg_temp_new(); -+ TCGv t3 = tcg_temp_new(); -+ tcg_gen_ext32s_tl(t0, t0); -+ tcg_gen_ext32s_tl(t1, t1); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); -+ tcg_gen_and_tl(t2, t2, t3); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); -+ tcg_gen_or_tl(t2, t2, t3); -+ tcg_gen_movi_tl(t3, 0); -+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); -+ tcg_gen_div_tl(cpu_gpr[rd], t0, t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MOD_W: -+ { -+ TCGv t2 = tcg_temp_new(); -+ TCGv t3 = tcg_temp_new(); -+ tcg_gen_ext32s_tl(t0, t0); -+ tcg_gen_ext32s_tl(t1, t1); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); -+ tcg_gen_and_tl(t2, t2, t3); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); -+ tcg_gen_or_tl(t2, t2, t3); -+ tcg_gen_movi_tl(t3, 0); -+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); -+ tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_DIV_WU: -+ { -+ TCGv t2 = tcg_const_tl(0); -+ TCGv t3 = tcg_const_tl(1); -+ tcg_gen_ext32u_tl(t0, t0); -+ tcg_gen_ext32u_tl(t1, t1); -+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); -+ tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MOD_WU: -+ { -+ TCGv t2 = tcg_const_tl(0); -+ TCGv t3 = tcg_const_tl(1); -+ tcg_gen_ext32u_tl(t0, t0); -+ tcg_gen_ext32u_tl(t1, t1); -+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); -+ tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MUL_W: -+ { -+ TCGv_i32 t2 = tcg_temp_new_i32(); -+ TCGv_i32 t3 = tcg_temp_new_i32(); -+ tcg_gen_trunc_tl_i32(t2, t0); -+ tcg_gen_trunc_tl_i32(t3, t1); -+ tcg_gen_mul_i32(t2, t2, t3); -+ tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); -+ tcg_temp_free_i32(t2); -+ tcg_temp_free_i32(t3); -+ } -+ break; -+ case OPC_LARCH_MULH_W: -+ { -+ TCGv_i32 t2 = tcg_temp_new_i32(); -+ TCGv_i32 t3 = tcg_temp_new_i32(); -+ tcg_gen_trunc_tl_i32(t2, t0); -+ tcg_gen_trunc_tl_i32(t3, t1); -+ tcg_gen_muls2_i32(t2, t3, t2, t3); -+ tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); -+ tcg_temp_free_i32(t2); -+ tcg_temp_free_i32(t3); -+ } -+ break; -+ case OPC_LARCH_MULH_WU: -+ { -+ TCGv_i32 t2 = tcg_temp_new_i32(); -+ TCGv_i32 t3 = tcg_temp_new_i32(); -+ tcg_gen_trunc_tl_i32(t2, t0); -+ tcg_gen_trunc_tl_i32(t3, t1); -+ tcg_gen_mulu2_i32(t2, t3, t2, t3); -+ tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); -+ tcg_temp_free_i32(t2); -+ tcg_temp_free_i32(t3); -+ } -+ break; -+ case OPC_LARCH_DIV_D: -+ { -+ TCGv t2 = tcg_temp_new(); -+ TCGv t3 = tcg_temp_new(); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); -+ tcg_gen_and_tl(t2, t2, t3); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); -+ tcg_gen_or_tl(t2, t2, t3); -+ tcg_gen_movi_tl(t3, 0); -+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); -+ tcg_gen_div_tl(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MOD_D: -+ { -+ TCGv t2 = tcg_temp_new(); -+ TCGv t3 = tcg_temp_new(); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); -+ tcg_gen_and_tl(t2, t2, t3); -+ tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); -+ tcg_gen_or_tl(t2, t2, t3); -+ tcg_gen_movi_tl(t3, 0); -+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); -+ tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_DIV_DU: -+ { -+ TCGv t2 = tcg_const_tl(0); -+ TCGv t3 = tcg_const_tl(1); -+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); -+ tcg_gen_divu_i64(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MOD_DU: -+ { -+ TCGv t2 = tcg_const_tl(0); -+ TCGv t3 = tcg_const_tl(1); -+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); -+ tcg_gen_remu_i64(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t3); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MUL_D: -+ tcg_gen_mul_i64(cpu_gpr[rd], t0, t1); -+ break; -+ case OPC_LARCH_MULH_D: -+ { -+ TCGv t2 = tcg_temp_new(); -+ tcg_gen_muls2_i64(t2, cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t2); -+ } -+ break; -+ case OPC_LARCH_MULH_DU: -+ { -+ TCGv t2 = tcg_temp_new(); -+ tcg_gen_mulu2_i64(t2, cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t2); -+ } -+ break; -+ default: -+ LARCH_INVAL("r6 mul/div"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ out: -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+static void gen_cl(DisasContext *ctx, uint32_t opc, -+ int rd, int rs) -+{ -+ TCGv t0; -+ -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = cpu_gpr[rd]; -+ gen_load_gpr(t0, rs); -+ -+ switch (opc) { -+ case OPC_LARCH_CLO_W: -+ case OPC_LARCH_CLO_D: -+ tcg_gen_not_tl(t0, t0); -+ break; -+ } -+ -+ switch (opc) { -+ case OPC_LARCH_CLO_W: -+ case OPC_LARCH_CLZ_W: -+ tcg_gen_ext32u_tl(t0, t0); -+ tcg_gen_clzi_tl(t0, t0, TARGET_LONG_BITS); -+ tcg_gen_subi_tl(t0, t0, TARGET_LONG_BITS - 32); -+ break; -+ case OPC_LARCH_CLO_D: -+ case OPC_LARCH_CLZ_D: -+ tcg_gen_clzi_i64(t0, t0, 64); -+ break; -+ } -+} -+ -+static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) -+{ -+ if (unlikely(ctx->base.singlestep_enabled)) { -+ return false; -+ } -+ -+#ifndef CONFIG_USER_ONLY -+ return (ctx->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); -+#else -+ return true; -+#endif -+} -+ -+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) -+{ -+ if (use_goto_tb(ctx, dest)) { -+ tcg_gen_goto_tb(n); -+ gen_save_pc(dest); -+ tcg_gen_exit_tb(ctx->base.tb, n); -+ } else { -+ gen_save_pc(dest); -+ if (ctx->base.singlestep_enabled) { -+ save_cpu_state(ctx, 0); -+ gen_helper_raise_exception_debug(cpu_env); -+ } -+ tcg_gen_lookup_and_goto_ptr(); -+ } -+} -+ -+/* Branches */ -+static void gen_compute_branch(DisasContext *ctx, uint32_t opc, -+ int insn_bytes, -+ int rs, int rt, int32_t offset) -+{ -+ target_ulong btgt = -1; -+ int bcond_compute = 0; -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ if (ctx->hflags & LARCH_HFLAG_BMASK) { -+#ifdef LARCH_DEBUG_DISAS -+ LOG_DISAS("Branch at PC 0x" -+ TARGET_FMT_lx "\n", ctx->base.pc_next); -+#endif -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ -+ /* Load needed operands */ -+ switch (opc) { -+ case OPC_LARCH_BLT: -+ case OPC_LARCH_BGE: -+ case OPC_LARCH_BLTU: -+ case OPC_LARCH_BGEU: -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ bcond_compute = 1; -+ btgt = ctx->base.pc_next + offset; -+ break; -+ case OPC_LARCH_BEQZ: -+ case OPC_LARCH_B: -+ case OPC_LARCH_BEQ: -+ case OPC_LARCH_BNEZ: -+ case OPC_LARCH_BNE: -+ /* Compare two registers */ -+ if (rs != rt) { -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ bcond_compute = 1; -+ } -+ btgt = ctx->base.pc_next + offset; -+ break; -+ default: -+ LARCH_INVAL("branch/jump"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ if (bcond_compute == 0) { -+ /* No condition to be computed */ -+ switch (opc) { -+ case OPC_LARCH_BEQZ: /* rx == rx */ -+ case OPC_LARCH_B: -+ case OPC_LARCH_BEQ: -+ /* Always take */ -+ ctx->hflags |= LARCH_HFLAG_B; -+ break; -+ case OPC_LARCH_BNEZ: -+ case OPC_LARCH_BNE: -+ /* Treat as NOP. */ -+ goto out; -+ default: -+ LARCH_INVAL("branch/jump"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ } else { -+ switch (opc) { -+ case OPC_LARCH_BLT: -+ tcg_gen_setcond_tl(TCG_COND_LT, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BGE: -+ tcg_gen_setcond_tl(TCG_COND_GE, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BLTU: -+ tcg_gen_setcond_tl(TCG_COND_LTU, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BGEU: -+ tcg_gen_setcond_tl(TCG_COND_GEU, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BEQZ: -+ case OPC_LARCH_B: -+ case OPC_LARCH_BEQ: -+ tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); -+ goto not_likely; -+ case OPC_LARCH_BNEZ: -+ case OPC_LARCH_BNE: -+ tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); -+ goto not_likely; -+ not_likely: -+ ctx->hflags |= LARCH_HFLAG_BC; -+ break; -+ default: -+ LARCH_INVAL("conditional branch/jump"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ } -+ -+ ctx->btarget = btgt; -+ -+ out: -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+/* special3 bitfield operations */ -+static void gen_bitops(DisasContext *ctx, uint32_t opc, int rt, -+ int rs, int lsb, int msb) -+{ -+ TCGv t0 = tcg_temp_new(); -+ TCGv t1 = tcg_temp_new(); -+ -+ gen_load_gpr(t1, rs); -+ switch (opc) { -+ case OPC_LARCH_TRPICK_W: -+ if (lsb + msb > 31) { -+ goto fail; -+ } -+ if (msb != 31) { -+ tcg_gen_extract_tl(t0, t1, lsb, msb + 1); -+ } else { -+ /* -+ * The two checks together imply that lsb == 0, -+ * so this is a simple sign-extension. -+ */ -+ tcg_gen_ext32s_tl(t0, t1); -+ } -+ break; -+ case OPC_LARCH_TRINS_W: -+ if (lsb > msb) { -+ goto fail; -+ } -+ gen_load_gpr(t0, rt); -+ tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); -+ tcg_gen_ext32s_tl(t0, t0); -+ break; -+ default: -+fail: -+ LARCH_INVAL("bitops"); -+ generate_exception_end(ctx, EXCP_RI); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ return; -+ } -+ gen_store_gpr(t0, rt); -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+} -+ -+static void gen_bshfl(DisasContext *ctx, uint32_t op2, int rt, int rd) -+{ -+ TCGv t0; -+ -+ if (rd == 0) { -+ /* If no destination, treat it as a NOP. */ -+ return; -+ } -+ -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rt); -+ switch (op2) { -+ case OPC_LARCH_REVB_2H: -+ { -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_const_tl(0x00FF00FF); -+ -+ tcg_gen_shri_tl(t1, t0, 8); -+ tcg_gen_and_tl(t1, t1, t2); -+ tcg_gen_and_tl(t0, t0, t2); -+ tcg_gen_shli_tl(t0, t0, 8); -+ tcg_gen_or_tl(t0, t0, t1); -+ tcg_temp_free(t2); -+ tcg_temp_free(t1); -+ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); -+ } -+ break; -+ case OPC_LARCH_EXT_WB: -+ tcg_gen_ext8s_tl(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_EXT_WH: -+ tcg_gen_ext16s_tl(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_REVB_4H: -+ { -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_const_tl(0x00FF00FF00FF00FFULL); -+ -+ tcg_gen_shri_tl(t1, t0, 8); -+ tcg_gen_and_tl(t1, t1, t2); -+ tcg_gen_and_tl(t0, t0, t2); -+ tcg_gen_shli_tl(t0, t0, 8); -+ tcg_gen_or_tl(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t2); -+ tcg_temp_free(t1); -+ } -+ break; -+ case OPC_LARCH_REVH_D: -+ { -+ TCGv t1 = tcg_temp_new(); -+ TCGv t2 = tcg_const_tl(0x0000FFFF0000FFFFULL); -+ -+ tcg_gen_shri_tl(t1, t0, 16); -+ tcg_gen_and_tl(t1, t1, t2); -+ tcg_gen_and_tl(t0, t0, t2); -+ tcg_gen_shli_tl(t0, t0, 16); -+ tcg_gen_or_tl(t0, t0, t1); -+ tcg_gen_shri_tl(t1, t0, 32); -+ tcg_gen_shli_tl(t0, t0, 32); -+ tcg_gen_or_tl(cpu_gpr[rd], t0, t1); -+ tcg_temp_free(t2); -+ tcg_temp_free(t1); -+ } -+ break; -+ default: -+ LARCH_INVAL("bsfhl"); -+ generate_exception_end(ctx, EXCP_RI); -+ tcg_temp_free(t0); -+ return; -+ } -+ tcg_temp_free(t0); -+} -+ -+/* REV with sf==1, opcode==3 ("REV64") */ -+static void handle_rev64(DisasContext *ctx, -+ unsigned int rn, unsigned int rd) -+{ -+ tcg_gen_bswap64_i64(cpu_gpr[rd], cpu_gpr[rn]); -+} -+ -+/* REV with sf==0, opcode==2 -+ * REV32 (sf==1, opcode==2) -+ */ -+static void handle_rev32(DisasContext *ctx, -+ unsigned int rn, unsigned int rd) -+{ -+ TCGv_i64 tcg_rd = tcg_temp_new_i64(); -+ gen_load_gpr(tcg_rd, rd); -+ -+ TCGv_i64 tcg_tmp = tcg_temp_new_i64(); -+ TCGv_i64 tcg_rn = tcg_temp_new_i64(); -+ gen_load_gpr(tcg_rn, rn); -+ -+ /* bswap32_i64 requires zero high word */ -+ tcg_gen_ext32u_i64(tcg_tmp, tcg_rn); -+ tcg_gen_bswap32_i64(tcg_rd, tcg_tmp, TCG_BSWAP_OZ); -+ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32); -+ tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp, TCG_BSWAP_OZ); -+ tcg_gen_concat32_i64(cpu_gpr[rd], tcg_rd, tcg_tmp); -+ -+ tcg_temp_free_i64(tcg_tmp); -+ tcg_temp_free_i64(tcg_rd); -+ tcg_temp_free_i64(tcg_rn); -+} -+ -+/* REV16 */ -+static void handle_rev16(DisasContext *ctx, unsigned int rn, unsigned int rd) -+{ -+ TCGv_i64 tcg_rd = tcg_temp_new_i64(); -+ TCGv_i64 tcg_rn = tcg_temp_new_i64(); -+ gen_load_gpr(tcg_rd, rd); -+ gen_load_gpr(tcg_rn, rn); -+ TCGv_i64 tcg_tmp = tcg_temp_new_i64(); -+ TCGv_i64 mask = tcg_const_i64(0x0000ffff0000ffffull); -+ -+ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 16); -+ tcg_gen_and_i64(tcg_rd, tcg_rn, mask); -+ tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask); -+ tcg_gen_shli_i64(tcg_rd, tcg_rd, 16); -+ tcg_gen_or_i64(cpu_gpr[rd], tcg_rd, tcg_tmp); -+ -+ tcg_temp_free_i64(mask); -+ tcg_temp_free_i64(tcg_tmp); -+ tcg_temp_free_i64(tcg_rd); -+ tcg_temp_free_i64(tcg_rn); -+} -+ -+static void gen_lsa(DisasContext *ctx, int opc, int rd, int rs, int rt, -+ int imm2) -+{ -+ TCGv t0; -+ TCGv t1; -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ gen_load_gpr(t0, rs); -+ gen_load_gpr(t1, rt); -+ tcg_gen_shli_tl(t0, t0, imm2 + 1); -+ tcg_gen_add_tl(cpu_gpr[rd], t0, t1); -+ if (opc == OPC_LARCH_ALSL_W) { -+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); -+ } -+ -+ tcg_temp_free(t1); -+ tcg_temp_free(t0); -+ -+ return; -+} -+ -+static void gen_align_bits(DisasContext *ctx, int wordsz, int rd, int rs, -+ int rt, int bits) -+{ -+ TCGv t0; -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ if (bits == 0 || bits == wordsz) { -+ if (bits == 0) { -+ gen_load_gpr(t0, rt); -+ } else { -+ gen_load_gpr(t0, rs); -+ } -+ switch (wordsz) { -+ case 32: -+ tcg_gen_ext32s_tl(cpu_gpr[rd], t0); -+ break; -+ case 64: -+ tcg_gen_mov_tl(cpu_gpr[rd], t0); -+ break; -+ } -+ } else { -+ TCGv t1 = tcg_temp_new(); -+ gen_load_gpr(t0, rt); -+ gen_load_gpr(t1, rs); -+ switch (wordsz) { -+ case 32: -+ { -+ TCGv_i64 t2 = tcg_temp_new_i64(); -+ tcg_gen_concat_tl_i64(t2, t1, t0); -+ tcg_gen_shri_i64(t2, t2, 32 - bits); -+ gen_move_low32(cpu_gpr[rd], t2); -+ tcg_temp_free_i64(t2); -+ } -+ break; -+ case 64: -+ tcg_gen_shli_tl(t0, t0, bits); -+ tcg_gen_shri_tl(t1, t1, 64 - bits); -+ tcg_gen_or_tl(cpu_gpr[rd], t1, t0); -+ break; -+ } -+ tcg_temp_free(t1); -+ } -+ -+ tcg_temp_free(t0); -+} -+ -+static void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt, -+ int bp) -+{ -+ gen_align_bits(ctx, wordsz, rd, rs, rt, bp * 8); -+} -+ -+static void gen_bitswap(DisasContext *ctx, int opc, int rd, int rt) -+{ -+ TCGv t0; -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ gen_load_gpr(t0, rt); -+ switch (opc) { -+ case OPC_LARCH_BREV_4B: -+ gen_helper_bitswap(cpu_gpr[rd], t0); -+ break; -+ case OPC_LARCH_BREV_8B: -+ gen_helper_dbitswap(cpu_gpr[rd], t0); -+ break; -+ } -+ tcg_temp_free(t0); -+} -+ -+static void gen_cp1(DisasContext *ctx, uint32_t opc, int rt, int fs) -+{ -+ TCGv t0 = tcg_temp_new(); -+ check_cp1_enabled(ctx); -+ -+ switch (opc) { -+ case OPC_LARCH_FR2GR_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ tcg_gen_ext_i32_tl(t0, fp0); -+ tcg_temp_free_i32(fp0); -+ } -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_GR2FR_W: -+ gen_load_gpr(t0, rt); -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ tcg_gen_trunc_tl_i32(fp0, t0); -+ gen_store_fpr32(ctx, fp0, fs); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FR2GR_D: -+ gen_load_fpr64(ctx, t0, fs); -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_GR2FR_D: -+ gen_load_gpr(t0, rt); -+ gen_store_fpr64(ctx, t0, fs); -+ break; -+ case OPC_LARCH_FRH2GR_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32h(ctx, fp0, fs); -+ tcg_gen_ext_i32_tl(t0, fp0); -+ tcg_temp_free_i32(fp0); -+ } -+ gen_store_gpr(t0, rt); -+ break; -+ case OPC_LARCH_GR2FRH_W: -+ gen_load_gpr(t0, rt); -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ tcg_gen_trunc_tl_i32(fp0, t0); -+ gen_store_fpr32h(ctx, fp0, fs); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ default: -+ LARCH_INVAL("cp1 move"); -+ generate_exception_end(ctx, EXCP_RI); -+ goto out; -+ } -+ -+ out: -+ tcg_temp_free(t0); -+} -+ -+static inline void gen_movcf_ps(DisasContext *ctx, int fs, int fd, -+ int cc, int tf) -+{ -+ int cond; -+ TCGv_i32 t0 = tcg_temp_new_i32(); -+ TCGLabel *l1 = gen_new_label(); -+ TCGLabel *l2 = gen_new_label(); -+ -+ if (tf) { -+ cond = TCG_COND_EQ; -+ } else { -+ cond = TCG_COND_NE; -+ } -+ -+ tcg_gen_andi_i32(t0, fpu_fcsr0, 1 << get_fp_bit(cc)); -+ tcg_gen_brcondi_i32(cond, t0, 0, l1); -+ gen_load_fpr32(ctx, t0, fs); -+ gen_store_fpr32(ctx, t0, fd); -+ gen_set_label(l1); -+ -+ tcg_gen_andi_i32(t0, fpu_fcsr0, 1 << get_fp_bit(cc + 1)); -+ tcg_gen_brcondi_i32(cond, t0, 0, l2); -+ gen_load_fpr32h(ctx, t0, fs); -+ gen_store_fpr32h(ctx, t0, fd); -+ tcg_temp_free_i32(t0); -+ gen_set_label(l2); -+} -+ -+static void gen_farith(DisasContext *ctx, uint32_t opc, -+ int ft, int fs, int fd, int cc) -+{ -+ check_cp1_enabled(ctx); -+ switch (opc) { -+ case OPC_LARCH_FADD_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_add_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FSUB_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_sub_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMUL_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_mul_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FDIV_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_div_s(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i32(fp1); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FSQRT_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_sqrt_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FABS_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_abs_s(fp0, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMOV_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FNEG_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_chs_s(fp0, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRNE_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_round_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINTRZ_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_trunc_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINTRP_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_ceil_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINTRM_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_floor_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINTRNE_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_round_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRZ_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_trunc_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRP_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_ceil_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRM_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_floor_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FRECIP_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_recip_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FRSQRT_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_rsqrt_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FRINT_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_rint_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FCLASS_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_class_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMIN_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ TCGv_i32 fp2 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_min_s(fp2, cpu_env, fp0, fp1); -+ gen_store_fpr32(ctx, fp2, fd); -+ tcg_temp_free_i32(fp2); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMINA_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ TCGv_i32 fp2 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_mina_s(fp2, cpu_env, fp0, fp1); -+ gen_store_fpr32(ctx, fp2, fd); -+ tcg_temp_free_i32(fp2); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMAX_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_max_s(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr32(ctx, fp1, fd); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FMAXA_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ TCGv_i32 fp1 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_load_fpr32(ctx, fp1, ft); -+ gen_helper_float_maxa_s(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr32(ctx, fp1, fd); -+ tcg_temp_free_i32(fp1); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FCVT_D_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_cvtd_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FTINT_W_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_cvt_w_s(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINT_L_S: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_cvt_l_s(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FADD_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_add_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FSUB_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_sub_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMUL_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_mul_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FDIV_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_div_d(fp0, cpu_env, fp0, fp1); -+ tcg_temp_free_i64(fp1); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FSQRT_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_sqrt_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FABS_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_abs_d(fp0, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMOV_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FNEG_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_chs_d(fp0, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRNE_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_round_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRZ_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_trunc_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRP_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_ceil_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRM_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_floor_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FTINTRNE_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_round_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINTRZ_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_trunc_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINTRP_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_ceil_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINTRM_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_floor_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FRECIP_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_recip_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FRSQRT_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_rsqrt_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FRINT_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_rint_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FCLASS_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_class_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMIN_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_min_d(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr64(ctx, fp1, fd); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMINA_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_mina_d(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr64(ctx, fp1, fd); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMAX_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_max_d(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr64(ctx, fp1, fd); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FMAXA_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ TCGv_i64 fp1 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_load_fpr64(ctx, fp1, ft); -+ gen_helper_float_maxa_d(fp1, cpu_env, fp0, fp1); -+ gen_store_fpr64(ctx, fp1, fd); -+ tcg_temp_free_i64(fp1); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FCVT_S_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_cvts_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINT_W_D: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_cvt_w_d(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FTINT_L_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_cvt_l_d(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FFINT_S_W: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ gen_load_fpr32(ctx, fp0, fs); -+ gen_helper_float_cvts_w(fp0, cpu_env, fp0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FFINT_D_W: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr32(ctx, fp32, fs); -+ gen_helper_float_cvtd_w(fp64, cpu_env, fp32); -+ tcg_temp_free_i32(fp32); -+ gen_store_fpr64(ctx, fp64, fd); -+ tcg_temp_free_i64(fp64); -+ } -+ break; -+ case OPC_LARCH_FFINT_S_L: -+ { -+ TCGv_i32 fp32 = tcg_temp_new_i32(); -+ TCGv_i64 fp64 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp64, fs); -+ gen_helper_float_cvts_l(fp32, cpu_env, fp64); -+ tcg_temp_free_i64(fp64); -+ gen_store_fpr32(ctx, fp32, fd); -+ tcg_temp_free_i32(fp32); -+ } -+ break; -+ case OPC_LARCH_FFINT_D_L: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ -+ gen_load_fpr64(ctx, fp0, fs); -+ gen_helper_float_cvtd_l(fp0, cpu_env, fp0); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ default: -+ LARCH_INVAL("farith"); -+ generate_exception_end(ctx, EXCP_RI); -+ return; -+ } -+} -+ -+/* Coprocessor 3 (FPU) */ -+static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc, -+ int fd, int fs, int base, int index) -+{ -+ TCGv t0 = tcg_temp_new(); -+ -+ check_cp1_enabled(ctx); -+ if (base == 0) { -+ gen_load_gpr(t0, index); -+ } else if (index == 0) { -+ gen_load_gpr(t0, base); -+ } else { -+ gen_op_addr_add(ctx, t0, cpu_gpr[base], cpu_gpr[index]); -+ } -+ -+ /* -+ * Don't do NOP if destination is zero: we must perform the actual -+ * memory access. -+ */ -+ switch (opc) { -+ case OPC_LARCH_FLDX_S: -+ case OPC_LARCH_FLDGT_S: -+ case OPC_LARCH_FLDLE_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ -+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL); -+ tcg_gen_trunc_tl_i32(fp0, t0); -+ gen_store_fpr32(ctx, fp0, fd); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FLDX_D: -+ case OPC_LARCH_FLDGT_D: -+ case OPC_LARCH_FLDLE_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ); -+ gen_store_fpr64(ctx, fp0, fd); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ case OPC_LARCH_FSTX_S: -+ case OPC_LARCH_FSTGT_S: -+ case OPC_LARCH_FSTLE_S: -+ { -+ TCGv_i32 fp0 = tcg_temp_new_i32(); -+ gen_load_fpr32(ctx, fp0, fs); -+ tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL); -+ tcg_temp_free_i32(fp0); -+ } -+ break; -+ case OPC_LARCH_FSTX_D: -+ case OPC_LARCH_FSTGT_D: -+ case OPC_LARCH_FSTLE_D: -+ { -+ TCGv_i64 fp0 = tcg_temp_new_i64(); -+ gen_load_fpr64(ctx, fp0, fs); -+ tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ); -+ tcg_temp_free_i64(fp0); -+ } -+ break; -+ } -+ tcg_temp_free(t0); -+} -+ -+static inline void clear_branch_hflags(DisasContext *ctx) -+{ -+ ctx->hflags &= ~LARCH_HFLAG_BMASK; -+ if (ctx->base.is_jmp == DISAS_NEXT) { -+ save_cpu_state(ctx, 0); -+ } else { -+ /* -+ * It is not safe to save ctx->hflags as hflags may be changed -+ * in execution time. -+ */ -+ tcg_gen_andi_i32(hflags, hflags, ~LARCH_HFLAG_BMASK); -+ } -+} -+ -+static void gen_branch(DisasContext *ctx, int insn_bytes) -+{ -+ if (ctx->hflags & LARCH_HFLAG_BMASK) { -+ int proc_hflags = ctx->hflags & LARCH_HFLAG_BMASK; -+ /* Branches completion */ -+ clear_branch_hflags(ctx); -+ ctx->base.is_jmp = DISAS_NORETURN; -+ /* FIXME: Need to clear can_do_io. */ -+ switch (proc_hflags & LARCH_HFLAG_BMASK) { -+ case LARCH_HFLAG_B: -+ /* unconditional branch */ -+ gen_goto_tb(ctx, 0, ctx->btarget); -+ break; -+ case LARCH_HFLAG_BC: -+ /* Conditional branch */ -+ { -+ TCGLabel *l1 = gen_new_label(); -+ -+ tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1); -+ gen_goto_tb(ctx, 1, ctx->base.pc_next + insn_bytes); -+ gen_set_label(l1); -+ gen_goto_tb(ctx, 0, ctx->btarget); -+ } -+ break; -+ case LARCH_HFLAG_BR: -+ /* unconditional branch to register */ -+ tcg_gen_mov_tl(cpu_PC, btarget); -+ if (ctx->base.singlestep_enabled) { -+ save_cpu_state(ctx, 0); -+ gen_helper_raise_exception_debug(cpu_env); -+ } -+ tcg_gen_lookup_and_goto_ptr(); -+ break; -+ default: -+ fprintf(stderr, "unknown branch 0x%x\n", proc_hflags); -+ abort(); -+ } -+ } -+} -+ -+/* Signed immediate */ -+#define SIMM(op, start, width) \ -+ ((int32_t)(((op >> start) & ((~0U) >> (32 - width))) \ -+ << (32 - width)) \ -+ >> (32 - width)) -+/* Zero-extended immediate */ -+#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32 - width))) -+ -+static void gen_sync(int stype) -+{ -+ TCGBar tcg_mo = TCG_BAR_SC; -+ -+ switch (stype) { -+ case 0x4: /* SYNC_WMB */ -+ tcg_mo |= TCG_MO_ST_ST; -+ break; -+ case 0x10: /* SYNC_MB */ -+ tcg_mo |= TCG_MO_ALL; -+ break; -+ case 0x11: /* SYNC_ACQUIRE */ -+ tcg_mo |= TCG_MO_LD_LD | TCG_MO_LD_ST; -+ break; -+ case 0x12: /* SYNC_RELEASE */ -+ tcg_mo |= TCG_MO_ST_ST | TCG_MO_LD_ST; -+ break; -+ case 0x13: /* SYNC_RMB */ -+ tcg_mo |= TCG_MO_LD_LD; -+ break; -+ default: -+ tcg_mo |= TCG_MO_ALL; -+ break; -+ } -+ -+ tcg_gen_mb(tcg_mo); -+} -+ -+static void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz, -+ int crc32c) -+{ -+ TCGv t0; -+ TCGv t1; -+ TCGv_i32 tsz = tcg_const_i32(1 << sz); -+ if (rd == 0) { -+ /* Treat as NOP. */ -+ return; -+ } -+ t0 = tcg_temp_new(); -+ t1 = tcg_temp_new(); -+ -+ gen_load_gpr(t0, rt); -+ gen_load_gpr(t1, rs); -+ -+ if (crc32c) { -+ gen_helper_crc32c(cpu_gpr[rd], t0, t1, tsz); -+ } else { -+ gen_helper_crc32(cpu_gpr[rd], t0, t1, tsz); -+ } -+ -+ tcg_temp_free(t0); -+ tcg_temp_free(t1); -+ tcg_temp_free_i32(tsz); -+} -+ -+#include "cpu-csr.h" -+ -+#ifndef CONFIG_USER_ONLY -+ -+/* -+ * 64-bit CSR read -+ * -+ * @arg : GPR to store the value of CSR register -+ * @csr : CSR register number -+ */ -+static void gen_csr_rdq(DisasContext *ctx, TCGv rd, int64_t a1) -+{ -+ TCGv_i64 csr = tcg_const_i64(a1); -+ gen_helper_csr_rdq(rd, cpu_env, csr); -+} -+ -+/* -+ * 64-bit CSR write -+ * -+ * @arg : GPR that stores the new value of CSR register -+ * @csr : CSR register number -+ */ -+static void gen_csr_wrq(DisasContext *ctx, TCGv val, int64_t a1) -+{ -+ TCGv_i64 csr = tcg_const_i64(a1); -+ gen_helper_csr_wrq(val, cpu_env, val, csr); -+} -+ -+/* -+ * 64-bit CSR exchange -+ * -+ * @arg : GPR that stores the new value of CSR register -+ * @csr : CSR register number -+ */ -+static void gen_csr_xchgq(DisasContext *ctx, TCGv val, TCGv mask, int64_t a1) -+{ -+ TCGv_i64 csr = tcg_const_i64(a1); -+ gen_helper_csr_xchgq(val, cpu_env, val, mask, csr); -+} -+#endif /* !CONFIG_USER_ONLY */ -+ -+static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, -+ CPUState *cs) -+{ -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ CPULOONGARCHState *env = cs->env_ptr; -+ -+ ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; -+ ctx->saved_pc = -1; -+ ctx->insn_flags = env->insn_flags; -+ ctx->btarget = 0; -+ /* Restore state from the tb context. */ -+ ctx->hflags = (uint32_t)ctx->base.tb->flags; /* FIXME: maybe use 64 bits? */ -+ restore_cpu_state(env, ctx); -+#ifdef CONFIG_USER_ONLY -+ ctx->mem_idx = LARCH_HFLAG_UM; -+#else -+ ctx->mem_idx = hflags_mmu_index(ctx->hflags); -+#endif -+ ctx->default_tcg_memop_mask = MO_ALIGN; -+ -+ LOG_DISAS("\ntb %p idx %d hflags %04x\n", ctx->base.tb, ctx->mem_idx, -+ ctx->hflags); -+} -+ -+static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) -+{ -+} -+ -+static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) -+{ -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ -+ tcg_gen_insn_start(ctx->base.pc_next, ctx->hflags & LARCH_HFLAG_BMASK, -+ ctx->btarget); -+} -+#if 0 -+static bool loongarch_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, -+ const CPUBreakpoint *bp) -+{ -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ -+ save_cpu_state(ctx, 1); -+ ctx->base.is_jmp = DISAS_NORETURN; -+ gen_helper_raise_exception_debug(cpu_env); -+ /* The address covered by the breakpoint must be included in -+ [tb->pc, tb->pc + tb->size) in order to for it to be -+ properly cleared -- thus we increment the PC here so that -+ the logic setting tb->size below does the right thing. */ -+ ctx->base.pc_next += 4; -+ return true; -+} -+#endif -+/* 128 and 256 lsx vector instructions are not supported yet */ -+static bool decode_vector_lsx(uint32_t opcode) -+{ -+ uint32_t value = (opcode & 0xff000000); -+ -+ if ((opcode & 0xf0000000) == 0x70000000) { -+ return true; -+ } else if ((opcode & 0xfff00000) == 0x38400000) { -+ return true; -+ } else { -+ switch (value) { -+ case 0x09000000: -+ case 0x0a000000: -+ case 0x0e000000: -+ case 0x0f000000: -+ case 0x2c000000: -+ case 0x30000000: -+ case 0x31000000: -+ case 0x32000000: -+ case 0x33000000: -+ return true; -+ } -+ } -+ return false; -+} -+ -+static bool decode_insn(DisasContext *ctx, uint32_t insn); -+#include "decode-insn.c.inc" -+#include "trans.inc.c" -+ -+static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) -+{ -+ CPULOONGARCHState *env = cs->env_ptr; -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ int insn_bytes = 4; -+ -+ ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next); -+ -+ if (!decode_insn(ctx, ctx->opcode)) { -+ if (decode_vector_lsx(ctx->opcode)) { -+ generate_exception_end(ctx, EXCP_RI); -+ } else { -+ fprintf(stderr, "Error: unkown opcode. 0x%lx: 0x%x\n", -+ ctx->base.pc_next, ctx->opcode); -+ generate_exception_end(ctx, EXCP_RI); -+ } -+ } -+ -+ if (ctx->hflags & LARCH_HFLAG_BMASK) { -+ gen_branch(ctx, insn_bytes); -+ } -+ ctx->base.pc_next += insn_bytes; -+} -+ -+static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) -+{ -+ DisasContext *ctx = container_of(dcbase, DisasContext, base); -+ -+ if (ctx->base.singlestep_enabled && ctx->base.is_jmp != DISAS_NORETURN) { -+ save_cpu_state(ctx, ctx->base.is_jmp != DISAS_EXIT); -+ gen_helper_raise_exception_debug(cpu_env); -+ } else { -+ switch (ctx->base.is_jmp) { -+ case DISAS_STOP: -+ gen_save_pc(ctx->base.pc_next); -+ tcg_gen_lookup_and_goto_ptr(); -+ break; -+ case DISAS_NEXT: -+ case DISAS_TOO_MANY: -+ save_cpu_state(ctx, 0); -+ gen_goto_tb(ctx, 0, ctx->base.pc_next); -+ break; -+ case DISAS_EXIT: -+ tcg_gen_exit_tb(NULL, 0); -+ break; -+ case DISAS_NORETURN: -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ } -+} -+ -+static void loongarch_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) -+{ -+ qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); -+ log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); -+} -+ -+static const TranslatorOps loongarch_tr_ops = { -+ .init_disas_context = loongarch_tr_init_disas_context, -+ .tb_start = loongarch_tr_tb_start, -+ .insn_start = loongarch_tr_insn_start, -+#if 0 -+ .breakpoint_check = loongarch_tr_breakpoint_check, -+#endif -+ .translate_insn = loongarch_tr_translate_insn, -+ .tb_stop = loongarch_tr_tb_stop, -+ .disas_log = loongarch_tr_disas_log, -+}; -+ -+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb, int max_insns) -+{ -+ DisasContext ctx; -+ -+ translator_loop(&loongarch_tr_ops, &ctx.base, cs, tb, max_insns); -+} -+ -+void loongarch_tcg_init(void) -+{ -+ int i; -+ -+ for (i = 0; i < 32; i++) -+ cpu_gpr[i] = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, -+ active_tc.gpr[i]), -+ regnames[i]); -+ -+ for (i = 0; i < 32; i++) { -+ int off = offsetof(CPULOONGARCHState, active_fpu.fpr[i].d); -+ fpu_f64[i] = tcg_global_mem_new_i64(cpu_env, off, fregnames[i]); -+ } -+ -+ cpu_PC = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, active_tc.PC), "PC"); -+ bcond = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, bcond), "bcond"); -+ btarget = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, btarget), "btarget"); -+ hflags = tcg_global_mem_new_i32(cpu_env, -+ offsetof(CPULOONGARCHState, hflags), "hflags"); -+ fpu_fcsr0 = tcg_global_mem_new_i32(cpu_env, -+ offsetof(CPULOONGARCHState, active_fpu.fcsr0), -+ "fcsr0"); -+ cpu_lladdr = tcg_global_mem_new(cpu_env, -+ offsetof(CPULOONGARCHState, lladdr), -+ "lladdr"); -+ cpu_llval = tcg_global_mem_new(cpu_env, offsetof(CPULOONGARCHState, llval), -+ "llval"); -+} -+ -+void restore_state_to_opc(CPULOONGARCHState *env, TranslationBlock *tb, -+ target_ulong *data) -+{ -+ env->active_tc.PC = data[0]; -+ env->hflags &= ~LARCH_HFLAG_BMASK; -+ env->hflags |= data[1]; -+ switch (env->hflags & LARCH_HFLAG_BMASK) { -+ case LARCH_HFLAG_BR: -+ break; -+ case LARCH_HFLAG_BC: -+ case LARCH_HFLAG_B: -+ env->btarget = data[2]; -+ break; -+ } -+} -diff --git a/target/meson.build b/target/meson.build -index 2f6940255..ac0ce618b 100644 ---- a/target/meson.build -+++ b/target/meson.build -@@ -5,6 +5,7 @@ subdir('cris') - subdir('hexagon') - subdir('hppa') - subdir('i386') -+subdir('loongarch64') - subdir('m68k') - subdir('microblaze') - subdir('mips') --- -2.43.5 - diff --git a/0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch b/0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch deleted file mode 100644 index 1ea643b7a696a58b41c635c2e94f2be615bc4177..0000000000000000000000000000000000000000 --- a/0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 630d76cc15bd98669162f785861cdd81f2ee8f01 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Wed, 25 Aug 2021 12:25:05 +0800 -Subject: [PATCH 4/8] anolis: csv/i386: add command to load vmcb to guest - memory - -The KVM_CSV_LAUNCH_ENCRYPT_VMCB command is used to load and encrypt -the initial VMCB data to secure memory in an isolated region -that guest owns. - -Signed-off-by: Xin Jiang -Change-Id: I821bc8ab726f1bd22df36c163196951504eaa8da ---- - linux-headers/linux/kvm.h | 1 + - target/i386/csv-sysemu-stub.c | 5 +++++ - target/i386/csv.c | 21 +++++++++++++++++++++ - target/i386/csv.h | 1 + - target/i386/sev.c | 7 +++++-- - 5 files changed, 33 insertions(+), 2 deletions(-) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 53f9202ffb..c6cd3a619a 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1814,6 +1814,7 @@ enum csv_cmd_id { - - KVM_CSV_INIT = KVM_CSV_NR_MIN, - KVM_CSV_LAUNCH_ENCRYPT_DATA, -+ KVM_CSV_LAUNCH_ENCRYPT_VMCB, - }; - - struct kvm_csv_launch_encrypt_data { -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index 236a6909d2..a5ce986e3c 100644 ---- a/target/i386/csv-sysemu-stub.c -+++ b/target/i386/csv-sysemu-stub.c -@@ -24,3 +24,8 @@ int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) - { - g_assert_not_reached(); - } -+ -+int csv_launch_encrypt_vmcb(void) -+{ -+ g_assert_not_reached(); -+} -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 3b3dff5174..d166d3775e 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -162,3 +162,24 @@ csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) - - return ret; - } -+ -+int -+csv_launch_encrypt_vmcb(void) -+{ -+ int ret, fw_error; -+ -+ if (!csv_enabled()) { -+ error_report("%s: CSV is not enabled",__func__); -+ return -1; -+ } -+ -+ ret = csv_ioctl(KVM_CSV_LAUNCH_ENCRYPT_VMCB, NULL, &fw_error); -+ if (ret) { -+ error_report("%s: CSV LAUNCH_ENCRYPT_VMCB ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+err: -+ return ret; -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 6f7b112d96..7dc5c75366 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -34,6 +34,7 @@ typedef struct CsvGuestState CsvGuestState; - - extern struct CsvGuestState csv_guest; - extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); -+extern int csv_launch_encrypt_vmcb(void); - - int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 023532f4ec..73a794ef74 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -770,8 +770,11 @@ sev_launch_get_measure(Notifier *notifier, void *unused) - } - - if (sev_es_enabled()) { -- /* measure all the VM save areas before getting launch_measure */ -- ret = sev_launch_update_vmsa(sev); -+ if (csv_enabled()) -+ ret = csv_launch_encrypt_vmcb(); -+ else -+ /* measure all the VM save areas before getting launch_measure */ -+ ret = sev_launch_update_vmsa(sev); - if (ret) { - exit(1); - } --- -2.17.1 - diff --git a/0005-Add-linux-headers-and-linux-user.patch b/0005-Add-linux-headers-and-linux-user.patch deleted file mode 100644 index 8e5b37e66e30cf268b4ede4ce06f0d02e1b3bca7..0000000000000000000000000000000000000000 --- a/0005-Add-linux-headers-and-linux-user.patch +++ /dev/null @@ -1,1663 +0,0 @@ -From be4aee607329aee902b9a03936523c7d57d47100 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:47:06 -0400 -Subject: [PATCH 05/28] Add linux-headers and linux-user. - -Change-Id: If052442a981fed87c03ca431c010629dc8e872ca -Signed-off-by: lixianglai ---- - linux-headers/asm-loongarch64/bitsperlong.h | 9 + - linux-headers/asm-loongarch64/kvm.h | 346 ++++++++++++++++++++ - linux-headers/asm-loongarch64/sgidefs.h | 20 ++ - linux-headers/asm-loongarch64/unistd.h | 23 ++ - linux-user/loongarch64/cpu_loop.c | 193 +++++++++++ - linux-user/loongarch64/meson.build | 6 + - linux-user/loongarch64/signal.c | 212 ++++++++++++ - linux-user/loongarch64/sockbits.h | 1 + - linux-user/loongarch64/syscall_nr.h | 287 ++++++++++++++++ - linux-user/loongarch64/target_cpu.h | 45 +++ - linux-user/loongarch64/target_elf.h | 14 + - linux-user/loongarch64/target_fcntl.h | 13 + - linux-user/loongarch64/target_signal.h | 23 ++ - linux-user/loongarch64/target_structs.h | 62 ++++ - linux-user/loongarch64/target_syscall.h | 44 +++ - linux-user/loongarch64/termbits.h | 224 +++++++++++++ - 16 files changed, 1522 insertions(+) - create mode 100644 linux-headers/asm-loongarch64/bitsperlong.h - create mode 100644 linux-headers/asm-loongarch64/kvm.h - create mode 100644 linux-headers/asm-loongarch64/sgidefs.h - create mode 100644 linux-headers/asm-loongarch64/unistd.h - create mode 100644 linux-user/loongarch64/cpu_loop.c - create mode 100644 linux-user/loongarch64/meson.build - create mode 100644 linux-user/loongarch64/signal.c - create mode 100644 linux-user/loongarch64/sockbits.h - create mode 100644 linux-user/loongarch64/syscall_nr.h - create mode 100644 linux-user/loongarch64/target_cpu.h - create mode 100644 linux-user/loongarch64/target_elf.h - create mode 100644 linux-user/loongarch64/target_fcntl.h - create mode 100644 linux-user/loongarch64/target_signal.h - create mode 100644 linux-user/loongarch64/target_structs.h - create mode 100644 linux-user/loongarch64/target_syscall.h - create mode 100644 linux-user/loongarch64/termbits.h - -diff --git a/linux-headers/asm-loongarch64/bitsperlong.h b/linux-headers/asm-loongarch64/bitsperlong.h -new file mode 100644 -index 000000000..5c2c8779a ---- /dev/null -+++ b/linux-headers/asm-loongarch64/bitsperlong.h -@@ -0,0 +1,9 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+#ifndef __ASM_LOONGARCH_BITSPERLONG_H -+#define __ASM_LOONGARCH_BITSPERLONG_H -+ -+#define __BITS_PER_LONG _LOONGARCH_SZLONG -+ -+#include -+ -+#endif /* __ASM_LOONGARCH_BITSPERLONG_H */ -diff --git a/linux-headers/asm-loongarch64/kvm.h b/linux-headers/asm-loongarch64/kvm.h -new file mode 100644 -index 000000000..a24375ee5 ---- /dev/null -+++ b/linux-headers/asm-loongarch64/kvm.h -@@ -0,0 +1,346 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * Copyright (C) 2020 Loongson Technologies, Inc. All rights reserved. -+ * Authors: Sanjay Lal -+ * Authors: Xing Li -+ */ -+ -+#ifndef __LINUX_KVM_LOONGARCH_H -+#define __LINUX_KVM_LOONGARCH_H -+ -+#include -+ -+#define __KVM_HAVE_GUEST_DEBUG -+#define KVM_GUESTDBG_USE_SW_BP 0x00010000 -+#define KVM_GUESTDBG_USE_HW_BP 0x00020000 -+#define KVM_DATA_HW_BREAKPOINT_NUM 8 -+#define KVM_INST_HW_BREAKPOINT_NUM 8 -+ -+/* -+ * KVM Loongarch specific structures and definitions. -+ * -+ * Some parts derived from the x86 version of this file. -+ */ -+ -+#define __KVM_HAVE_READONLY_MEM -+ -+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 -+ -+#define KVM_LARCH_VCPU_PVTIME_CTRL 2 -+#define KVM_LARCH_VCPU_PVTIME_IPA 0 -+ -+/* -+ * for KVM_GET_REGS and KVM_SET_REGS -+ */ -+struct kvm_regs { -+ /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ -+ __u64 gpr[32]; -+ __u64 pc; -+}; -+ -+/* -+ * for KVM_GET_CPUCFG -+ */ -+struct kvm_cpucfg { -+ /* out (KVM_GET_CPUCFG) */ -+ __u32 cpucfg[64]; -+}; -+ -+/* -+ * for KVM_GET_FPU and KVM_SET_FPU -+ */ -+struct kvm_fpu { -+ __u32 fcsr; -+ __u32 vcsr; -+ __u64 fcc; /* 8x8 */ -+ struct kvm_fpureg { -+ __u64 val64[4]; //support max 256 bits -+ }fpr[32]; -+}; -+ -+/* -+ * For LOONGARCH, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various -+ * registers. The id field is broken down as follows: -+ * -+ * bits[63..52] - As per linux/kvm.h -+ * bits[51..32] - Must be zero. -+ * bits[31..16] - Register set. -+ * -+ * Register set = 0: GP registers from kvm_regs (see definitions below). -+ * -+ * Register set = 1: CP0 registers. -+ * bits[15..8] - COP0 register set. -+ * -+ * COP0 register set = 0: Main CP0 registers. -+ * bits[7..3] - Register 'rd' index. -+ * bits[2..0] - Register 'sel' index. -+ * -+ * COP0 register set = 1: MAARs. -+ * bits[7..0] - MAAR index. -+ * -+ * Register set = 2: KVM specific registers (see definitions below). -+ * -+ * Register set = 3: FPU / MSA registers (see definitions below). -+ * -+ * Other sets registers may be added in the future. Each set would -+ * have its own identifier in bits[31..16]. -+ */ -+ -+#define KVM_REG_LOONGARCH_GP (KVM_REG_LOONGARCH | 0x0000000000000000ULL) -+#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x0000000000010000ULL) -+#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x0000000000020000ULL) -+#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x0000000000030000ULL) -+ -+ -+/* -+ * KVM_REG_LOONGARCH_GP - General purpose registers from kvm_regs. -+ */ -+ -+#define KVM_REG_LOONGARCH_R0 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 0) -+#define KVM_REG_LOONGARCH_R1 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 1) -+#define KVM_REG_LOONGARCH_R2 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 2) -+#define KVM_REG_LOONGARCH_R3 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 3) -+#define KVM_REG_LOONGARCH_R4 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 4) -+#define KVM_REG_LOONGARCH_R5 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 5) -+#define KVM_REG_LOONGARCH_R6 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 6) -+#define KVM_REG_LOONGARCH_R7 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 7) -+#define KVM_REG_LOONGARCH_R8 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 8) -+#define KVM_REG_LOONGARCH_R9 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 9) -+#define KVM_REG_LOONGARCH_R10 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 10) -+#define KVM_REG_LOONGARCH_R11 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 11) -+#define KVM_REG_LOONGARCH_R12 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 12) -+#define KVM_REG_LOONGARCH_R13 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 13) -+#define KVM_REG_LOONGARCH_R14 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 14) -+#define KVM_REG_LOONGARCH_R15 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 15) -+#define KVM_REG_LOONGARCH_R16 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 16) -+#define KVM_REG_LOONGARCH_R17 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 17) -+#define KVM_REG_LOONGARCH_R18 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 18) -+#define KVM_REG_LOONGARCH_R19 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 19) -+#define KVM_REG_LOONGARCH_R20 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 20) -+#define KVM_REG_LOONGARCH_R21 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 21) -+#define KVM_REG_LOONGARCH_R22 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 22) -+#define KVM_REG_LOONGARCH_R23 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 23) -+#define KVM_REG_LOONGARCH_R24 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 24) -+#define KVM_REG_LOONGARCH_R25 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 25) -+#define KVM_REG_LOONGARCH_R26 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 26) -+#define KVM_REG_LOONGARCH_R27 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 27) -+#define KVM_REG_LOONGARCH_R28 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 28) -+#define KVM_REG_LOONGARCH_R29 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 29) -+#define KVM_REG_LOONGARCH_R30 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 30) -+#define KVM_REG_LOONGARCH_R31 (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 31) -+ -+#define KVM_REG_LOONGARCH_HI (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 32) -+#define KVM_REG_LOONGARCH_LO (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 33) -+#define KVM_REG_LOONGARCH_PC (KVM_REG_LOONGARCH_GP | KVM_REG_SIZE_U64 | 34) -+ -+ -+/* -+ * KVM_REG_LOONGARCH_KVM - KVM specific control registers. -+ */ -+ -+/* -+ * CP0_Count control -+ * DC: Set 0: Master disable CP0_Count and set COUNT_RESUME to now -+ * Set 1: Master re-enable CP0_Count with unchanged bias, handling timer -+ * interrupts since COUNT_RESUME -+ * This can be used to freeze the timer to get a consistent snapshot of -+ * the CP0_Count and timer interrupt pending state, while also resuming -+ * safely without losing time or guest timer interrupts. -+ * Other: Reserved, do not change. -+ */ -+#define KVM_REG_LOONGARCH_COUNT_CTL (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 0) -+#define KVM_REG_LOONGARCH_COUNT_CTL_DC 0x00000001 -+ -+/* -+ * CP0_Count resume monotonic nanoseconds -+ * The monotonic nanosecond time of the last set of COUNT_CTL.DC (master -+ * disable). Any reads and writes of Count related registers while -+ * COUNT_CTL.DC=1 will appear to occur at this time. When COUNT_CTL.DC is -+ * cleared again (master enable) any timer interrupts since this time will be -+ * emulated. -+ * Modifications to times in the future are rejected. -+ */ -+#define KVM_REG_LOONGARCH_COUNT_RESUME (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 1) -+/* -+ * CP0_Count rate in Hz -+ * Specifies the rate of the CP0_Count timer in Hz. Modifications occur without -+ * discontinuities in CP0_Count. -+ */ -+#define KVM_REG_LOONGARCH_COUNT_HZ (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 2) -+ -+#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3) -+ -+#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4) -+ -+struct kvm_iocsr_entry { -+ __u32 addr; -+ __u32 pad; -+ __u64 data; -+}; -+ -+struct kvm_csr_entry { -+ __u32 index; -+ __u32 reserved; -+ __u64 data; -+}; -+ -+/* for KVM_GET_MSRS and KVM_SET_MSRS */ -+struct kvm_msrs { -+ __u32 ncsrs; /* number of msrs in entries */ -+ __u32 pad; -+ struct kvm_csr_entry entries[0]; -+}; -+ -+#define __KVM_HAVE_IRQ_LINE -+ -+struct kvm_debug_exit_arch { -+ __u64 epc; -+ __u32 fwps; -+ __u32 mwps; -+ __u32 exception; -+}; -+ -+/* for KVM_SET_GUEST_DEBUG */ -+struct hw_breakpoint { -+ __u64 addr; -+ __u64 mask; -+ __u32 asid; -+ __u32 ctrl; -+}; -+ -+struct kvm_guest_debug_arch { -+ struct hw_breakpoint data_breakpoint[KVM_DATA_HW_BREAKPOINT_NUM]; -+ struct hw_breakpoint inst_breakpoint[KVM_INST_HW_BREAKPOINT_NUM]; -+ int inst_bp_nums, data_bp_nums; -+}; -+ -+/* definition of registers in kvm_run */ -+struct kvm_sync_regs { -+}; -+ -+/* dummy definition */ -+struct kvm_sregs { -+}; -+ -+struct kvm_loongarch_interrupt { -+ /* in */ -+ __u32 cpu; -+ __u32 irq; -+}; -+ -+#define KVM_IRQCHIP_LS7A_IOAPIC 0x0 -+#define KVM_IRQCHIP_LS3A_GIPI 0x1 -+#define KVM_IRQCHIP_LS3A_HT_IRQ 0x2 -+#define KVM_IRQCHIP_LS3A_ROUTE 0x3 -+#define KVM_IRQCHIP_LS3A_EXTIRQ 0x4 -+#define KVM_IRQCHIP_LS3A_IPMASK 0x5 -+#define KVM_NR_IRQCHIPS 1 -+#define KVM_IRQCHIP_NUM_PINS 64 -+ -+#define KVM_MAX_CORES 256 -+#define KVM_EXTIOI_IRQS (256) -+#define KVM_EXTIOI_IRQS_BITMAP_SIZE (KVM_EXTIOI_IRQS / 8) -+/* map to ipnum per 32 irqs */ -+#define KVM_EXTIOI_IRQS_IPMAP_SIZE (KVM_EXTIOI_IRQS / 32) -+#define KVM_EXTIOI_IRQS_PER_GROUP 32 -+#define KVM_EXTIOI_IRQS_COREMAP_SIZE (KVM_EXTIOI_IRQS) -+#define KVM_EXTIOI_IRQS_NODETYPE_SIZE 16 -+ -+struct ls7a_ioapic_state { -+ __u64 int_id; -+ /* 0x020 interrupt mask register */ -+ __u64 int_mask; -+ /* 0x040 1=msi */ -+ __u64 htmsi_en; -+ /* 0x060 edge=1 level =0 */ -+ __u64 intedge; -+ /* 0x080 for clean edge int,set 1 clean,set 0 is noused */ -+ __u64 intclr; -+ /* 0x0c0 */ -+ __u64 auto_crtl0; -+ /* 0x0e0 */ -+ __u64 auto_crtl1; -+ /* 0x100 - 0x140 */ -+ __u8 route_entry[64]; -+ /* 0x200 - 0x240 */ -+ __u8 htmsi_vector[64]; -+ /* 0x300 */ -+ __u64 intisr_chip0; -+ /* 0x320 */ -+ __u64 intisr_chip1; -+ /* edge detection */ -+ __u64 last_intirr; -+ /* 0x380 interrupt request register */ -+ __u64 intirr; -+ /* 0x3a0 interrupt service register */ -+ __u64 intisr; -+ /* 0x3e0 interrupt level polarity selection register, -+ * 0 for high level tirgger -+ */ -+ __u64 int_polarity; -+}; -+ -+struct loongarch_gipi_single { -+ __u32 status; -+ __u32 en; -+ __u32 set; -+ __u32 clear; -+ __u64 buf[4]; -+}; -+ -+struct loongarch_gipiState { -+ struct loongarch_gipi_single core[KVM_MAX_CORES]; -+}; -+ -+struct kvm_loongarch_ls3a_extirq_state { -+ union ext_en_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_BITMAP_SIZE]; -+ } ext_en_r; -+ union bounce_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_BITMAP_SIZE]; -+ } bounce_r; -+ union ext_isr_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_BITMAP_SIZE]; -+ } ext_isr_r; -+ union ext_core_isr_r { -+ uint64_t reg_u64[KVM_MAX_CORES][KVM_EXTIOI_IRQS_BITMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_MAX_CORES][KVM_EXTIOI_IRQS_BITMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_MAX_CORES][KVM_EXTIOI_IRQS_BITMAP_SIZE]; -+ } ext_core_isr_r; -+ union ip_map_r { -+ uint64_t reg_u64; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_IPMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_IPMAP_SIZE]; -+ } ip_map_r; -+ union core_map_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_COREMAP_SIZE / 8]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_COREMAP_SIZE / 4]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_COREMAP_SIZE]; -+ } core_map_r; -+ union node_type_r { -+ uint64_t reg_u64[KVM_EXTIOI_IRQS_NODETYPE_SIZE / 4]; -+ uint32_t reg_u32[KVM_EXTIOI_IRQS_NODETYPE_SIZE / 2]; -+ uint16_t reg_u16[KVM_EXTIOI_IRQS_NODETYPE_SIZE]; -+ uint8_t reg_u8[KVM_EXTIOI_IRQS_NODETYPE_SIZE * 2]; -+ } node_type_r; -+}; -+ -+struct loongarch_kvm_irqchip { -+ __u16 chip_id; -+ __u16 len; -+ __u16 vcpu_id; -+ __u16 reserved; -+ char data[0]; -+}; -+ -+#endif /* __LINUX_KVM_LOONGARCH_H */ -diff --git a/linux-headers/asm-loongarch64/sgidefs.h b/linux-headers/asm-loongarch64/sgidefs.h -new file mode 100644 -index 000000000..b80960834 ---- /dev/null -+++ b/linux-headers/asm-loongarch64/sgidefs.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -+/* -+* Copyright (C) 2020 Loongson Technology Corporation Limited -+* -+* Author: Hanlu Li -+*/ -+#ifndef __ASM_SGIDEFS_H -+#define __ASM_SGIDEFS_H -+ -+#define _LOONGARCH_ISA_LOONGARCH32 6 -+#define _LOONGARCH_ISA_LOONGARCH64 7 -+ -+/* -+ * Subprogram calling convention -+ */ -+#define _LOONGARCH_SIM_ABILP32 1 -+#define _LOONGARCH_SIM_ABILPX32 2 -+#define _LOONGARCH_SIM_ABILP64 3 -+ -+#endif /* __ASM_SGIDEFS_H */ -diff --git a/linux-headers/asm-loongarch64/unistd.h b/linux-headers/asm-loongarch64/unistd.h -new file mode 100644 -index 000000000..2a6014562 ---- /dev/null -+++ b/linux-headers/asm-loongarch64/unistd.h -@@ -0,0 +1,23 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ * Copyright (C) 2020 Loongson Technologies, Inc. -+ * Authors: Jun Yi -+ */ -+ -+#ifdef __LP64__ -+#define __ARCH_WANT_NEW_STAT -+#endif /* __LP64__ */ -+ -+#include -diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c -new file mode 100644 -index 000000000..6d4093e1d ---- /dev/null -+++ b/linux-user/loongarch64/cpu_loop.c -@@ -0,0 +1,193 @@ -+/* -+ * qemu user cpu loop -+ * -+ * Copyright (c) 2003-2008 Fabrice Bellard -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu.h" -+#include "cpu_loop-common.h" -+#include "elf.h" -+ -+/* Break codes */ -+enum { -+ BRK_OVERFLOW = 6, -+ BRK_DIVZERO = 7 -+}; -+ -+static int do_break(CPULOONGARCHState *env, target_siginfo_t *info, -+ unsigned int code) -+{ -+ int ret = -1; -+ -+ switch (code) { -+ case BRK_OVERFLOW: -+ case BRK_DIVZERO: -+ info->si_signo = TARGET_SIGFPE; -+ info->si_errno = 0; -+ info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV; -+ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); -+ ret = 0; -+ break; -+ default: -+ info->si_signo = TARGET_SIGTRAP; -+ info->si_errno = 0; -+ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); -+ ret = 0; -+ break; -+ } -+ -+ return ret; -+} -+ -+void cpu_loop(CPULOONGARCHState *env) -+{ -+ CPUState *cs = CPU(loongarch_env_get_cpu(env)); -+ target_siginfo_t info; -+ int trapnr; -+ abi_long ret; -+ -+ for (;;) { -+ cpu_exec_start(cs); -+ trapnr = cpu_exec(cs); -+ cpu_exec_end(cs); -+ process_queued_cpu_work(cs); -+ -+ switch (trapnr) { -+ case EXCP_SYSCALL: -+ env->active_tc.PC += 4; -+ ret = do_syscall(env, env->active_tc.gpr[11], -+ env->active_tc.gpr[4], env->active_tc.gpr[5], -+ env->active_tc.gpr[6], env->active_tc.gpr[7], -+ env->active_tc.gpr[8], env->active_tc.gpr[9], -+ -1, -1); -+ if (ret == -TARGET_ERESTARTSYS) { -+ env->active_tc.PC -= 4; -+ break; -+ } -+ if (ret == -TARGET_QEMU_ESIGRETURN) { -+ /* Returning from a successful sigreturn syscall. -+ Avoid clobbering register state. */ -+ break; -+ } -+ env->active_tc.gpr[4] = ret; -+ break; -+ case EXCP_TLBL: -+ case EXCP_TLBS: -+ case EXCP_AdEL: -+ case EXCP_AdES: -+ info.si_signo = TARGET_SIGSEGV; -+ info.si_errno = 0; -+ /* XXX: check env->error_code */ -+ info.si_code = TARGET_SEGV_MAPERR; -+ info._sifields._sigfault._addr = env->CSR_BADV; -+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); -+ break; -+ case EXCP_FPDIS: -+ case EXCP_LSXDIS: -+ case EXCP_LASXDIS: -+ case EXCP_RI: -+ info.si_signo = TARGET_SIGILL; -+ info.si_errno = 0; -+ info.si_code = 0; -+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); -+ break; -+ case EXCP_INTERRUPT: -+ /* just indicate that signals should be handled asap */ -+ break; -+ case EXCP_DEBUG: -+ info.si_signo = TARGET_SIGTRAP; -+ info.si_errno = 0; -+ info.si_code = TARGET_TRAP_BRKPT; -+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); -+ break; -+ case EXCP_FPE: -+ info.si_signo = TARGET_SIGFPE; -+ info.si_errno = 0; -+ info.si_code = TARGET_FPE_FLTUNK; -+ if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_INVALID) { -+ info.si_code = TARGET_FPE_FLTINV; -+ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_DIV0) { -+ info.si_code = TARGET_FPE_FLTDIV; -+ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_OVERFLOW) { -+ info.si_code = TARGET_FPE_FLTOVF; -+ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_UNDERFLOW) { -+ info.si_code = TARGET_FPE_FLTUND; -+ } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_INEXACT) { -+ info.si_code = TARGET_FPE_FLTRES; -+ } -+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); -+ break; -+ case EXCP_BREAK: -+ { -+ abi_ulong trap_instr; -+ unsigned int code; -+ -+ ret = get_user_u32(trap_instr, env->active_tc.PC); -+ if (ret != 0) { -+ goto error; -+ } -+ -+ code = trap_instr & 0x7fff; -+ -+ if (do_break(env, &info, code) != 0) { -+ goto error; -+ } -+ } -+ break; -+ case EXCP_TRAP: -+ { -+ abi_ulong trap_instr; -+ unsigned int code = 0; -+ -+ ret = get_user_u32(trap_instr, env->active_tc.PC); -+ -+ if (ret != 0) { -+ goto error; -+ } -+ -+ /* The immediate versions don't provide a code. */ -+ if (!(trap_instr & 0xFC000000)) { -+ code = ((trap_instr >> 6) & ((1 << 10) - 1)); -+ } -+ -+ if (do_break(env, &info, code) != 0) { -+ goto error; -+ } -+ } -+ break; -+ case EXCP_ATOMIC: -+ cpu_exec_step_atomic(cs); -+ break; -+ default: -+error: -+ printf("111111\n"); -+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); -+ abort(); -+ } -+ process_pending_signals(env); -+ } -+} -+ -+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) -+{ -+ int i; -+ -+ for (i = 0; i < 32; i++) { -+ env->active_tc.gpr[i] = regs->regs[i]; -+ } -+ env->active_tc.PC = regs->csr_era & ~(target_ulong)1; -+} -diff --git a/linux-user/loongarch64/meson.build b/linux-user/loongarch64/meson.build -new file mode 100644 -index 000000000..c4c0b4d70 ---- /dev/null -+++ b/linux-user/loongarch64/meson.build -@@ -0,0 +1,6 @@ -+syscall_nr_generators += { -+ 'loongarch64': generator(sh, -+ arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@', -+ '', 'TARGET_SYSCALL_OFFSET' ], -+ output: '@BASENAME@_nr.h') -+} -diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c -new file mode 100644 -index 000000000..6fe685275 ---- /dev/null -+++ b/linux-user/loongarch64/signal.c -@@ -0,0 +1,212 @@ -+/* -+ * Emulation of Linux signals -+ * -+ * Copyright (c) 2003 Fabrice Bellard -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+#include "qemu/osdep.h" -+#include "qemu.h" -+#include "signal-common.h" -+#include "linux-user/trace.h" -+ -+#define FPU_REG_WIDTH 256 -+union fpureg { -+ uint32_t val32[FPU_REG_WIDTH / 32]; -+ uint64_t val64[FPU_REG_WIDTH / 64]; -+}; -+ -+struct target_sigcontext { -+ uint64_t sc_pc; -+ uint64_t sc_regs[32]; -+ uint32_t sc_flags; -+ -+ uint32_t sc_fcsr; -+ uint32_t sc_vcsr; -+ uint64_t sc_fcc; -+ union fpureg sc_fpregs[32] __attribute__((aligned(32))); -+ -+ uint32_t sc_reserved; -+ -+}; -+ -+struct sigframe { -+ uint32_t sf_ass[4]; /* argument save space for o32 */ -+ uint32_t sf_code[2]; /* signal trampoline */ -+ struct target_sigcontext sf_sc; -+ target_sigset_t sf_mask; -+}; -+ -+struct target_ucontext { -+ target_ulong tuc_flags; -+ target_ulong tuc_link; -+ target_stack_t tuc_stack; -+ target_ulong pad0; -+ struct target_sigcontext tuc_mcontext; -+ target_sigset_t tuc_sigmask; -+}; -+ -+struct target_rt_sigframe { -+ uint32_t rs_ass[4]; /* argument save space for o32 */ -+ uint32_t rs_code[2]; /* signal trampoline */ -+ struct target_siginfo rs_info; -+ struct target_ucontext rs_uc; -+}; -+ -+static inline void setup_sigcontext(CPULOONGARCHState *regs, -+ struct target_sigcontext *sc) -+{ -+ int i; -+ -+ __put_user(exception_resume_pc(regs), &sc->sc_pc); -+ regs->hflags &= ~LARCH_HFLAG_BMASK; -+ -+ __put_user(0, &sc->sc_regs[0]); -+ for (i = 1; i < 32; ++i) { -+ __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); -+ } -+ -+ for (i = 0; i < 32; ++i) { -+ __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i].val64[0]); -+ } -+} -+ -+static inline void -+restore_sigcontext(CPULOONGARCHState *regs, struct target_sigcontext *sc) -+{ -+ int i; -+ -+ __get_user(regs->CSR_ERA, &sc->sc_pc); -+ -+ for (i = 1; i < 32; ++i) { -+ __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); -+ } -+ -+ for (i = 0; i < 32; ++i) { -+ __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i].val64[0]); -+ } -+} -+ -+/* -+ * Determine which stack to use.. -+ */ -+static inline abi_ulong -+get_sigframe(struct target_sigaction *ka, CPULOONGARCHState *regs, -+ size_t frame_size) -+{ -+ unsigned long sp; -+ -+ /* -+ * FPU emulator may have its own trampoline active just -+ * above the user stack, 16-bytes before the next lowest -+ * 16 byte boundary. Try to avoid trashing it. -+ */ -+ sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka); -+ -+ return (sp - frame_size) & ~7; -+} -+ -+void setup_rt_frame(int sig, struct target_sigaction *ka, -+ target_siginfo_t *info, -+ target_sigset_t *set, CPULOONGARCHState *env) -+{ -+ struct target_rt_sigframe *frame; -+ abi_ulong frame_addr; -+ int i; -+ -+ frame_addr = get_sigframe(ka, env, sizeof(*frame)); -+ trace_user_setup_rt_frame(env, frame_addr); -+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { -+ goto give_sigsegv; -+ } -+ -+ /* ori a7, $r0, TARGET_NR_rt_sigreturn */ -+ /* syscall 0 */ -+ __put_user(0x0380000b + (TARGET_NR_rt_sigreturn << 10), &frame->rs_code[0]); -+ __put_user(0x002b0000, &frame->rs_code[1]); -+ -+ tswap_siginfo(&frame->rs_info, info); -+ -+ __put_user(0, &frame->rs_uc.tuc_flags); -+ __put_user(0, &frame->rs_uc.tuc_link); -+ target_save_altstack(&frame->rs_uc.tuc_stack, env); -+ -+ setup_sigcontext(env, &frame->rs_uc.tuc_mcontext); -+ -+ for (i = 0; i < TARGET_NSIG_WORDS; i++) { -+ __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); -+ } -+ -+ /* -+ * Arguments to signal handler: -+ * -+ * a0 = signal number -+ * a1 = pointer to siginfo_t -+ * a2 = pointer to ucontext_t -+ * -+ * $25 and PC point to the signal handler, $29 points to the -+ * struct sigframe. -+ */ -+ env->active_tc.gpr[4] = sig; -+ env->active_tc.gpr[5] = frame_addr -+ + offsetof(struct target_rt_sigframe, rs_info); -+ env->active_tc.gpr[6] = frame_addr -+ + offsetof(struct target_rt_sigframe, rs_uc); -+ env->active_tc.gpr[3] = frame_addr; -+ env->active_tc.gpr[1] = frame_addr -+ + offsetof(struct target_rt_sigframe, rs_code); -+ /* The original kernel code sets CP0_ERA to the handler -+ * since it returns to userland using ertn -+ * we cannot do this here, and we must set PC directly */ -+ env->active_tc.PC = env->active_tc.gpr[20] = ka->_sa_handler; -+ unlock_user_struct(frame, frame_addr, 1); -+ return; -+ -+give_sigsegv: -+ unlock_user_struct(frame, frame_addr, 1); -+ force_sigsegv(sig); -+} -+ -+long do_rt_sigreturn(CPULOONGARCHState *env) -+{ -+ struct target_rt_sigframe *frame; -+ abi_ulong frame_addr; -+ sigset_t blocked; -+ -+ frame_addr = env->active_tc.gpr[3]; -+ trace_user_do_rt_sigreturn(env, frame_addr); -+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { -+ goto badframe; -+ } -+ -+ target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); -+ set_sigmask(&blocked); -+ -+ restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); -+ -+ if (do_sigaltstack(frame_addr + -+ offsetof(struct target_rt_sigframe, rs_uc.tuc_stack), -+ 0, get_sp_from_cpustate(env)) == -EFAULT) -+ goto badframe; -+ -+ env->active_tc.PC = env->CSR_ERA; -+ /* I am not sure this is right, but it seems to work -+ * maybe a problem with nested signals ? */ -+ env->CSR_ERA = 0; -+ return -TARGET_QEMU_ESIGRETURN; -+ -+badframe: -+ force_sig(TARGET_SIGSEGV); -+ return -TARGET_QEMU_ESIGRETURN; -+} -diff --git a/linux-user/loongarch64/sockbits.h b/linux-user/loongarch64/sockbits.h -new file mode 100644 -index 000000000..0e4c8f012 ---- /dev/null -+++ b/linux-user/loongarch64/sockbits.h -@@ -0,0 +1 @@ -+#include "../generic/sockbits.h" -diff --git a/linux-user/loongarch64/syscall_nr.h b/linux-user/loongarch64/syscall_nr.h -new file mode 100644 -index 000000000..a30aca8d8 ---- /dev/null -+++ b/linux-user/loongarch64/syscall_nr.h -@@ -0,0 +1,287 @@ -+#ifndef LINUX_USER_LOONGARCH_SYSCALL_NR_H -+#define LINUX_USER_LOONGARCH_SYSCALL_NR_H -+ -+#define TARGET_NR_io_setup 0 -+#define TARGET_NR_io_destroy 1 -+#define TARGET_NR_io_submit 2 -+#define TARGET_NR_io_cancel 3 -+#define TARGET_NR_io_getevents 4 -+#define TARGET_NR_setxattr 5 -+#define TARGET_NR_lsetxattr 6 -+#define TARGET_NR_fsetxattr 7 -+#define TARGET_NR_getxattr 8 -+#define TARGET_NR_lgetxattr 9 -+#define TARGET_NR_fgetxattr 10 -+#define TARGET_NR_listxattr 11 -+#define TARGET_NR_llistxattr 12 -+#define TARGET_NR_flistxattr 13 -+#define TARGET_NR_removexattr 14 -+#define TARGET_NR_lremovexattr 15 -+#define TARGET_NR_fremovexattr 16 -+#define TARGET_NR_getcwd 17 -+#define TARGET_NR_lookup_dcookie 18 -+#define TARGET_NR_eventfd2 19 -+#define TARGET_NR_epoll_create1 20 -+#define TARGET_NR_epoll_ctl 21 -+#define TARGET_NR_epoll_pwait 22 -+#define TARGET_NR_dup 23 -+#define TARGET_NR_dup3 24 -+#define TARGET_NR_fcntl 25 -+#define TARGET_NR_inotify_init1 26 -+#define TARGET_NR_inotify_add_watch 27 -+#define TARGET_NR_inotify_rm_watch 28 -+#define TARGET_NR_ioctl 29 -+#define TARGET_NR_ioprio_set 30 -+#define TARGET_NR_ioprio_get 31 -+#define TARGET_NR_flock 32 -+#define TARGET_NR_mknodat 33 -+#define TARGET_NR_mkdirat 34 -+#define TARGET_NR_unlinkat 35 -+#define TARGET_NR_symlinkat 36 -+#define TARGET_NR_linkat 37 -+#define TARGET_NR_renameat 38 -+#define TARGET_NR_umount2 39 -+#define TARGET_NR_mount 40 -+#define TARGET_NR_pivot_root 41 -+#define TARGET_NR_nfsservctl 42 -+#define TARGET_NR_statfs 43 -+#define TARGET_NR_fstatfs 44 -+#define TARGET_NR_truncate 45 -+#define TARGET_NR_ftruncate 46 -+#define TARGET_NR_fallocate 47 -+#define TARGET_NR_faccessat 48 -+#define TARGET_NR_chdir 49 -+#define TARGET_NR_fchdir 50 -+#define TARGET_NR_chroot 51 -+#define TARGET_NR_fchmod 52 -+#define TARGET_NR_fchmodat 53 -+#define TARGET_NR_fchownat 54 -+#define TARGET_NR_fchown 55 -+#define TARGET_NR_openat 56 -+#define TARGET_NR_close 57 -+#define TARGET_NR_vhangup 58 -+#define TARGET_NR_pipe2 59 -+#define TARGET_NR_quotactl 60 -+#define TARGET_NR_getdents64 61 -+#define TARGET_NR_lseek 62 -+#define TARGET_NR_read 63 -+#define TARGET_NR_write 64 -+#define TARGET_NR_readv 65 -+#define TARGET_NR_writev 66 -+#define TARGET_NR_pread64 67 -+#define TARGET_NR_pwrite64 68 -+#define TARGET_NR_preadv 69 -+#define TARGET_NR_pwritev 70 -+#define TARGET_NR_sendfile 71 -+#define TARGET_NR_pselect6 72 -+#define TARGET_NR_ppoll 73 -+#define TARGET_NR_signalfd4 74 -+#define TARGET_NR_vmsplice 75 -+#define TARGET_NR_splice 76 -+#define TARGET_NR_tee 77 -+#define TARGET_NR_readlinkat 78 -+#define TARGET_NR_newfstatat 79 -+#define TARGET_NR_fstat 80 -+#define TARGET_NR_sync 81 -+#define TARGET_NR_fsync 82 -+#define TARGET_NR_fdatasync 83 -+#define TARGET_NR_sync_file_range 84 -+#define TARGET_NR_timerfd_create 85 -+#define TARGET_NR_timerfd_settime 86 -+#define TARGET_NR_timerfd_gettime 87 -+#define TARGET_NR_utimensat 88 -+#define TARGET_NR_acct 89 -+#define TARGET_NR_capget 90 -+#define TARGET_NR_capset 91 -+#define TARGET_NR_personality 92 -+#define TARGET_NR_exit 93 -+#define TARGET_NR_exit_group 94 -+#define TARGET_NR_waitid 95 -+#define TARGET_NR_set_tid_address 96 -+#define TARGET_NR_unshare 97 -+#define TARGET_NR_futex 98 -+#define TARGET_NR_set_robust_list 99 -+#define TARGET_NR_get_robust_list 100 -+#define TARGET_NR_nanosleep 101 -+#define TARGET_NR_getitimer 102 -+#define TARGET_NR_setitimer 103 -+#define TARGET_NR_kexec_load 104 -+#define TARGET_NR_init_module 105 -+#define TARGET_NR_delete_module 106 -+#define TARGET_NR_timer_create 107 -+#define TARGET_NR_timer_gettime 108 -+#define TARGET_NR_timer_getoverrun 109 -+#define TARGET_NR_timer_settime 110 -+#define TARGET_NR_timer_delete 111 -+#define TARGET_NR_clock_settime 112 -+#define TARGET_NR_clock_gettime 113 -+#define TARGET_NR_clock_getres 114 -+#define TARGET_NR_clock_nanosleep 115 -+#define TARGET_NR_syslog 116 -+#define TARGET_NR_ptrace 117 -+#define TARGET_NR_sched_setparam 118 -+#define TARGET_NR_sched_setscheduler 119 -+#define TARGET_NR_sched_getscheduler 120 -+#define TARGET_NR_sched_getparam 121 -+#define TARGET_NR_sched_setaffinity 122 -+#define TARGET_NR_sched_getaffinity 123 -+#define TARGET_NR_sched_yield 124 -+#define TARGET_NR_sched_get_priority_max 125 -+#define TARGET_NR_sched_get_priority_min 126 -+#define TARGET_NR_sched_rr_get_interval 127 -+#define TARGET_NR_restart_syscall 128 -+#define TARGET_NR_kill 129 -+#define TARGET_NR_tkill 130 -+#define TARGET_NR_tgkill 131 -+#define TARGET_NR_sigaltstack 132 -+#define TARGET_NR_rt_sigsuspend 133 -+#define TARGET_NR_rt_sigaction 134 -+#define TARGET_NR_rt_sigprocmask 135 -+#define TARGET_NR_rt_sigpending 136 -+#define TARGET_NR_rt_sigtimedwait 137 -+#define TARGET_NR_rt_sigqueueinfo 138 -+#define TARGET_NR_rt_sigreturn 139 -+#define TARGET_NR_setpriority 140 -+#define TARGET_NR_getpriority 141 -+#define TARGET_NR_reboot 142 -+#define TARGET_NR_setregid 143 -+#define TARGET_NR_setgid 144 -+#define TARGET_NR_setreuid 145 -+#define TARGET_NR_setuid 146 -+#define TARGET_NR_setresuid 147 -+#define TARGET_NR_getresuid 148 -+#define TARGET_NR_setresgid 149 -+#define TARGET_NR_getresgid 150 -+#define TARGET_NR_setfsuid 151 -+#define TARGET_NR_setfsgid 152 -+#define TARGET_NR_times 153 -+#define TARGET_NR_setpgid 154 -+#define TARGET_NR_getpgid 155 -+#define TARGET_NR_getsid 156 -+#define TARGET_NR_setsid 157 -+#define TARGET_NR_getgroups 158 -+#define TARGET_NR_setgroups 159 -+#define TARGET_NR_uname 160 -+#define TARGET_NR_sethostname 161 -+#define TARGET_NR_setdomainname 162 -+#define TARGET_NR_getrlimit 163 -+#define TARGET_NR_setrlimit 164 -+#define TARGET_NR_getrusage 165 -+#define TARGET_NR_umask 166 -+#define TARGET_NR_prctl 167 -+#define TARGET_NR_getcpu 168 -+#define TARGET_NR_gettimeofday 169 -+#define TARGET_NR_settimeofday 170 -+#define TARGET_NR_adjtimex 171 -+#define TARGET_NR_getpid 172 -+#define TARGET_NR_getppid 173 -+#define TARGET_NR_getuid 174 -+#define TARGET_NR_geteuid 175 -+#define TARGET_NR_getgid 176 -+#define TARGET_NR_getegid 177 -+#define TARGET_NR_gettid 178 -+#define TARGET_NR_sysinfo 179 -+#define TARGET_NR_mq_open 180 -+#define TARGET_NR_mq_unlink 181 -+#define TARGET_NR_mq_timedsend 182 -+#define TARGET_NR_mq_timedreceive 183 -+#define TARGET_NR_mq_notify 184 -+#define TARGET_NR_mq_getsetattr 185 -+#define TARGET_NR_msgget 186 -+#define TARGET_NR_msgctl 187 -+#define TARGET_NR_msgrcv 188 -+#define TARGET_NR_msgsnd 189 -+#define TARGET_NR_semget 190 -+#define TARGET_NR_semctl 191 -+#define TARGET_NR_semtimedop 192 -+#define TARGET_NR_semop 193 -+#define TARGET_NR_shmget 194 -+#define TARGET_NR_shmctl 195 -+#define TARGET_NR_shmat 196 -+#define TARGET_NR_shmdt 197 -+#define TARGET_NR_socket 198 -+#define TARGET_NR_socketpair 199 -+#define TARGET_NR_bind 200 -+#define TARGET_NR_listen 201 -+#define TARGET_NR_accept 202 -+#define TARGET_NR_connect 203 -+#define TARGET_NR_getsockname 204 -+#define TARGET_NR_getpeername 205 -+#define TARGET_NR_sendto 206 -+#define TARGET_NR_recvfrom 207 -+#define TARGET_NR_setsockopt 208 -+#define TARGET_NR_getsockopt 209 -+#define TARGET_NR_shutdown 210 -+#define TARGET_NR_sendmsg 211 -+#define TARGET_NR_recvmsg 212 -+#define TARGET_NR_readahead 213 -+#define TARGET_NR_brk 214 -+#define TARGET_NR_munmap 215 -+#define TARGET_NR_mremap 216 -+#define TARGET_NR_add_key 217 -+#define TARGET_NR_request_key 218 -+#define TARGET_NR_keyctl 219 -+#define TARGET_NR_clone 220 -+#define TARGET_NR_execve 221 -+#define TARGET_NR_mmap 222 -+#define TARGET_NR_fadvise64 223 -+#define TARGET_NR_swapon 224 -+#define TARGET_NR_swapoff 225 -+#define TARGET_NR_mprotect 226 -+#define TARGET_NR_msync 227 -+#define TARGET_NR_mlock 228 -+#define TARGET_NR_munlock 229 -+#define TARGET_NR_mlockall 230 -+#define TARGET_NR_munlockall 231 -+#define TARGET_NR_mincore 232 -+#define TARGET_NR_madvise 233 -+#define TARGET_NR_remap_file_pages 234 -+#define TARGET_NR_mbind 235 -+#define TARGET_NR_get_mempolicy 236 -+#define TARGET_NR_set_mempolicy 237 -+#define TARGET_NR_migrate_pages 238 -+#define TARGET_NR_move_pages 239 -+#define TARGET_NR_rt_tgsigqueueinfo 240 -+#define TARGET_NR_perf_event_open 241 -+#define TARGET_NR_accept4 242 -+#define TARGET_NR_recvmmsg 243 -+#define TARGET_NR_arch_specific_syscall 244 -+#define TARGET_NR_wait4 260 -+#define TARGET_NR_prlimit64 261 -+#define TARGET_NR_fanotify_init 262 -+#define TARGET_NR_fanotify_mark 263 -+#define TARGET_NR_name_to_handle_at 264 -+#define TARGET_NR_open_by_handle_at 265 -+#define TARGET_NR_clock_adjtime 266 -+#define TARGET_NR_syncfs 267 -+#define TARGET_NR_setns 268 -+#define TARGET_NR_sendmmsg 269 -+#define TARGET_NR_process_vm_readv 270 -+#define TARGET_NR_process_vm_writev 271 -+#define TARGET_NR_kcmp 272 -+#define TARGET_NR_finit_module 273 -+#define TARGET_NR_sched_setattr 274 -+#define TARGET_NR_sched_getattr 275 -+#define TARGET_NR_renameat2 276 -+#define TARGET_NR_seccomp 277 -+#define TARGET_NR_getrandom 278 -+#define TARGET_NR_memfd_create 279 -+#define TARGET_NR_bpf 280 -+#define TARGET_NR_execveat 281 -+#define TARGET_NR_userfaultfd 282 -+#define TARGET_NR_membarrier 283 -+#define TARGET_NR_mlock2 284 -+#define TARGET_NR_copy_file_range 285 -+#define TARGET_NR_preadv2 286 -+#define TARGET_NR_pwritev2 287 -+#define TARGET_NR_pkey_mprotect 288 -+#define TARGET_NR_pkey_alloc 289 -+#define TARGET_NR_pkey_free 290 -+#define TARGET_NR_statx 291 -+#define TARGET_NR_io_pgetevents 292 -+#define TARGET_NR_rseq 293 -+#define TARGET_NR_kexec_file_load 294 -+ -+#define TARGET_NR_syscalls (TARGET_NR_kexec_file_load + 1) -+ -+#endif -diff --git a/linux-user/loongarch64/target_cpu.h b/linux-user/loongarch64/target_cpu.h -new file mode 100644 -index 000000000..0f6845737 ---- /dev/null -+++ b/linux-user/loongarch64/target_cpu.h -@@ -0,0 +1,45 @@ -+/* -+ * MIPS specific CPU ABI and functions for linux-user -+ * -+ * Copyright (c) 2004-2005 Jocelyn Mayer -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+#ifndef LOONGARCH_TARGET_CPU_H -+#define LOONGARCH_TARGET_CPU_H -+ -+static inline void cpu_clone_regs_child(CPULOONGARCHState *env, target_ulong newsp, -+ unsigned flags) -+{ -+ if (newsp) { -+ env->active_tc.gpr[3] = newsp; -+ } -+ env->active_tc.gpr[7] = 0; -+ env->active_tc.gpr[4] = 0; -+} -+ -+static inline void cpu_clone_regs_parent(CPULOONGARCHState *env, unsigned flags) -+{ -+} -+ -+static inline void cpu_set_tls(CPULOONGARCHState *env, target_ulong newtls) -+{ -+ env->active_tc.gpr[2] = newtls; -+} -+ -+static inline abi_ulong get_sp_from_cpustate(CPULOONGARCHState *state) -+{ -+ return state->active_tc.gpr[3]; -+} -+#endif -diff --git a/linux-user/loongarch64/target_elf.h b/linux-user/loongarch64/target_elf.h -new file mode 100644 -index 000000000..6c153d12c ---- /dev/null -+++ b/linux-user/loongarch64/target_elf.h -@@ -0,0 +1,14 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation, or (at your option) any -+ * later version. See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef LOONGARCH_TARGET_ELF_H -+#define LOONGARCH_TARGET_ELF_H -+static inline const char *cpu_get_model(uint32_t eflags) -+{ -+ return "Loongson-3A5000"; -+} -+#endif -diff --git a/linux-user/loongarch64/target_fcntl.h b/linux-user/loongarch64/target_fcntl.h -new file mode 100644 -index 000000000..a3d7b4606 ---- /dev/null -+++ b/linux-user/loongarch64/target_fcntl.h -@@ -0,0 +1,13 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation, or (at your option) any -+ * later version. See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef LOONGARCH_TARGET_FCNTL_H -+#define LOONGARCH_TARGET_FCNTL_H -+ -+#include "../generic/fcntl.h" -+ -+#endif /* LOONGARCH_TARGET_FCNTL_H */ -diff --git a/linux-user/loongarch64/target_signal.h b/linux-user/loongarch64/target_signal.h -new file mode 100644 -index 000000000..e418c8e8f ---- /dev/null -+++ b/linux-user/loongarch64/target_signal.h -@@ -0,0 +1,23 @@ -+#ifndef LOONGARCH_TARGET_SIGNAL_H -+#define LOONGARCH_TARGET_SIGNAL_H -+ -+/* this struct defines a stack used during syscall handling */ -+ -+typedef struct target_sigaltstack { -+ abi_long ss_sp; -+ abi_int ss_flags; -+ abi_ulong ss_size; -+} target_stack_t; -+ -+/* -+ * sigaltstack controls -+ */ -+#define TARGET_SS_ONSTACK 1 -+#define TARGET_SS_DISABLE 2 -+ -+#define TARGET_MINSIGSTKSZ 2048 -+#define TARGET_SIGSTKSZ 8192 -+ -+#include "../generic/signal.h" -+ -+#endif /* LOONGARCH_TARGET_SIGNAL_H */ -diff --git a/linux-user/loongarch64/target_structs.h b/linux-user/loongarch64/target_structs.h -new file mode 100644 -index 000000000..280acd097 ---- /dev/null -+++ b/linux-user/loongarch64/target_structs.h -@@ -0,0 +1,62 @@ -+/* -+ * LOONGARCH specific structures for linux-user -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+#ifndef LOONGARCH_TARGET_STRUCTS_H -+#define LOONGARCH_TARGET_STRUCTS_H -+ -+struct target_ipc_perm { -+ abi_int __key; /* Key. */ -+ abi_uint uid; /* Owner's user ID. */ -+ abi_uint gid; /* Owner's group ID. */ -+ abi_uint cuid; /* Creator's user ID. */ -+ abi_uint cgid; /* Creator's group ID. */ -+ abi_uint mode; /* Read/write permission. */ -+ abi_ushort __seq; /* Sequence number. */ -+ abi_ushort __pad1; -+ abi_ulong __unused1; -+ abi_ulong __unused2; -+}; -+ -+struct target_shmid_ds { -+ struct target_ipc_perm shm_perm; /* operation permission struct */ -+ abi_long shm_segsz; /* size of segment in bytes */ -+ abi_ulong shm_atime; /* time of last shmat() */ -+ abi_ulong shm_dtime; /* time of last shmdt() */ -+ abi_ulong shm_ctime; /* time of last change by shmctl() */ -+ abi_int shm_cpid; /* pid of creator */ -+ abi_int shm_lpid; /* pid of last shmop */ -+ abi_ulong shm_nattch; /* number of current attaches */ -+ abi_ulong __unused1; -+ abi_ulong __unused2; -+}; -+ -+#define TARGET_SEMID64_DS -+ -+/* -+ * The semid64_ds structure for the MIPS architecture. -+ * Note extra padding because this structure is passed back and forth -+ * between kernel and user space. -+ */ -+struct target_semid64_ds { -+ struct target_ipc_perm sem_perm; -+ abi_ulong sem_otime; -+ abi_ulong sem_ctime; -+ abi_ulong sem_nsems; -+ abi_ulong __unused1; -+ abi_ulong __unused2; -+}; -+ -+#endif -diff --git a/linux-user/loongarch64/target_syscall.h b/linux-user/loongarch64/target_syscall.h -new file mode 100644 -index 000000000..cb77f0708 ---- /dev/null -+++ b/linux-user/loongarch64/target_syscall.h -@@ -0,0 +1,44 @@ -+#ifndef LOONGARCH_TARGET_SYSCALL_H -+#define LOONGARCH_TARGET_SYSCALL_H -+ -+/* this struct defines the way the registers are stored on the -+ stack during a system call. */ -+ -+struct target_pt_regs { -+ /* Saved main processor registers. */ -+ target_ulong regs[32]; -+ -+ /* Saved special registers. */ -+ /* Saved special registers. */ -+ target_ulong csr_crmd; -+ target_ulong csr_prmd; -+ target_ulong csr_euen; -+ target_ulong csr_ecfg; -+ target_ulong csr_estat; -+ target_ulong csr_era; -+ target_ulong csr_badvaddr; -+ target_ulong orig_a0; -+ target_ulong __last[0]; -+}; -+ -+#define UNAME_MACHINE "loongarch" -+#define UNAME_MINIMUM_RELEASE "2.6.32" -+ -+#define TARGET_CLONE_BACKWARDS -+#define TARGET_MINSIGSTKSZ 2048 -+#define TARGET_MLOCKALL_MCL_CURRENT 1 -+#define TARGET_MLOCKALL_MCL_FUTURE 2 -+ -+#define TARGET_FORCE_SHMLBA -+ -+static inline abi_ulong target_shmlba(CPULOONGARCHState *env) -+{ -+ return 0x40000; -+} -+ -+#define TARGET_PR_SET_FP_MODE 45 -+#define TARGET_PR_GET_FP_MODE 46 -+#define TARGET_PR_FP_MODE_FR (1 << 0) -+#define TARGET_PR_FP_MODE_FRE (1 << 1) -+ -+#endif /* LOONGARCH_TARGET_SYSCALL_H */ -diff --git a/linux-user/loongarch64/termbits.h b/linux-user/loongarch64/termbits.h -new file mode 100644 -index 000000000..6c613a197 ---- /dev/null -+++ b/linux-user/loongarch64/termbits.h -@@ -0,0 +1,224 @@ -+#ifndef LINUX_USER_LOONGARCH_TERMBITS_H -+#define LINUX_USER_LOONGARCH_TERMBITS_H -+ -+#define TARGET_NCCS 19 -+ -+struct target_termios { -+ unsigned int c_iflag; /* input mode flags */ -+ unsigned int c_oflag; /* output mode flags */ -+ unsigned int c_cflag; /* control mode flags */ -+ unsigned int c_lflag; /* local mode flags */ -+ unsigned char c_line; /* line discipline */ -+ unsigned char c_cc[TARGET_NCCS]; /* control characters */ -+}; -+ -+/* c_iflag bits */ -+#define TARGET_IGNBRK 0000001 -+#define TARGET_BRKINT 0000002 -+#define TARGET_IGNPAR 0000004 -+#define TARGET_PARMRK 0000010 -+#define TARGET_INPCK 0000020 -+#define TARGET_ISTRIP 0000040 -+#define TARGET_INLCR 0000100 -+#define TARGET_IGNCR 0000200 -+#define TARGET_ICRNL 0000400 -+#define TARGET_IUCLC 0001000 -+#define TARGET_IXON 0002000 -+#define TARGET_IXANY 0004000 -+#define TARGET_IXOFF 0010000 -+#define TARGET_IMAXBEL 0020000 -+#define TARGET_IUTF8 0040000 -+ -+/* c_oflag bits */ -+#define TARGET_OPOST 0000001 -+#define TARGET_OLCUC 0000002 -+#define TARGET_ONLCR 0000004 -+#define TARGET_OCRNL 0000010 -+#define TARGET_ONOCR 0000020 -+#define TARGET_ONLRET 0000040 -+#define TARGET_OFILL 0000100 -+#define TARGET_OFDEL 0000200 -+#define TARGET_NLDLY 0000400 -+#define TARGET_NL0 0000000 -+#define TARGET_NL1 0000400 -+#define TARGET_CRDLY 0003000 -+#define TARGET_CR0 0000000 -+#define TARGET_CR1 0001000 -+#define TARGET_CR2 0002000 -+#define TARGET_CR3 0003000 -+#define TARGET_TABDLY 0014000 -+#define TARGET_TAB0 0000000 -+#define TARGET_TAB1 0004000 -+#define TARGET_TAB2 0010000 -+#define TARGET_TAB3 0014000 -+#define TARGET_XTABS 0014000 -+#define TARGET_BSDLY 0020000 -+#define TARGET_BS0 0000000 -+#define TARGET_BS1 0020000 -+#define TARGET_VTDLY 0040000 -+#define TARGET_VT0 0000000 -+#define TARGET_VT1 0040000 -+#define TARGET_FFDLY 0100000 -+#define TARGET_FF0 0000000 -+#define TARGET_FF1 0100000 -+ -+/* c_cflag bit meaning */ -+#define TARGET_CBAUD 0010017 -+#define TARGET_B0 0000000 /* hang up */ -+#define TARGET_B50 0000001 -+#define TARGET_B75 0000002 -+#define TARGET_B110 0000003 -+#define TARGET_B134 0000004 -+#define TARGET_B150 0000005 -+#define TARGET_B200 0000006 -+#define TARGET_B300 0000007 -+#define TARGET_B600 0000010 -+#define TARGET_B1200 0000011 -+#define TARGET_B1800 0000012 -+#define TARGET_B2400 0000013 -+#define TARGET_B4800 0000014 -+#define TARGET_B9600 0000015 -+#define TARGET_B19200 0000016 -+#define TARGET_B38400 0000017 -+#define TARGET_EXTA B19200 -+#define TARGET_EXTB B38400 -+#define TARGET_CSIZE 0000060 -+#define TARGET_CS5 0000000 -+#define TARGET_CS6 0000020 -+#define TARGET_CS7 0000040 -+#define TARGET_CS8 0000060 -+#define TARGET_CSTOPB 0000100 -+#define TARGET_CREAD 0000200 -+#define TARGET_PARENB 0000400 -+#define TARGET_PARODD 0001000 -+#define TARGET_HUPCL 0002000 -+#define TARGET_CLOCAL 0004000 -+#define TARGET_CBAUDEX 0010000 -+#define TARGET_B57600 0010001 -+#define TARGET_B115200 0010002 -+#define TARGET_B230400 0010003 -+#define TARGET_B460800 0010004 -+#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ -+#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ -+#define TARGET_CRTSCTS 020000000000 /* flow control */ -+ -+/* c_lflag bits */ -+#define TARGET_ISIG 0000001 -+#define TARGET_ICANON 0000002 -+#define TARGET_XCASE 0000004 -+#define TARGET_ECHO 0000010 -+#define TARGET_ECHOE 0000020 -+#define TARGET_ECHOK 0000040 -+#define TARGET_ECHONL 0000100 -+#define TARGET_NOFLSH 0000200 -+#define TARGET_TOSTOP 0000400 -+#define TARGET_ECHOCTL 0001000 -+#define TARGET_ECHOPRT 0002000 -+#define TARGET_ECHOKE 0004000 -+#define TARGET_FLUSHO 0010000 -+#define TARGET_PENDIN 0040000 -+#define TARGET_IEXTEN 0100000 -+ -+/* c_cc character offsets */ -+#define TARGET_VINTR 0 -+#define TARGET_VQUIT 1 -+#define TARGET_VERASE 2 -+#define TARGET_VKILL 3 -+#define TARGET_VEOF 4 -+#define TARGET_VTIME 5 -+#define TARGET_VMIN 6 -+#define TARGET_VSWTC 7 -+#define TARGET_VSTART 8 -+#define TARGET_VSTOP 9 -+#define TARGET_VSUSP 10 -+#define TARGET_VEOL 11 -+#define TARGET_VREPRINT 12 -+#define TARGET_VDISCARD 13 -+#define TARGET_VWERASE 14 -+#define TARGET_VLNEXT 15 -+#define TARGET_VEOL2 16 -+ -+/* ioctls */ -+ -+#define TARGET_TCGETS 0x5401 -+#define TARGET_TCSETS 0x5402 -+#define TARGET_TCSETSW 0x5403 -+#define TARGET_TCSETSF 0x5404 -+#define TARGET_TCGETA 0x5405 -+#define TARGET_TCSETA 0x5406 -+#define TARGET_TCSETAW 0x5407 -+#define TARGET_TCSETAF 0x5408 -+#define TARGET_TCSBRK 0x5409 -+#define TARGET_TCXONC 0x540A -+#define TARGET_TCFLSH 0x540B -+ -+#define TARGET_TIOCEXCL 0x540C -+#define TARGET_TIOCNXCL 0x540D -+#define TARGET_TIOCSCTTY 0x540E -+#define TARGET_TIOCGPGRP 0x540F -+#define TARGET_TIOCSPGRP 0x5410 -+#define TARGET_TIOCOUTQ 0x5411 -+#define TARGET_TIOCSTI 0x5412 -+#define TARGET_TIOCGWINSZ 0x5413 -+#define TARGET_TIOCSWINSZ 0x5414 -+#define TARGET_TIOCMGET 0x5415 -+#define TARGET_TIOCMBIS 0x5416 -+#define TARGET_TIOCMBIC 0x5417 -+#define TARGET_TIOCMSET 0x5418 -+#define TARGET_TIOCGSOFTCAR 0x5419 -+#define TARGET_TIOCSSOFTCAR 0x541A -+#define TARGET_FIONREAD 0x541B -+#define TARGET_TIOCINQ TARGET_FIONREAD -+#define TARGET_TIOCLINUX 0x541C -+#define TARGET_TIOCCONS 0x541D -+#define TARGET_TIOCGSERIAL 0x541E -+#define TARGET_TIOCSSERIAL 0x541F -+#define TARGET_TIOCPKT 0x5420 -+#define TARGET_FIONBIO 0x5421 -+#define TARGET_TIOCNOTTY 0x5422 -+#define TARGET_TIOCSETD 0x5423 -+#define TARGET_TIOCGETD 0x5424 -+#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -+#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ -+#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ -+#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ -+#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ -+#define TARGET_TIOCGPTN TARGET_IOR('T', 0x30, unsigned int) -+ /* Get Pty Number (of pty-mux device) */ -+#define TARGET_TIOCSPTLCK TARGET_IOW('T', 0x31, int) -+ /* Lock/unlock Pty */ -+#define TARGET_TIOCGPTPEER TARGET_IO('T', 0x41) -+ /* Safely open the slave */ -+ -+#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ -+#define TARGET_FIOCLEX 0x5451 -+#define TARGET_FIOASYNC 0x5452 -+#define TARGET_TIOCSERCONFIG 0x5453 -+#define TARGET_TIOCSERGWILD 0x5454 -+#define TARGET_TIOCSERSWILD 0x5455 -+#define TARGET_TIOCGLCKTRMIOS 0x5456 -+#define TARGET_TIOCSLCKTRMIOS 0x5457 -+#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ -+#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ -+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ -+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ -+ -+#define TARGET_TIOCMIWAIT 0x545C -+ /* wait for a change on serial input line(s) */ -+#define TARGET_TIOCGICOUNT 0x545D -+ /* read serial port inline interrupt counts */ -+#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -+#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ -+ -+/* Used for packet mode */ -+#define TARGET_TIOCPKT_DATA 0 -+#define TARGET_TIOCPKT_FLUSHREAD 1 -+#define TARGET_TIOCPKT_FLUSHWRITE 2 -+#define TARGET_TIOCPKT_STOP 4 -+#define TARGET_TIOCPKT_START 8 -+#define TARGET_TIOCPKT_NOSTOP 16 -+#define TARGET_TIOCPKT_DOSTOP 32 -+ -+#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -+ -+#endif --- -2.43.5 - diff --git a/0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch b/0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch deleted file mode 100644 index 97cb7cca054d10dc16c43984f8096486c588c8c7..0000000000000000000000000000000000000000 --- a/0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 501e16b4b4cf5a302363c1ae55fb4fb8e68beb8d Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Tue, 24 Aug 2021 17:31:28 +0800 -Subject: [PATCH 5/8] anolis: cpu/i386: populate CPUID 0x8000_001F when CSV is - active - -On Hygon platform, bit 30 of EAX indicates whether -this feature is supported in hardware. - -When CSV is active, CPUID 0x8000_001F provides -information for it. - -Signed-off-by: Xin Jiang -Change-Id: Ifdd2a20f7cb4a079ba918928f012e5f64f7059e6 ---- - target/i386/cpu.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index aa9e636800..970d9bf184 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -27,6 +27,7 @@ - #include "sysemu/hvf.h" - #include "kvm/kvm_i386.h" - #include "sev.h" -+#include "csv.h" - #include "qapi/error.h" - #include "qapi/qapi-visit-machine.h" - #include "qapi/qmp/qerror.h" -@@ -5769,6 +5770,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - if (sev_enabled()) { - *eax = 0x2; - *eax |= sev_es_enabled() ? 0x8 : 0; -+ *eax |= csv_enabled() ? 0x40000000 : 0; /* bit 30 for CSV */ - *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */ - *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */ - } --- -2.17.1 - diff --git a/0006-Add-disas-gdb.patch b/0006-Add-disas-gdb.patch deleted file mode 100644 index 97e9a6d84400e83434066de66efa1973ee0bb150..0000000000000000000000000000000000000000 --- a/0006-Add-disas-gdb.patch +++ /dev/null @@ -1,3183 +0,0 @@ -From dbf0724c5c9e7928f0007e6a5e0009cabba90457 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Fri, 19 Aug 2022 23:51:12 -0400 -Subject: [PATCH 06/28] Add disas gdb. - -Change-Id: If41c0fc8aa128796e342319c7673fab3ccbf3913 -Signed-off-by: lixianglai ---- - .../devices/loongarch64-softmmu/default.mak | 154 + - configs/targets/loongarch64-softmmu.mak | 4 + - disas/loongarch.c | 2748 +++++++++++++++++ - disas/meson.build | 1 + - gdb-xml/loongarch-base32.xml | 43 + - gdb-xml/loongarch-base64.xml | 43 + - gdb-xml/loongarch-fpu32.xml | 52 + - gdb-xml/loongarch-fpu64.xml | 57 + - 8 files changed, 3102 insertions(+) - create mode 100644 configs/devices/loongarch64-softmmu/default.mak - create mode 100644 configs/targets/loongarch64-softmmu.mak - create mode 100644 disas/loongarch.c - create mode 100644 gdb-xml/loongarch-base32.xml - create mode 100644 gdb-xml/loongarch-base64.xml - create mode 100644 gdb-xml/loongarch-fpu32.xml - create mode 100644 gdb-xml/loongarch-fpu64.xml - -diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak -new file mode 100644 -index 000000000..fcb7e45dd ---- /dev/null -+++ b/configs/devices/loongarch64-softmmu/default.mak -@@ -0,0 +1,154 @@ -+# Default configuration for loongarch-softmmu -+ -+CONFIG_PCI=y -+CONFIG_ACPI_PCI=y -+# For now, CONFIG_IDE_CORE requires ISA, so we enable it here -+CONFIG_ISA_BUS=y -+CONFIG_VIRTIO_PCI=y -+ -+CONFIG_VGA_PCI=y -+CONFIG_ACPI_SMBUS=y -+#CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+CONFIG_VHOST_USER_SCSI=y -+#CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+CONFIG_VHOST_USER_BLK=y -+CONFIG_VIRTIO=y -+CONFIG_VIRTIO_BALLOON=y -+CONFIG_VIRTIO_BLK=y -+CONFIG_VIRTIO_CRYPTO=y -+CONFIG_VIRTIO_GPU=y -+CONFIG_VIRTIO_INPUT=y -+CONFIG_VIRTIO_NET=y -+CONFIG_VIRTIO_RNG=y -+CONFIG_SCSI=y -+CONFIG_VIRTIO_SCSI=y -+CONFIG_VIRTIO_SERIAL=y -+ -+CONFIG_USB_UHCI=y -+CONFIG_USB_OHCI=y -+CONFIG_USB_OHCI_PCI=y -+CONFIG_USB_XHCI=y -+CONFIG_USB_XHCI_NEC=y -+CONFIG_NE2000_PCI=y -+CONFIG_EEPRO100_PCI=y -+CONFIG_PCNET_PCI=y -+CONFIG_PCNET_COMMON=y -+CONFIG_AC97=y -+CONFIG_HDA=y -+CONFIG_ES1370=y -+CONFIG_SCSI=y -+CONFIG_LSI_SCSI_PCI=y -+CONFIG_VMW_PVSCSI_SCSI_PCI=y -+CONFIG_MEGASAS_SCSI_PCI=y -+CONFIG_MPTSAS_SCSI_PCI=y -+CONFIG_RTL8139_PCI=y -+CONFIG_E1000_PCI=y -+CONFIG_IDE_CORE=y -+CONFIG_IDE_QDEV=y -+CONFIG_IDE_PCI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_ICH9=y -+CONFIG_ESP=y -+CONFIG_ESP_PCI=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_SERIAL_PCI=y -+CONFIG_CAN_BUS=y -+CONFIG_CAN_SJA1000=y -+CONFIG_CAN_PCI=y -+CONFIG_USB_UHCI=y -+CONFIG_USB_OHCI=y -+CONFIG_USB_XHCI=y -+CONFIG_USB_XHCI_NEC=y -+CONFIG_NE2000_PCI=y -+CONFIG_EEPRO100_PCI=y -+CONFIG_PCNET_PCI=y -+CONFIG_PCNET_COMMON=y -+CONFIG_AC97=y -+CONFIG_HDA=y -+CONFIG_ES1370=y -+CONFIG_SCSI=y -+CONFIG_LSI_SCSI_PCI=y -+CONFIG_VMW_PVSCSI_SCSI_PCI=y -+CONFIG_MEGASAS_SCSI_PCI=y -+CONFIG_MPTSAS_SCSI_PCI=y -+CONFIG_RTL8139_PCI=y -+CONFIG_E1000_PCI=y -+CONFIG_IDE_CORE=y -+CONFIG_IDE_QDEV=y -+CONFIG_IDE_PCI=y -+CONFIG_AHCI=y -+CONFIG_ESP=y -+CONFIG_ESP_PCI=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_SERIAL_PCI=y -+CONFIG_CAN_BUS=y -+CONFIG_CAN_SJA1000=y -+CONFIG_CAN_PCI=y -+ -+CONFIG_SPICE=y -+CONFIG_QXL=y -+CONFIG_ESP=y -+CONFIG_SCSI=y -+CONFIG_VGA_ISA=y -+CONFIG_VGA_ISA_MM=y -+CONFIG_VGA_CIRRUS=y -+CONFIG_VMWARE_VGA=y -+CONFIG_VIRTIO_VGA=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_PARALLEL=y -+CONFIG_I8254=y -+CONFIG_PCSPK=y -+CONFIG_PCKBD=y -+CONFIG_FDC=y -+CONFIG_ACPI=y -+CONFIG_ACPI_MEMORY_HOTPLUG=y -+CONFIG_ACPI_NVDIMM=y -+CONFIG_ACPI_CPU_HOTPLUG=y -+CONFIG_APM=y -+CONFIG_I8257=y -+CONFIG_PIIX4=y -+CONFIG_IDE_ISA=y -+CONFIG_IDE_PIIX=y -+#CONFIG_NE2000_ISA=y -+CONFIG_MIPSNET=y -+CONFIG_PFLASH_CFI01=y -+CONFIG_I8259=y -+CONFIG_MC146818RTC=y -+CONFIG_ISA_TESTDEV=y -+CONFIG_EMPTY_SLOT=y -+CONFIG_I2C=y -+CONFIG_DIMM=y -+CONFIG_MEM_DEVICE=y -+ -+# Arch Specified CONFIG defines -+CONFIG_IDE_VIA=y -+CONFIG_VT82C686=y -+CONFIG_RC4030=y -+CONFIG_DP8393X=y -+CONFIG_DS1225Y=y -+CONFIG_FITLOADER=y -+CONFIG_SMBIOS=y -+ -+CONFIG_PCIE_PORT=y -+CONFIG_I82801B11=y -+CONFIG_XIO3130=y -+CONFIG_PCI_EXPRESS=y -+CONFIG_MSI_NONBROKEN=y -+CONFIG_IOH3420=y -+CONFIG_SD=y -+CONFIG_SDHCI=y -+CONFIG_VIRTFS=y -+CONFIG_VIRTIO_9P=y -+CONFIG_USB_EHCI=y -+CONFIG_USB_EHCI_PCI=y -+CONFIG_USB_EHCI_SYSBUS=y -+CONFIG_USB_STORAGE_BOT=y -+CONFIG_TPM_EMULATOR=y -+CONFIG_TPM_TIS=y -+CONFIG_PLATFORM_BUS=y -+CONFIG_TPM_TIS_SYSBUS=y -+CONFIG_ACPI_LOONGARCH=y -+CONFIG_LS7A_RTC=y -diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak -new file mode 100644 -index 000000000..dc5ab3966 ---- /dev/null -+++ b/configs/targets/loongarch64-softmmu.mak -@@ -0,0 +1,4 @@ -+TARGET_ARCH=loongarch64 -+TARGET_SUPPORTS_MTTCG=y -+TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml -+ -diff --git a/disas/loongarch.c b/disas/loongarch.c -new file mode 100644 -index 000000000..14dd131e2 ---- /dev/null -+++ b/disas/loongarch.c -@@ -0,0 +1,2748 @@ -+/* -+ * QEMU Loongarch Disassembler -+ * -+ * Copyright (c) 2020-2021. -+ * Author: Song Gao, gaosong@loongson.cn -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program. If not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "disas/dis-asm.h" -+ -+#define INSNLEN 4 -+ -+/* types */ -+ -+typedef uint16_t la_opcode; -+ -+/* enums */ -+ -+typedef enum { -+ la_op_illegal = 0, -+ la_op_gr2scr = 1, -+ la_op_scr2gr = 2, -+ la_op_clo_w = 3, -+ la_op_clz_w = 4, -+ la_op_cto_w = 5, -+ la_op_ctz_w = 6, -+ la_op_clo_d = 7, -+ la_op_clz_d = 8, -+ la_op_cto_d = 9, -+ la_op_ctz_d = 10, -+ la_op_revb_2h = 11, -+ la_op_revb_4h = 12, -+ la_op_revb_2w = 13, -+ la_op_revb_d = 14, -+ la_op_revh_2w = 15, -+ la_op_revh_d = 16, -+ la_op_bitrev_4b = 17, -+ la_op_bitrev_8b = 18, -+ la_op_bitrev_w = 19, -+ la_op_bitrev_d = 20, -+ la_op_ext_w_h = 21, -+ la_op_ext_w_b = 22, -+ la_op_rdtime_d = 23, -+ la_op_cpucfg = 24, -+ la_op_asrtle_d = 25, -+ la_op_asrtgt_d = 26, -+ la_op_alsl_w = 27, -+ la_op_alsl_wu = 28, -+ la_op_bytepick_w = 29, -+ la_op_bytepick_d = 30, -+ la_op_add_w = 31, -+ la_op_add_d = 32, -+ la_op_sub_w = 33, -+ la_op_sub_d = 34, -+ la_op_slt = 35, -+ la_op_sltu = 36, -+ la_op_maskeqz = 37, -+ la_op_masknez = 38, -+ la_op_nor = 39, -+ la_op_and = 40, -+ la_op_or = 41, -+ la_op_xor = 42, -+ la_op_orn = 43, -+ la_op_andn = 44, -+ la_op_sll_w = 45, -+ la_op_srl_w = 46, -+ la_op_sra_w = 47, -+ la_op_sll_d = 48, -+ la_op_srl_d = 49, -+ la_op_sra_d = 50, -+ la_op_rotr_w = 51, -+ la_op_rotr_d = 52, -+ la_op_mul_w = 53, -+ la_op_mulh_w = 54, -+ la_op_mulh_wu = 55, -+ la_op_mul_d = 56, -+ la_op_mulh_d = 57, -+ la_op_mulh_du = 58, -+ la_op_mulw_d_w = 59, -+ la_op_mulw_d_wu = 60, -+ la_op_div_w = 61, -+ la_op_mod_w = 62, -+ la_op_div_wu = 63, -+ la_op_mod_wu = 64, -+ la_op_div_d = 65, -+ la_op_mod_d = 66, -+ la_op_div_du = 67, -+ la_op_mod_du = 68, -+ la_op_crc_w_b_w = 69, -+ la_op_crc_w_h_w = 70, -+ la_op_crc_w_w_w = 71, -+ la_op_crc_w_d_w = 72, -+ la_op_crcc_w_b_w = 73, -+ la_op_crcc_w_h_w = 74, -+ la_op_crcc_w_w_w = 75, -+ la_op_crcc_w_d_w = 76, -+ la_op_break = 77, -+ la_op_dbcl = 78, -+ la_op_syscall = 79, -+ la_op_alsl_d = 80, -+ la_op_slli_w = 81, -+ la_op_slli_d = 82, -+ la_op_srli_w = 83, -+ la_op_srli_d = 84, -+ la_op_srai_w = 85, -+ la_op_srai_d = 86, -+ la_op_rotri_w = 87, -+ la_op_rotri_d = 88, -+ la_op_bstrins_w = 89, -+ la_op_bstrpick_w = 90, -+ la_op_bstrins_d = 91, -+ la_op_bstrpick_d = 92, -+ la_op_fadd_s = 93, -+ la_op_fadd_d = 94, -+ la_op_fsub_s = 95, -+ la_op_fsub_d = 96, -+ la_op_fmul_s = 97, -+ la_op_fmul_d = 98, -+ la_op_fdiv_s = 99, -+ la_op_fdiv_d = 100, -+ la_op_fmax_s = 101, -+ la_op_fmax_d = 102, -+ la_op_fmin_s = 103, -+ la_op_fmin_d = 104, -+ la_op_fmaxa_s = 105, -+ la_op_fmaxa_d = 106, -+ la_op_fmina_s = 107, -+ la_op_fmina_d = 108, -+ la_op_fscaleb_s = 109, -+ la_op_fscaleb_d = 110, -+ la_op_fcopysign_s = 111, -+ la_op_fcopysign_d = 112, -+ la_op_fabs_s = 113, -+ la_op_fabs_d = 114, -+ la_op_fneg_s = 115, -+ la_op_fneg_d = 116, -+ la_op_flogb_s = 117, -+ la_op_flogb_d = 118, -+ la_op_fclass_s = 119, -+ la_op_fclass_d = 120, -+ la_op_fsqrt_s = 121, -+ la_op_fsqrt_d = 122, -+ la_op_frecip_s = 123, -+ la_op_frecip_d = 124, -+ la_op_frsqrt_s = 125, -+ la_op_frsqrt_d = 126, -+ la_op_fmov_s = 127, -+ la_op_fmov_d = 128, -+ la_op_movgr2fr_w = 129, -+ la_op_movgr2fr_d = 130, -+ la_op_movgr2frh_w = 131, -+ la_op_movfr2gr_s = 132, -+ la_op_movfr2gr_d = 133, -+ la_op_movfrh2gr_s = 134, -+ la_op_movgr2fcsr = 135, -+ la_op_movfcsr2gr = 136, -+ la_op_movfr2cf = 137, -+ la_op_movcf2fr = 138, -+ la_op_movgr2cf = 139, -+ la_op_movcf2gr = 140, -+ la_op_fcvt_s_d = 141, -+ la_op_fcvt_d_s = 142, -+ -+ la_op_ftintrm_w_s = 143, -+ la_op_ftintrm_w_d = 144, -+ la_op_ftintrm_l_s = 145, -+ la_op_ftintrm_l_d = 146, -+ la_op_ftintrp_w_s = 147, -+ la_op_ftintrp_w_d = 148, -+ la_op_ftintrp_l_s = 149, -+ la_op_ftintrp_l_d = 150, -+ la_op_ftintrz_w_s = 151, -+ la_op_ftintrz_w_d = 152, -+ la_op_ftintrz_l_s = 153, -+ la_op_ftintrz_l_d = 154, -+ la_op_ftintrne_w_s = 155, -+ la_op_ftintrne_w_d = 156, -+ la_op_ftintrne_l_s = 157, -+ la_op_ftintrne_l_d = 158, -+ la_op_ftint_w_s = 159, -+ la_op_ftint_w_d = 160, -+ la_op_ftint_l_s = 161, -+ la_op_ftint_l_d = 162, -+ la_op_ffint_s_w = 163, -+ la_op_ffint_s_l = 164, -+ la_op_ffint_d_w = 165, -+ la_op_ffint_d_l = 166, -+ la_op_frint_s = 167, -+ la_op_frint_d = 168, -+ -+ la_op_slti = 169, -+ la_op_sltui = 170, -+ la_op_addi_w = 171, -+ la_op_addi_d = 172, -+ la_op_lu52i_d = 173, -+ la_op_addi = 174, -+ la_op_ori = 175, -+ la_op_xori = 176, -+ -+ la_op_csrxchg = 177, -+ la_op_cacop = 178, -+ la_op_lddir = 179, -+ la_op_ldpte = 180, -+ la_op_iocsrrd_b = 181, -+ la_op_iocsrrd_h = 182, -+ la_op_iocsrrd_w = 183, -+ la_op_iocsrrd_d = 184, -+ la_op_iocsrwr_b = 185, -+ la_op_iocsrwr_h = 186, -+ la_op_iocsrwr_w = 187, -+ la_op_iocsrwr_d = 188, -+ la_op_tlbclr = 189, -+ la_op_tlbflush = 190, -+ la_op_tlbsrch = 191, -+ la_op_tlbrd = 192, -+ la_op_tlbwr = 193, -+ la_op_tlbfill = 194, -+ la_op_ertn = 195, -+ la_op_idle = 196, -+ la_op_invtlb = 197, -+ -+ la_op_fmadd_s = 198, -+ la_op_fmadd_d = 199, -+ la_op_fmsub_s = 200, -+ la_op_fmsub_d = 201, -+ la_op_fnmadd_s = 202, -+ la_op_fnmadd_d = 203, -+ la_op_fnmsub_s = 204, -+ la_op_fnmsub_d = 205, -+ la_op_fcmp_cond_s = 206, -+ la_op_fcmp_cond_d = 207, -+ la_op_fsel = 208, -+ la_op_addu16i_d = 209, -+ la_op_lu12i_w = 210, -+ la_op_lu32i_d = 211, -+ la_op_pcaddi = 212, -+ la_op_pcalau12i = 213, -+ la_op_pcaddu12i = 214, -+ la_op_pcaddu18i = 215, -+ -+ la_op_ll_w = 216, -+ la_op_sc_w = 217, -+ la_op_ll_d = 218, -+ la_op_sc_d = 219, -+ la_op_ldptr_w = 220, -+ la_op_stptr_w = 221, -+ la_op_ldptr_d = 222, -+ la_op_stptr_d = 223, -+ la_op_ld_b = 224, -+ la_op_ld_h = 225, -+ la_op_ld_w = 226, -+ la_op_ld_d = 227, -+ la_op_st_b = 228, -+ la_op_st_h = 229, -+ la_op_st_w = 230, -+ la_op_st_d = 231, -+ la_op_ld_bu = 232, -+ la_op_ld_hu = 233, -+ la_op_ld_wu = 234, -+ la_op_preld = 235, -+ la_op_fld_s = 236, -+ la_op_fst_s = 237, -+ la_op_fld_d = 238, -+ la_op_fst_d = 239, -+ la_op_ldl_w = 240, -+ la_op_ldr_w = 241, -+ la_op_ldl_d = 242, -+ la_op_ldr_d = 243, -+ la_op_stl_d = 244, -+ la_op_str_d = 245, -+ la_op_ldx_b = 246, -+ la_op_ldx_h = 247, -+ la_op_ldx_w = 248, -+ la_op_ldx_d = 249, -+ la_op_stx_b = 250, -+ la_op_stx_h = 251, -+ la_op_stx_w = 252, -+ la_op_stx_d = 253, -+ la_op_ldx_bu = 254, -+ la_op_ldx_hu = 255, -+ la_op_ldx_wu = 256, -+ la_op_fldx_s = 257, -+ la_op_fldx_d = 258, -+ la_op_fstx_s = 259, -+ la_op_fstx_d = 260, -+ -+ la_op_amswap_w = 261, -+ la_op_amswap_d = 262, -+ la_op_amadd_w = 263, -+ la_op_amadd_d = 264, -+ la_op_amand_w = 265, -+ la_op_amand_d = 266, -+ la_op_amor_w = 267, -+ la_op_amor_d = 268, -+ la_op_amxor_w = 269, -+ la_op_amxor_d = 270, -+ la_op_ammax_w = 271, -+ la_op_ammax_d = 272, -+ la_op_ammin_w = 273, -+ la_op_ammin_d = 274, -+ la_op_ammax_wu = 275, -+ la_op_ammax_du = 276, -+ la_op_ammin_wu = 277, -+ la_op_ammin_du = 278, -+ la_op_amswap_db_w = 279, -+ la_op_amswap_db_d = 280, -+ la_op_amadd_db_w = 281, -+ la_op_amadd_db_d = 282, -+ la_op_amand_db_w = 283, -+ la_op_amand_db_d = 284, -+ la_op_amor_db_w = 285, -+ la_op_amor_db_d = 286, -+ la_op_amxor_db_w = 287, -+ la_op_amxor_db_d = 288, -+ la_op_ammax_db_w = 289, -+ la_op_ammax_db_d = 290, -+ la_op_ammin_db_w = 291, -+ la_op_ammin_db_d = 292, -+ la_op_ammax_db_wu = 293, -+ la_op_ammax_db_du = 294, -+ la_op_ammin_db_wu = 295, -+ la_op_ammin_db_du = 296, -+ la_op_dbar = 297, -+ la_op_ibar = 298, -+ la_op_fldgt_s = 299, -+ la_op_fldgt_d = 300, -+ la_op_fldle_s = 301, -+ la_op_fldle_d = 302, -+ la_op_fstgt_s = 303, -+ la_op_fstgt_d = 304, -+ ls_op_fstle_s = 305, -+ la_op_fstle_d = 306, -+ la_op_ldgt_b = 307, -+ la_op_ldgt_h = 308, -+ la_op_ldgt_w = 309, -+ la_op_ldgt_d = 310, -+ la_op_ldle_b = 311, -+ la_op_ldle_h = 312, -+ la_op_ldle_w = 313, -+ la_op_ldle_d = 314, -+ la_op_stgt_b = 315, -+ la_op_stgt_h = 316, -+ la_op_stgt_w = 317, -+ la_op_stgt_d = 318, -+ la_op_stle_b = 319, -+ la_op_stle_h = 320, -+ la_op_stle_w = 321, -+ la_op_stle_d = 322, -+ la_op_beqz = 323, -+ la_op_bnez = 324, -+ la_op_bceqz = 325, -+ la_op_bcnez = 326, -+ la_op_jirl = 327, -+ la_op_b = 328, -+ la_op_bl = 329, -+ la_op_beq = 330, -+ la_op_bne = 331, -+ la_op_blt = 332, -+ la_op_bge = 333, -+ la_op_bltu = 334, -+ la_op_bgeu = 335, -+ -+ /* vz insn */ -+ la_op_hvcl = 336, -+ -+} la_op; -+ -+typedef enum { -+ la_codec_illegal, -+ la_codec_empty, -+ la_codec_2r, -+ la_codec_2r_u5, -+ la_codec_2r_u6, -+ la_codec_2r_2bw, -+ la_codec_2r_2bd, -+ la_codec_3r, -+ la_codec_3r_rd0, -+ la_codec_3r_sa2, -+ la_codec_3r_sa3, -+ la_codec_4r, -+ la_codec_r_im20, -+ la_codec_2r_im16, -+ la_codec_2r_im14, -+ la_codec_2r_im12, -+ la_codec_im5_r_im12, -+ la_codec_2r_im8, -+ la_codec_r_sd, -+ la_codec_r_sj, -+ la_codec_r_cd, -+ la_codec_r_cj, -+ la_codec_r_seq, -+ la_codec_code, -+ la_codec_whint, -+ la_codec_invtlb, -+ la_codec_r_ofs21, -+ la_codec_cj_ofs21, -+ la_codec_ofs26, -+ la_codec_cond, -+ la_codec_sel, -+ -+} la_codec; -+ -+#define la_fmt_illegal "nte" -+#define la_fmt_empty "nt" -+#define la_fmt_sd_rj "ntA,1" -+#define la_fmt_rd_sj "nt0,B" -+#define la_fmt_rd_rj "nt0,1" -+#define la_fmt_rj_rk "nt1,2" -+#define la_fmt_rj_seq "nt1,x" -+#define la_fmt_rd_si20 "nt0,i(x)" -+#define la_fmt_rd_rj_ui5 "nt0,1,C" -+#define la_fmt_rd_rj_ui6 "nt0,1.C" -+#define la_fmt_rd_rj_level "nt0,1,x" -+#define la_fmt_rd_rj_msbw_lsbw "nt0,1,C,D" -+#define la_fmt_rd_rj_msbd_lsbd "nt0,1,C,D" -+#define la_fmt_rd_rj_si12 "nt0,1,i(x)" -+#define la_fmt_hint_rj_si12 "ntE,1,i(x)" -+#define la_fmt_rd_rj_csr "nt0,1,x" -+#define la_fmt_rd_rj_si14 "nt0,1,i(x)" -+#define la_fmt_rd_rj_si16 "nt0,1,i(x)" -+#define la_fmt_rd_rj_rk "nt0,1,2" -+#define la_fmt_fd_rj_rk "nt3,1,2" -+#define la_fmt_rd_rj_rk_sa2 "nt0,1,2,D" -+#define la_fmt_rd_rj_rk_sa3 "nt0,1,2,D" -+#define la_fmt_fd_rj "nt3,1" -+#define la_fmt_rd_fj "nt0,4" -+#define la_fmt_fd_fj "nt3,4" -+#define la_fmt_fd_fj_si12 "nt3,4,i(x)" -+#define la_fmt_fcsrd_rj "ntF,1" -+#define la_fmt_rd_fcsrs "nt0,G" -+#define la_fmt_cd_fj "ntH,4" -+#define la_fmt_fd_cj "nt3,I" -+#define la_fmt_fd_fj_fk "nt3,4,5" -+#define la_fmt_code "ntJ" -+#define la_fmt_whint "ntx" -+#define la_fmt_invtlb "ntx,1,2" /* op,rj,rk */ -+#define la_fmt_offs26 "nto(X)p" -+#define la_fmt_rj_offs21 "nt1,o(X)p" -+#define la_fmt_cj_offs21 "ntQ,o(X)p" -+#define la_fmt_rd_rj_offs16 "nt0,1,o(X)" -+#define la_fmt_rj_rd_offs16 "nt1,0,o(X)p" -+#define la_fmt_s_cd_fj_fk "K.stH,4,5" -+#define la_fmt_d_cd_fj_fk "K.dtH,4,5" -+#define la_fmt_fd_fj_fk_fa "nt3,4,5,6" -+#define la_fmt_fd_fj_fk_ca "nt3,4,5,L" -+#define la_fmt_cop_rj_si12 "ntM,1,i(x)" -+ -+/* structures */ -+ -+typedef struct { -+ uint32_t pc; -+ uint32_t insn; -+ int32_t imm; -+ int32_t imm2; -+ uint16_t op; -+ uint16_t code; -+ uint8_t codec; -+ uint8_t r1; -+ uint8_t r2; -+ uint8_t r3; -+ uint8_t r4; -+ uint8_t bit; -+} la_decode; -+ -+typedef struct { -+ const char * const name; -+ const la_codec codec; -+ const char * const format; -+} la_opcode_data; -+ -+/* reg names */ -+ -+const char * const loongarch_r_normal_name[32] = { -+ "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", -+ "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", -+ "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23", -+ "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31", -+}; -+ -+const char * const loongarch_f_normal_name[32] = { -+ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", -+ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", -+ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", -+ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", -+}; -+ -+const char * const loongarch_cr_normal_name[4] = { -+ "$scr0", "$scr1", "$scr2", "$scr3", -+}; -+ -+const char * const loongarch_c_normal_name[8] = { -+ "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", -+}; -+ -+/* instruction data */ -+ -+const la_opcode_data opcode_data[] = { -+ { "illegal", la_codec_illegal, la_fmt_illegal }, -+ { "gr2scr", la_codec_r_sd, la_fmt_sd_rj }, -+ { "scr2gr", la_codec_r_sj, la_fmt_rd_sj }, -+ { "clo.w", la_codec_2r, la_fmt_rd_rj }, -+ { "clz.w", la_codec_2r, la_fmt_rd_rj }, -+ { "cto.w", la_codec_2r, la_fmt_rd_rj }, -+ { "ctz.w", la_codec_2r, la_fmt_rd_rj }, -+ { "clo.d", la_codec_2r, la_fmt_rd_rj }, -+ { "clz.d", la_codec_2r, la_fmt_rd_rj }, -+ { "cto.d", la_codec_2r, la_fmt_rd_rj }, -+ { "ctz_d", la_codec_2r, la_fmt_rd_rj }, -+ { "revb.2h", la_codec_2r, la_fmt_rd_rj }, -+ { "revb.4h", la_codec_2r, la_fmt_rd_rj }, -+ { "revb.2w", la_codec_2r, la_fmt_rd_rj }, -+ { "revb.d", la_codec_2r, la_fmt_rd_rj }, -+ { "revh.2w", la_codec_2r, la_fmt_rd_rj }, -+ { "revh.d", la_codec_2r, la_fmt_rd_rj }, -+ { "bitrev.4b", la_codec_2r, la_fmt_rd_rj }, -+ { "bitrev.8b", la_codec_2r, la_fmt_rd_rj }, -+ { "bitrev.w", la_codec_2r, la_fmt_rd_rj }, -+ { "bitrev.d", la_codec_2r, la_fmt_rd_rj }, -+ { "ext.w.h", la_codec_2r, la_fmt_rd_rj }, -+ { "ext.w.b", la_codec_2r, la_fmt_rd_rj }, -+ { "rdtime.d", la_codec_2r, la_fmt_rd_rj }, -+ { "cpucfg", la_codec_2r, la_fmt_rd_rj }, -+ { "asrtle.d", la_codec_3r_rd0, la_fmt_rj_rk }, -+ { "asrtgt.d", la_codec_3r_rd0, la_fmt_rj_rk }, -+ { "alsl.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, -+ { "alsl.wu", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, -+ { "bytepick.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, -+ { "bytepick.d", la_codec_3r_sa3, la_fmt_rd_rj_rk_sa3 }, -+ { "add.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "add.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sub.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sub.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "slt", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sltu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "maskeqz", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "masknez", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "nor", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "and", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "or", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "xor", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "orn", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "andn", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sll.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "srl.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sra.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sll.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "srl.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "sra.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "rotr.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "rotr.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mul.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulh.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulh.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mul.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulh.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulh.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulw.d.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mulw.d.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "div.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mod.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "div.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mod.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "div.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mod.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "div.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "mod.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crcc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crcc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crcc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "crcc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "break", la_codec_code, la_fmt_code }, -+ { "dbcl", la_codec_code, la_fmt_code }, -+ { "syscall", la_codec_code, la_fmt_code }, -+ { "alsl.d", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, -+ { "slli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, -+ { "slli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, -+ { "srli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, -+ { "srli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, -+ { "srai.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, -+ { "srai.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, -+ { "rotri.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, -+ { "rotri.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, -+ { "bstrins.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw }, -+ { "bstrpick.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw }, -+ { "bstrins.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd }, -+ { "bstrpick.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd }, -+ { "fadd.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fadd.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fsub.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fsub.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmul.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmul.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fdiv.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fdiv.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmax.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmax.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmin.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmin.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmaxa.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmaxa.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmina.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fmina.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fscaleb.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fscaleb.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fcopysign.s", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fcopysign.d", la_codec_3r, la_fmt_fd_fj_fk }, -+ { "fabs.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fabs.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fneg.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fneg.d", la_codec_2r, la_fmt_fd_fj }, -+ { "flogb.s", la_codec_2r, la_fmt_fd_fj }, -+ { "flogb.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fclass.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fclass.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fsqrt.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fsqrt.d", la_codec_2r, la_fmt_fd_fj }, -+ { "frecip.s", la_codec_2r, la_fmt_fd_fj }, -+ { "frecip.d", la_codec_2r, la_fmt_fd_fj }, -+ { "frsqrt.s", la_codec_2r, la_fmt_fd_fj }, -+ { "frsqrt.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fmov.s", la_codec_2r, la_fmt_fd_fj }, -+ { "fmov.d", la_codec_2r, la_fmt_fd_fj }, -+ { "movgr2fr.w", la_codec_2r, la_fmt_fd_rj }, -+ { "movgr2fr.d", la_codec_2r, la_fmt_fd_rj }, -+ { "movgr2frh.w", la_codec_2r, la_fmt_fd_rj }, -+ { "movfr2gr.s", la_codec_2r, la_fmt_rd_fj }, -+ { "movfr2gr.d", la_codec_2r, la_fmt_rd_fj }, -+ { "movfrh2gr.s", la_codec_2r, la_fmt_rd_fj }, -+ { "movgr2fcsr", la_codec_2r, la_fmt_fcsrd_rj }, -+ { "movfcsr2gr", la_codec_2r, la_fmt_rd_fcsrs }, -+ { "movfr2cf", la_codec_r_cd, la_fmt_cd_fj }, -+ { "movcf2fr", la_codec_r_cj, la_fmt_fd_cj }, -+ { "movgr2cf", la_codec_r_cd, la_fmt_cd_fj }, -+ { "movcf2gr", la_codec_r_cj, la_fmt_fd_cj }, -+ { "fcvt.s.d", la_codec_2r, la_fmt_fd_fj }, -+ { "fcvt.d.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrm.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrm.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrm.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrm.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrp.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrp.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrp.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrp.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrz.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrz.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrz.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrz.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrne.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrne.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrne.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftintrne.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftint.w.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftint.w.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ftint.l.s", la_codec_2r, la_fmt_fd_fj }, -+ { "ftint.l.d", la_codec_2r, la_fmt_fd_fj }, -+ { "ffint.s.w", la_codec_2r, la_fmt_fd_fj }, -+ { "ffint.s.l", la_codec_2r, la_fmt_fd_fj }, -+ { "ffint.d.w", la_codec_2r, la_fmt_fd_fj }, -+ { "ffint.d.l", la_codec_2r, la_fmt_fd_fj }, -+ { "frint.s", la_codec_2r, la_fmt_fd_fj }, -+ { "frint.d", la_codec_2r, la_fmt_fd_fj }, -+ { "slti", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "sltui", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "addi.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "addi.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "lu52i.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "addi", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ori", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "xori", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "csrxchg", la_codec_2r_im14, la_fmt_rd_rj_csr }, -+ { "cacop", la_codec_im5_r_im12, la_fmt_cop_rj_si12 }, -+ { "lddir", la_codec_2r_im8, la_fmt_rd_rj_level }, -+ { "ldpte", la_codec_r_seq, la_fmt_rj_seq }, -+ { "iocsrrd.b", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrrd.h", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrrd.w", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrrd.d", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrwr.b", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrwr.h", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrwr.w", la_codec_2r, la_fmt_rd_rj }, -+ { "iocsrwr.d", la_codec_2r, la_fmt_rd_rj }, -+ { "tlbclr", la_codec_empty, la_fmt_empty }, -+ { "tlbflush", la_codec_empty, la_fmt_empty }, -+ { "tlbsrch", la_codec_empty, la_fmt_empty }, -+ { "tlbrd", la_codec_empty, la_fmt_empty }, -+ { "tlbwr", la_codec_empty, la_fmt_empty }, -+ { "tlbfill", la_codec_empty, la_fmt_empty }, -+ { "ertn", la_codec_empty, la_fmt_empty }, -+ { "idle", la_codec_whint, la_fmt_whint }, -+ { "invtlb", la_codec_invtlb, la_fmt_invtlb }, -+ { "fmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fnmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fnmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fnmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fnmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, -+ { "fcmp.cond.s", la_codec_cond, la_fmt_s_cd_fj_fk }, -+ { "fcmp.cond.d", la_codec_cond, la_fmt_d_cd_fj_fk }, -+ { "fsel", la_codec_sel, la_fmt_fd_fj_fk_ca }, -+ { "addu16i.d", la_codec_2r_im16, la_fmt_rd_rj_si16 }, -+ { "lu12i.w", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "lu32i.d", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "pcaddi", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "pcalau12i", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "pcaddu12i", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "pcaddu18i", la_codec_r_im20, la_fmt_rd_si20 }, -+ { "ll.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "sc.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "ll.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "sc.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "ldptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "stptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "ldptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "stptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, -+ { "ld.b", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.h", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "st.b", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "st.h", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "st.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "st.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.bu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.hu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ld.wu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "preld", la_codec_2r_im12, la_fmt_hint_rj_si12 }, -+ { "fld.s", la_codec_2r_im12, la_fmt_fd_fj_si12 }, -+ { "fst.s", la_codec_2r_im12, la_fmt_fd_fj_si12 }, -+ { "fld.d", la_codec_2r_im12, la_fmt_fd_fj_si12 }, -+ { "fst.d", la_codec_2r_im12, la_fmt_fd_fj_si12 }, -+ { "ldl.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ldr.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ldl.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ldr.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "stl.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "str.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, -+ { "ldx.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stx.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stx.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stx.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stx.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.bu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.hu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldx.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "fldx.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fldx.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstx.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstx.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "amswap.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amswap.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amadd.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amadd.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amand.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amand.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amor.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amor.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amxor.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amxor.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amswap.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amswap.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amadd.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amadd.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amand.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amand.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amor.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amor.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amxor.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "amxor.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.db.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.db.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.db.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammax.db.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.db.wu", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ammin.db.du", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "dbar", la_codec_whint, la_fmt_whint }, -+ { "ibar", la_codec_whint, la_fmt_whint }, -+ { "fldgt.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fldgt.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fldle.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fldle.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstgt.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstgt.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstle.s", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "fstle.d", la_codec_3r, la_fmt_fd_rj_rk }, -+ { "ldgt.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldgt.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldgt.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldgt.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldle.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldle.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldle.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "ldle.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stgt.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stgt.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stgt.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stgt.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stle.b", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stle.h", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stle.w", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "stle.d", la_codec_3r, la_fmt_rd_rj_rk }, -+ { "beqz", la_codec_r_ofs21, la_fmt_rj_offs21 }, -+ { "bnez", la_codec_r_ofs21, la_fmt_rj_offs21 }, -+ { "bceqz", la_codec_cj_ofs21, la_fmt_cj_offs21 }, -+ { "bcnez", la_codec_cj_ofs21, la_fmt_cj_offs21 }, -+ { "jirl", la_codec_2r_im16, la_fmt_rd_rj_offs16 }, -+ { "b", la_codec_ofs26, la_fmt_offs26 }, -+ { "bl", la_codec_ofs26, la_fmt_offs26 }, -+ { "beq", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "bne", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "blt", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "bge", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "bltu", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ { "bgeu", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, -+ -+ /* vz insn */ -+ { "hvcl", la_codec_code, la_fmt_code }, -+ -+}; -+ -+ -+/* decode opcode */ -+ -+static void decode_insn_opcode(la_decode *dec) -+{ -+ uint32_t insn = dec->insn; -+ uint16_t op = la_op_illegal; -+ switch ((insn >> 26) & 0x3f) { -+ case 0x0: -+ switch ((insn >> 22) & 0xf) { -+ case 0x0: -+ switch ((insn >> 18) & 0xf) { -+ case 0x0: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x2: -+ switch ((insn >> 2) & 0x7) { -+ case 0x0: -+ op = la_op_gr2scr; -+ break; -+ } -+ break; -+ case 0x3: -+ switch ((insn >> 7) & 0x7) { -+ case 0x0: -+ op = la_op_scr2gr; -+ break; -+ } -+ break; -+ case 0x4: -+ op = la_op_clo_w; -+ break; -+ case 0x5: -+ op = la_op_clz_w; -+ break; -+ case 0x6: -+ op = la_op_cto_w; -+ break; -+ case 0x7: -+ op = la_op_ctz_w; -+ break; -+ case 0x8: -+ op = la_op_clo_d; -+ break; -+ case 0x9: -+ op = la_op_clz_d; -+ break; -+ case 0xa: -+ op = la_op_cto_d; -+ break; -+ case 0xb: -+ op = la_op_ctz_d; -+ break; -+ case 0xc: -+ op = la_op_revb_2h; -+ break; -+ case 0xd: -+ op = la_op_revb_4h; -+ break; -+ case 0xe: -+ op = la_op_revb_2w; -+ break; -+ case 0xf: -+ op = la_op_revb_d; -+ break; -+ case 0x10: -+ op = la_op_revh_2w; -+ break; -+ case 0x11: -+ op = la_op_revh_d; -+ break; -+ case 0x12: -+ op = la_op_bitrev_4b; -+ break; -+ case 0x13: -+ op = la_op_bitrev_8b; -+ break; -+ case 0x14: -+ op = la_op_bitrev_w; -+ break; -+ case 0x15: -+ op = la_op_bitrev_d; -+ break; -+ case 0x16: -+ op = la_op_ext_w_h; -+ break; -+ case 0x17: -+ op = la_op_ext_w_b; -+ break; -+ case 0x1a: -+ op = la_op_rdtime_d; -+ break; -+ case 0x1b: -+ op = la_op_cpucfg; -+ break; -+ } -+ break; -+ case 0x2: -+ switch (insn & 0x0000001f) { -+ case 0x00000000: -+ op = la_op_asrtle_d; -+ break; -+ } -+ break; -+ case 0x3: -+ switch (insn & 0x0000001f) { -+ case 0x00000000: -+ op = la_op_asrtgt_d; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x1: -+ switch ((insn >> 17) & 0x1) { -+ case 0x0: -+ op = la_op_alsl_w; -+ break; -+ case 0x1: -+ op = la_op_alsl_wu; -+ break; -+ } -+ break; -+ case 0x2: -+ switch ((insn >> 17) & 0x1) { -+ case 0x0: -+ op = la_op_bytepick_w; -+ break; -+ } -+ break; -+ case 0x3: -+ op = la_op_bytepick_d; -+ break; -+ case 0x4: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_add_w; -+ break; -+ case 0x1: -+ op = la_op_add_d; -+ break; -+ case 0x2: -+ op = la_op_sub_w; -+ break; -+ case 0x3: -+ op = la_op_sub_d; -+ break; -+ case 0x4: -+ op = la_op_slt; -+ break; -+ case 0x5: -+ op = la_op_sltu; -+ break; -+ case 0x6: -+ op = la_op_maskeqz; -+ break; -+ case 0x7: -+ op = la_op_masknez; -+ break; -+ } -+ break; -+ case 0x5: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_nor; -+ break; -+ case 0x1: -+ op = la_op_and; -+ break; -+ case 0x2: -+ op = la_op_or; -+ break; -+ case 0x3: -+ op = la_op_xor; -+ break; -+ case 0x4: -+ op = la_op_orn; -+ break; -+ case 0x5: -+ op = la_op_andn; -+ break; -+ case 0x6: -+ op = la_op_sll_w; -+ break; -+ case 0x7: -+ op = la_op_srl_w; -+ break; -+ } -+ break; -+ case 0x6: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_sra_w; -+ break; -+ case 0x1: -+ op = la_op_sll_d; -+ break; -+ case 0x2: -+ op = la_op_srl_d; -+ break; -+ case 0x3: -+ op = la_op_sra_d; -+ break; -+ case 0x6: -+ op = la_op_rotr_w; -+ break; -+ case 0x7: -+ op = la_op_rotr_d; -+ break; -+ } -+ break; -+ case 0x7: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_mul_w; -+ break; -+ case 0x1: -+ op = la_op_mulh_w; -+ break; -+ case 0x2: -+ op = la_op_mulh_wu; -+ break; -+ case 0x3: -+ op = la_op_mul_d; -+ break; -+ case 0x4: -+ op = la_op_mulh_d; -+ break; -+ case 0x5: -+ op = la_op_mulh_du; -+ break; -+ case 0x6: -+ op = la_op_mulw_d_w; -+ break; -+ case 0x7: -+ op = la_op_mulw_d_wu; -+ break; -+ } -+ break; -+ case 0x8: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_div_w; -+ break; -+ case 0x1: -+ op = la_op_mod_w; -+ break; -+ case 0x2: -+ op = la_op_div_wu; -+ break; -+ case 0x3: -+ op = la_op_mod_wu; -+ break; -+ case 0x4: -+ op = la_op_div_d; -+ break; -+ case 0x5: -+ op = la_op_mod_d; -+ break; -+ case 0x6: -+ op = la_op_div_du; -+ break; -+ case 0x7: -+ op = la_op_mod_du; -+ break; -+ } -+ break; -+ case 0x9: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ op = la_op_crc_w_b_w; -+ break; -+ case 0x1: -+ op = la_op_crc_w_h_w; -+ break; -+ case 0x2: -+ op = la_op_crc_w_w_w; -+ break; -+ case 0x3: -+ op = la_op_crc_w_d_w; -+ break; -+ case 0x4: -+ op = la_op_crcc_w_b_w; -+ break; -+ case 0x5: -+ op = la_op_crcc_w_h_w; -+ break; -+ case 0x6: -+ op = la_op_crcc_w_w_w; -+ break; -+ case 0x7: -+ op = la_op_crcc_w_d_w; -+ break; -+ } -+ break; -+ case 0xa: -+ switch ((insn >> 15) & 0x7) { -+ case 0x4: -+ op = la_op_break; -+ break; -+ case 0x5: -+ op = la_op_dbcl; -+ break; -+ case 0x6: -+ op = la_op_syscall; -+ break; -+ case 0x7: -+ op = la_op_hvcl; -+ break; -+ } -+ break; -+ case 0xb: -+ switch ((insn >> 17) & 0x1) { -+ case 0x0: -+ op = la_op_alsl_d; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x1: -+ switch ((insn >> 21) & 0x1) { -+ case 0x0: -+ switch ((insn >> 16) & 0x1f) { -+ case 0x0: -+ switch ((insn >> 15) & 0x1) { -+ case 0x1: -+ op = la_op_slli_w; -+ break; -+ } -+ break; -+ case 0x1: -+ op = la_op_slli_d; -+ break; -+ case 0x4: -+ switch ((insn >> 15) & 0x1) { -+ case 0x1: -+ op = la_op_srli_w; -+ break; -+ } -+ break; -+ case 0x5: -+ op = la_op_srli_d; -+ break; -+ case 0x8: -+ switch ((insn >> 15) & 0x1) { -+ case 0x1: -+ op = la_op_srai_w; -+ break; -+ } -+ break; -+ case 0x9: -+ op = la_op_srai_d; -+ break; -+ case 0xc: -+ switch ((insn >> 15) & 0x1) { -+ case 0x1: -+ op = la_op_rotri_w; -+ break; -+ } -+ break; -+ case 0xd: -+ op = la_op_rotri_d; -+ break; -+ } -+ break; -+ case 0x1: -+ switch ((insn >> 15) & 0x1) { -+ case 0x0: -+ op = la_op_bstrins_w; -+ break; -+ case 0x1: -+ op = la_op_bstrpick_w; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x2: -+ op = la_op_bstrins_d; -+ break; -+ case 0x3: -+ op = la_op_bstrpick_d; -+ break; -+ case 0x4: -+ switch ((insn >> 15) & 0x7f) { -+ case 0x1: -+ op = la_op_fadd_s; -+ break; -+ case 0x2: -+ op = la_op_fadd_d; -+ break; -+ case 0x5: -+ op = la_op_fsub_s; -+ break; -+ case 0x6: -+ op = la_op_fsub_d; -+ break; -+ case 0x9: -+ op = la_op_fmul_s; -+ break; -+ case 0xa: -+ op = la_op_fmul_d; -+ break; -+ case 0xd: -+ op = la_op_fdiv_s; -+ break; -+ case 0xe: -+ op = la_op_fdiv_d; -+ break; -+ case 0x11: -+ op = la_op_fmax_s; -+ break; -+ case 0x12: -+ op = la_op_fmax_d; -+ break; -+ case 0x15: -+ op = la_op_fmin_s; -+ break; -+ case 0x16: -+ op = la_op_fmin_d; -+ break; -+ case 0x19: -+ op = la_op_fmaxa_s; -+ break; -+ case 0x1a: -+ op = la_op_fmaxa_d; -+ break; -+ case 0x1d: -+ op = la_op_fmina_s; -+ break; -+ case 0x1e: -+ op = la_op_fmina_d; -+ break; -+ case 0x21: -+ op = la_op_fscaleb_s; -+ break; -+ case 0x22: -+ op = la_op_fscaleb_d; -+ break; -+ case 0x25: -+ op = la_op_fcopysign_s; -+ break; -+ case 0x26: -+ op = la_op_fcopysign_d; -+ break; -+ case 0x28: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x1: -+ op = la_op_fabs_s; -+ break; -+ case 0x2: -+ op = la_op_fabs_d; -+ break; -+ case 0x5: -+ op = la_op_fneg_s; -+ break; -+ case 0x6: -+ op = la_op_fneg_d; -+ break; -+ case 0x9: -+ op = la_op_flogb_s; -+ break; -+ case 0xa: -+ op = la_op_flogb_d; -+ break; -+ case 0xd: -+ op = la_op_fclass_s; -+ break; -+ case 0xe: -+ op = la_op_fclass_d; -+ break; -+ case 0x11: -+ op = la_op_fsqrt_s; -+ break; -+ case 0x12: -+ op = la_op_fsqrt_d; -+ break; -+ case 0x15: -+ op = la_op_frecip_s; -+ break; -+ case 0x16: -+ op = la_op_frecip_d; -+ break; -+ case 0x19: -+ op = la_op_frsqrt_s; -+ break; -+ case 0x1a: -+ op = la_op_frsqrt_d; -+ break; -+ } -+ break; -+ case 0x29: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x5: -+ op = la_op_fmov_s; -+ break; -+ case 0x6: -+ op = la_op_fmov_d; -+ break; -+ case 0x9: -+ op = la_op_movgr2fr_w; -+ break; -+ case 0xa: -+ op = la_op_movgr2fr_d; -+ break; -+ case 0xb: -+ op = la_op_movgr2frh_w; -+ break; -+ case 0xd: -+ op = la_op_movfr2gr_s; -+ break; -+ case 0xe: -+ op = la_op_movfr2gr_d; -+ break; -+ case 0xf: -+ op = la_op_movfrh2gr_s; -+ break; -+ case 0x10: -+ op = la_op_movgr2fcsr; -+ break; -+ case 0x12: -+ op = la_op_movfcsr2gr; -+ break; -+ case 0x14: -+ switch ((insn >> 3) & 0x3) { -+ case 0x0: -+ op = la_op_movfr2cf; -+ break; -+ } -+ break; -+ case 0x15: -+ switch ((insn >> 8) & 0x3) { -+ case 0x0: -+ op = la_op_movcf2fr; -+ break; -+ } -+ break; -+ case 0x16: -+ switch ((insn >> 3) & 0x3) { -+ case 0x0: -+ op = la_op_movgr2cf; -+ break; -+ } -+ break; -+ case 0x17: -+ switch ((insn >> 8) & 0x3) { -+ case 0x0: -+ op = la_op_movcf2gr; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x32: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x6: -+ op = la_op_fcvt_s_d; -+ break; -+ case 0x9: -+ op = la_op_fcvt_d_s; -+ break; -+ } -+ break; -+ case 0x34: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x1: -+ op = la_op_ftintrm_w_s; -+ break; -+ case 0x2: -+ op = la_op_ftintrm_w_d; -+ break; -+ case 0x9: -+ op = la_op_ftintrm_l_s; -+ break; -+ case 0xa: -+ op = la_op_ftintrm_l_d; -+ break; -+ case 0x11: -+ op = la_op_ftintrp_w_s; -+ break; -+ case 0x12: -+ op = la_op_ftintrp_w_d; -+ break; -+ case 0x19: -+ op = la_op_ftintrp_l_s; -+ break; -+ case 0x1a: -+ op = la_op_ftintrp_l_d; -+ break; -+ } -+ break; -+ case 0x35: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x1: -+ op = la_op_ftintrz_w_s; -+ break; -+ case 0x2: -+ op = la_op_ftintrz_w_d; -+ break; -+ case 0x9: -+ op = la_op_ftintrz_l_s; -+ break; -+ case 0xa: -+ op = la_op_ftintrz_l_d; -+ break; -+ case 0x11: -+ op = la_op_ftintrne_w_s; -+ break; -+ case 0x12: -+ op = la_op_ftintrne_w_d; -+ break; -+ case 0x19: -+ op = la_op_ftintrne_l_s; -+ break; -+ case 0x1a: -+ op = la_op_ftintrne_l_d; -+ break; -+ } -+ break; -+ case 0x36: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x1: -+ op = la_op_ftint_w_s; -+ break; -+ case 0x2: -+ op = la_op_ftint_w_d; -+ break; -+ case 0x9: -+ op = la_op_ftint_l_s; -+ break; -+ case 0xa: -+ op = la_op_ftint_l_d; -+ break; -+ } -+ break; -+ case 0x3a: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x4: -+ op = la_op_ffint_s_w; -+ break; -+ case 0x6: -+ op = la_op_ffint_s_l; -+ break; -+ case 0x8: -+ op = la_op_ffint_d_w; -+ break; -+ case 0xa: -+ op = la_op_ffint_d_l; -+ break; -+ } -+ break; -+ case 0x3c: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x11: -+ op = la_op_frint_s; -+ break; -+ case 0x12: -+ op = la_op_frint_d; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x8: -+ op = la_op_slti; -+ break; -+ case 0x9: -+ op = la_op_sltui; -+ break; -+ case 0xa: -+ op = la_op_addi_w; -+ break; -+ case 0xb: -+ op = la_op_addi_d; -+ break; -+ case 0xc: -+ op = la_op_lu52i_d; -+ break; -+ case 0xd: -+ op = la_op_addi; -+ break; -+ case 0xe: -+ op = la_op_ori; -+ break; -+ case 0xf: -+ op = la_op_xori; -+ break; -+ } -+ break; -+ case 0x1: -+ switch ((insn >> 24) & 0x3) { -+ case 0x0: -+ op = la_op_csrxchg; -+ break; -+ case 0x2: -+ switch ((insn >> 22) & 0x3) { -+ case 0x0: -+ op = la_op_cacop; -+ break; -+ case 0x1: -+ switch ((insn >> 18) & 0xf) { -+ case 0x0: -+ op = la_op_lddir; -+ break; -+ case 0x1: -+ switch (insn & 0x0000001f) { -+ case 0x00000000: -+ op = la_op_ldpte; -+ break; -+ } -+ break; -+ case 0x2: -+ switch ((insn >> 15) & 0x7) { -+ case 0x0: -+ switch ((insn >> 10) & 0x1f) { -+ case 0x0: -+ op = la_op_iocsrrd_b; -+ break; -+ case 0x1: -+ op = la_op_iocsrrd_h; -+ break; -+ case 0x2: -+ op = la_op_iocsrrd_w; -+ break; -+ case 0x3: -+ op = la_op_iocsrrd_d; -+ break; -+ case 0x4: -+ op = la_op_iocsrwr_b; -+ break; -+ case 0x5: -+ op = la_op_iocsrwr_h; -+ break; -+ case 0x6: -+ op = la_op_iocsrwr_w; -+ break; -+ case 0x7: -+ op = la_op_iocsrwr_d; -+ break; -+ case 0x8: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbclr; -+ break; -+ } -+ break; -+ case 0x9: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbflush; -+ break; -+ } -+ break; -+ case 0xa: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbsrch; -+ break; -+ } -+ break; -+ case 0xb: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbrd; -+ break; -+ } -+ break; -+ case 0xc: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbwr; -+ break; -+ } -+ break; -+ case 0xd: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_tlbfill; -+ break; -+ } -+ break; -+ case 0xe: -+ switch (insn & 0x000003ff) { -+ case 0x00000000: -+ op = la_op_ertn; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x1: -+ op = la_op_idle; -+ break; -+ case 0x3: -+ op = la_op_invtlb; -+ break; -+ } -+ break; -+ } -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x2: -+ switch ((insn >> 20) & 0x3f) { -+ case 0x1: -+ op = la_op_fmadd_s; -+ break; -+ case 0x2: -+ op = la_op_fmadd_d; -+ break; -+ case 0x5: -+ op = la_op_fmsub_s; -+ break; -+ case 0x6: -+ op = la_op_fmsub_d; -+ break; -+ case 0x9: -+ op = la_op_fnmadd_s; -+ break; -+ case 0xa: -+ op = la_op_fnmadd_d; -+ break; -+ case 0xd: -+ op = la_op_fnmsub_s; -+ break; -+ case 0xe: -+ op = la_op_fnmsub_d; -+ break; -+ } -+ break; -+ case 0x3: -+ switch ((insn >> 20) & 0x3f) { -+ case 0x1: -+ switch ((insn >> 3) & 0x3) { -+ case 0x0: -+ op = la_op_fcmp_cond_s; -+ break; -+ } -+ break; -+ case 0x2: -+ switch ((insn >> 3) & 0x3) { -+ case 0x0: -+ op = la_op_fcmp_cond_d; -+ break; -+ } -+ break; -+ case 0x10: -+ switch ((insn >> 18) & 0x3) { -+ case 0x0: -+ op = la_op_fsel; -+ break; -+ } -+ break; -+ } -+ break; -+ case 0x4: -+ op = la_op_addu16i_d; -+ break; -+ case 0x5: -+ switch ((insn >> 25) & 0x1) { -+ case 0x0: -+ op = la_op_lu12i_w; -+ break; -+ case 0x1: -+ op = la_op_lu32i_d; -+ break; -+ } -+ break; -+ case 0x6: -+ switch ((insn >> 25) & 0x1) { -+ case 0x0: -+ op = la_op_pcaddi; -+ break; -+ case 0x1: -+ op = la_op_pcalau12i; -+ break; -+ } -+ break; -+ case 0x7: -+ switch ((insn >> 25) & 0x1) { -+ case 0x0: -+ op = la_op_pcaddu12i; -+ break; -+ case 0x1: -+ op = la_op_pcaddu18i; -+ break; -+ } -+ break; -+ case 0x8: -+ switch ((insn >> 24) & 0x3) { -+ case 0x0: -+ op = la_op_ll_w; -+ break; -+ case 0x1: -+ op = la_op_sc_w; -+ break; -+ case 0x2: -+ op = la_op_ll_d; -+ break; -+ case 0x3: -+ op = la_op_sc_d; -+ break; -+ } -+ break; -+ case 0x9: -+ switch ((insn >> 24) & 0x3) { -+ case 0x0: -+ op = la_op_ldptr_w; -+ break; -+ case 0x1: -+ op = la_op_stptr_w; -+ break; -+ case 0x2: -+ op = la_op_ldptr_d; -+ break; -+ case 0x3: -+ op = la_op_stptr_d; -+ break; -+ } -+ break; -+ case 0xa: -+ switch ((insn >> 22) & 0xf) { -+ case 0x0: -+ op = la_op_ld_b; -+ break; -+ case 0x1: -+ op = la_op_ld_h; -+ break; -+ case 0x2: -+ op = la_op_ld_w; -+ break; -+ case 0x3: -+ op = la_op_ld_d; -+ break; -+ case 0x4: -+ op = la_op_st_b; -+ break; -+ case 0x5: -+ op = la_op_st_h; -+ break; -+ case 0x6: -+ op = la_op_st_w; -+ break; -+ case 0x7: -+ op = la_op_st_d; -+ break; -+ case 0x8: -+ op = la_op_ld_bu; -+ break; -+ case 0x9: -+ op = la_op_ld_hu; -+ break; -+ case 0xa: -+ op = la_op_ld_wu; -+ break; -+ case 0xb: -+ op = la_op_preld; -+ break; -+ case 0xc: -+ op = la_op_fld_s; -+ break; -+ case 0xd: -+ op = la_op_fst_s; -+ break; -+ case 0xe: -+ op = la_op_fld_d; -+ break; -+ case 0xf: -+ op = la_op_fst_d; -+ break; -+ } -+ break; -+ case 0xb: -+ switch ((insn >> 22) & 0xf) { -+ case 0x8: -+ op = la_op_ldl_w; -+ break; -+ case 0x9: -+ op = la_op_ldr_w; -+ break; -+ case 0xa: -+ op = la_op_ldl_d; -+ break; -+ case 0xb: -+ op = la_op_ldr_d; -+ break; -+ case 0xe: -+ op = la_op_stl_d; -+ break; -+ case 0xf: -+ op = la_op_str_d; -+ break; -+ } -+ break; -+ case 0xe: -+ switch ((insn >> 15) & 0x7ff) { -+ case 0x0: -+ op = la_op_ldx_b; -+ break; -+ case 0x8: -+ op = la_op_ldx_h; -+ break; -+ case 0x10: -+ op = la_op_ldx_w; -+ break; -+ case 0x18: -+ op = la_op_ldx_d; -+ break; -+ case 0x20: -+ op = la_op_stx_b; -+ break; -+ case 0x28: -+ op = la_op_stx_h; -+ break; -+ case 0x30: -+ op = la_op_stx_w; -+ break; -+ case 0x38: -+ op = la_op_stx_d; -+ break; -+ case 0x40: -+ op = la_op_ldx_bu; -+ break; -+ case 0x48: -+ op = la_op_ldx_hu; -+ break; -+ case 0x50: -+ op = la_op_ldx_wu; -+ break; -+ case 0x60: -+ op = la_op_fldx_s; -+ break; -+ case 0x68: -+ op = la_op_fldx_d; -+ break; -+ case 0x70: -+ op = la_op_fstx_s; -+ break; -+ case 0x78: -+ op = la_op_fstx_d; -+ break; -+ case 0xc0: -+ op = la_op_amswap_w; -+ break; -+ case 0xc1: -+ op = la_op_amswap_d; -+ break; -+ case 0xc2: -+ op = la_op_amadd_w; -+ break; -+ case 0xc3: -+ op = la_op_amadd_d; -+ break; -+ case 0xc4: -+ op = la_op_amand_w; -+ break; -+ case 0xc5: -+ op = la_op_amand_d; -+ break; -+ case 0xc6: -+ op = la_op_amor_w; -+ break; -+ case 0xc7: -+ op = la_op_amor_d; -+ break; -+ case 0xc8: -+ op = la_op_amxor_w; -+ break; -+ case 0xc9: -+ op = la_op_amxor_d; -+ break; -+ case 0xca: -+ op = la_op_ammax_w; -+ break; -+ case 0xcb: -+ op = la_op_ammax_d; -+ break; -+ case 0xcc: -+ op = la_op_ammin_w; -+ break; -+ case 0xcd: -+ op = la_op_ammin_d; -+ break; -+ case 0xce: -+ op = la_op_ammax_wu; -+ break; -+ case 0xcf: -+ op = la_op_ammax_du; -+ break; -+ case 0xd0: -+ op = la_op_ammin_wu; -+ break; -+ case 0xd1: -+ op = la_op_ammin_du; -+ break; -+ case 0xd2: -+ op = la_op_amswap_db_w; -+ break; -+ case 0xd3: -+ op = la_op_amswap_db_d; -+ break; -+ case 0xd4: -+ op = la_op_amadd_db_w; -+ break; -+ case 0xd5: -+ op = la_op_amadd_db_d; -+ break; -+ case 0xd6: -+ op = la_op_amand_db_w; -+ break; -+ case 0xd7: -+ op = la_op_amand_db_d; -+ break; -+ case 0xd8: -+ op = la_op_amor_db_w; -+ break; -+ case 0xd9: -+ op = la_op_amor_db_d; -+ break; -+ case 0xda: -+ op = la_op_amxor_db_w; -+ break; -+ case 0xdb: -+ op = la_op_amxor_db_d; -+ break; -+ case 0xdc: -+ op = la_op_ammax_db_w; -+ break; -+ case 0xdd: -+ op = la_op_ammax_db_d; -+ break; -+ case 0xde: -+ op = la_op_ammin_db_w; -+ break; -+ case 0xdf: -+ op = la_op_ammin_db_d; -+ break; -+ case 0xe0: -+ op = la_op_ammax_db_wu; -+ break; -+ case 0xe1: -+ op = la_op_ammax_db_du; -+ break; -+ case 0xe2: -+ op = la_op_ammin_db_wu; -+ break; -+ case 0xe3: -+ op = la_op_ammin_db_du; -+ break; -+ case 0xe4: -+ op = la_op_dbar; -+ break; -+ case 0xe5: -+ op = la_op_ibar; -+ break; -+ case 0xe8: -+ op = la_op_fldgt_s; -+ break; -+ case 0xe9: -+ op = la_op_fldgt_d; -+ break; -+ case 0xea: -+ op = la_op_fldle_s; -+ break; -+ case 0xeb: -+ op = la_op_fldle_d; -+ break; -+ case 0xec: -+ op = la_op_fstgt_s; -+ break; -+ case 0xed: -+ op = la_op_fstgt_d; -+ break; -+ case 0xee: -+ op = ls_op_fstle_s; -+ break; -+ case 0xef: -+ op = la_op_fstle_d; -+ break; -+ case 0xf0: -+ op = la_op_ldgt_b; -+ break; -+ case 0xf1: -+ op = la_op_ldgt_h; -+ break; -+ case 0xf2: -+ op = la_op_ldgt_w; -+ break; -+ case 0xf3: -+ op = la_op_ldgt_d; -+ break; -+ case 0xf4: -+ op = la_op_ldle_b; -+ break; -+ case 0xf5: -+ op = la_op_ldle_h; -+ break; -+ case 0xf6: -+ op = la_op_ldle_w; -+ break; -+ case 0xf7: -+ op = la_op_ldle_d; -+ break; -+ case 0xf8: -+ op = la_op_stgt_b; -+ break; -+ case 0xf9: -+ op = la_op_stgt_h; -+ break; -+ case 0xfa: -+ op = la_op_stgt_w; -+ break; -+ case 0xfb: -+ op = la_op_stgt_d; -+ break; -+ case 0xfc: -+ op = la_op_stle_b; -+ break; -+ case 0xfd: -+ op = la_op_stle_h; -+ break; -+ case 0xfe: -+ op = la_op_stle_w; -+ break; -+ case 0xff: -+ op = la_op_stle_d; -+ break; -+ } -+ break; -+ case 0x10: -+ op = la_op_beqz; -+ break; -+ case 0x11: -+ op = la_op_bnez; -+ break; -+ case 0x12: -+ switch ((insn >> 8) & 0x3) { -+ case 0x0: -+ op = la_op_bceqz; -+ break; -+ case 0x1: -+ op = la_op_bcnez; -+ break; -+ } -+ break; -+ case 0x13: -+ op = la_op_jirl; -+ break; -+ case 0x14: -+ op = la_op_b; -+ break; -+ case 0x15: -+ op = la_op_bl; -+ break; -+ case 0x16: -+ op = la_op_beq; -+ break; -+ case 0x17: -+ op = la_op_bne; -+ break; -+ case 0x18: -+ op = la_op_blt; -+ break; -+ case 0x19: -+ op = la_op_bge; -+ break; -+ case 0x1a: -+ op = la_op_bltu; -+ break; -+ case 0x1b: -+ op = la_op_bgeu; -+ break; -+ default: -+ op = la_op_illegal; -+ break; -+ } -+ dec->op = op; -+} -+ -+/* operand extractors */ -+ -+#define IM_5 5 -+#define IM_8 8 -+#define IM_12 12 -+#define IM_14 14 -+#define IM_15 15 -+#define IM_16 16 -+#define IM_20 20 -+#define IM_21 21 -+#define IM_26 26 -+ -+static uint32_t operand_r1(uint32_t insn) -+{ -+ return insn & 0x1f; -+} -+ -+static uint32_t operand_r2(uint32_t insn) -+{ -+ return (insn >> 5) & 0x1f; -+} -+ -+static uint32_t operand_r3(uint32_t insn) -+{ -+ return (insn >> 10) & 0x1f; -+} -+ -+static uint32_t operand_r4(uint32_t insn) -+{ -+ return (insn >> 15) & 0x1f; -+} -+ -+static uint32_t operand_u6(uint32_t insn) -+{ -+ return (insn >> 10) & 0x3f; -+} -+ -+static uint32_t operand_bw1(uint32_t insn) -+{ -+ return (insn >> 10) & 0x1f; -+} -+ -+static uint32_t operand_bw2(uint32_t insn) -+{ -+ return (insn >> 16) & 0x1f; -+} -+ -+static uint32_t operand_bd1(uint32_t insn) -+{ -+ return (insn >> 10) & 0x3f; -+} -+ -+static uint32_t operand_bd2(uint32_t insn) -+{ -+ return (insn >> 16) & 0x3f; -+} -+ -+static uint32_t operand_sa2(uint32_t insn) -+{ -+ return (insn >> 15) & 0x3; -+} -+ -+static uint32_t operand_sa3(uint32_t insn) -+{ -+ return (insn >> 15) & 0x3; -+} -+ -+static int32_t operand_im20(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 5) & 0xfffff); -+ return imm > (1 << 19) ? imm - (1 << 20) : imm; -+} -+ -+static int32_t operand_im16(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 10) & 0xffff); -+ return imm > (1 << 15) ? imm - (1 << 16) : imm; -+} -+ -+static int32_t operand_im14(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 10) & 0x3fff); -+ return imm > (1 << 13) ? imm - (1 << 14) : imm; -+} -+ -+static int32_t operand_im12(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 10) & 0xfff); -+ return imm > (1 << 11) ? imm - (1 << 12) : imm; -+} -+ -+static int32_t operand_im8(uint32_t insn) -+{ -+ int32_t imm = (int32_t)((insn >> 10) & 0xff); -+ return imm > (1 << 7) ? imm - (1 << 8) : imm; -+} -+ -+static uint32_t operand_sd(uint32_t insn) -+{ -+ return insn & 0x3; -+} -+ -+static uint32_t operand_sj(uint32_t insn) -+{ -+ return (insn >> 5) & 0x3; -+} -+ -+static uint32_t operand_cd(uint32_t insn) -+{ -+ return insn & 0x7; -+} -+ -+static uint32_t operand_cj(uint32_t insn) -+{ -+ return (insn >> 5) & 0x7; -+} -+ -+static uint32_t operand_code(uint32_t insn) -+{ -+ return insn & 0x7fff; -+} -+ -+static int32_t operand_whint(uint32_t insn) -+{ -+ int32_t imm = (int32_t)(insn & 0x7fff); -+ return imm > (1 << 14) ? imm - (1 << 15) : imm; -+} -+ -+static int32_t operand_invop(uint32_t insn) -+{ -+ int32_t imm = (int32_t)(insn & 0x1f); -+ return imm > (1 << 4) ? imm - (1 << 5) : imm; -+} -+ -+static int32_t operand_ofs21(uint32_t insn) -+{ -+ int32_t imm = (((int32_t)insn & 0x1f) << 16) | -+ ((insn >> 10) & 0xffff); -+ return imm > (1 << 20) ? imm - (1 << 21) : imm; -+} -+ -+static int32_t operand_ofs26(uint32_t insn) -+{ -+ int32_t imm = (((int32_t)insn & 0x3ff) << 16) | -+ ((insn >> 10) & 0xffff); -+ return imm > (1 << 25) ? imm - (1 << 26) : imm; -+} -+ -+static uint32_t operand_fcond(uint32_t insn) -+{ -+ return (insn >> 15) & 0x1f; -+} -+ -+static uint32_t operand_sel(uint32_t insn) -+{ -+ return (insn >> 15) & 0x7; -+} -+ -+/* decode operands */ -+ -+static void decode_insn_operands(la_decode *dec) -+{ -+ uint32_t insn = dec->insn; -+ dec->codec = opcode_data[dec->op].codec; -+ switch (dec->codec) { -+ case la_codec_illegal: -+ case la_codec_empty: -+ break; -+ case la_codec_2r: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ break; -+ case la_codec_2r_u5: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ break; -+ case la_codec_2r_u6: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_u6(insn); -+ break; -+ case la_codec_2r_2bw: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_bw1(insn); -+ dec->r4 = operand_bw2(insn); -+ break; -+ case la_codec_2r_2bd: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_bd1(insn); -+ dec->r4 = operand_bd2(insn); -+ break; -+ case la_codec_3r: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ break; -+ case la_codec_3r_rd0: -+ dec->r1 = 0; -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ break; -+ case la_codec_3r_sa2: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_sa2(insn); -+ break; -+ case la_codec_3r_sa3: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_sa3(insn); -+ break; -+ case la_codec_4r: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_r4(insn); -+ break; -+ case la_codec_r_im20: -+ dec->r1 = operand_r1(insn); -+ dec->imm = operand_im20(insn); -+ dec->bit = IM_20; -+ break; -+ case la_codec_2r_im16: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im16(insn); -+ dec->bit = IM_16; -+ break; -+ case la_codec_2r_im14: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im14(insn); -+ dec->bit = IM_14; -+ break; -+ case la_codec_im5_r_im12: -+ dec->imm2 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im12(insn); -+ dec->bit = IM_12; -+ break; -+ case la_codec_2r_im12: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im12(insn); -+ dec->bit = IM_12; -+ break; -+ case la_codec_2r_im8: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->imm = operand_im8(insn); -+ dec->bit = IM_8; -+ break; -+ case la_codec_r_sd: -+ dec->r1 = operand_sd(insn); -+ dec->r2 = operand_r2(insn); -+ break; -+ case la_codec_r_sj: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_sj(insn); -+ break; -+ case la_codec_r_cd: -+ dec->r1 = operand_cd(insn); -+ dec->r2 = operand_r2(insn); -+ break; -+ case la_codec_r_cj: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_cj(insn); -+ break; -+ case la_codec_r_seq: -+ dec->r1 = 0; -+ dec->r2 = operand_r1(insn); -+ dec->imm = operand_im8(insn); -+ dec->bit = IM_8; -+ break; -+ case la_codec_code: -+ dec->code = operand_code(insn); -+ break; -+ case la_codec_whint: -+ dec->imm = operand_whint(insn); -+ dec->bit = IM_15; -+ break; -+ case la_codec_invtlb: -+ dec->imm = operand_invop(insn); -+ dec->bit = IM_5; -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ break; -+ case la_codec_r_ofs21: -+ dec->imm = operand_ofs21(insn); -+ dec->bit = IM_21; -+ dec->r2 = operand_r2(insn); -+ break; -+ case la_codec_cj_ofs21: -+ dec->imm = operand_ofs21(insn); -+ dec->bit = IM_21; -+ dec->r2 = operand_cj(insn); -+ break; -+ case la_codec_ofs26: -+ dec->imm = operand_ofs26(insn); -+ dec->bit = IM_26; -+ break; -+ case la_codec_cond: -+ dec->r1 = operand_cd(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_fcond(insn); -+ break; -+ case la_codec_sel: -+ dec->r1 = operand_r1(insn); -+ dec->r2 = operand_r2(insn); -+ dec->r3 = operand_r3(insn); -+ dec->r4 = operand_sel(insn); -+ break; -+ } -+} -+ -+/* format instruction */ -+ -+static void append(char *s1, const char *s2, size_t n) -+{ -+ size_t l1 = strlen(s1); -+ if (n - l1 - 1 > 0) { -+ strncat(s1, s2, n - l1); -+ } -+} -+ -+static void format_insn(char *buf, size_t buflen, size_t tab, la_decode *dec) -+{ -+ char tmp[16]; -+ const char *fmt; -+ -+ fmt = opcode_data[dec->op].format; -+ while (*fmt) { -+ switch (*fmt) { -+ case 'n': /* name */ -+ append(buf, opcode_data[dec->op].name, buflen); -+ break; -+ case 's': -+ append(buf, "s", buflen); -+ break; -+ case 'd': -+ append(buf, "d", buflen); -+ break; -+ case 'e': /* illegal */ -+ snprintf(tmp, sizeof(tmp), "%x", dec->insn); -+ append(buf, tmp, buflen); -+ break; -+ case 't': -+ while (strlen(buf) < tab) { -+ append(buf, " ", buflen); -+ } -+ break; -+ case '(': -+ append(buf, "(", buflen); -+ break; -+ case ',': -+ append(buf, ",", buflen); -+ break; -+ case '.': -+ append(buf, ".", buflen); -+ break; -+ case ')': -+ append(buf, ")", buflen); -+ break; -+ case '0': /* rd */ -+ append(buf, loongarch_r_normal_name[dec->r1], buflen); -+ break; -+ case '1': /* rj */ -+ append(buf, loongarch_r_normal_name[dec->r2], buflen); -+ break; -+ case '2': /* rk */ -+ append(buf, loongarch_r_normal_name[dec->r3], buflen); -+ break; -+ case '3': /* fd */ -+ append(buf, loongarch_f_normal_name[dec->r1], buflen); -+ break; -+ case '4': /* fj */ -+ append(buf, loongarch_f_normal_name[dec->r2], buflen); -+ break; -+ case '5': /* fk */ -+ append(buf, loongarch_f_normal_name[dec->r3], buflen); -+ break; -+ case '6': /* fa */ -+ append(buf, loongarch_f_normal_name[dec->r4], buflen); -+ break; -+ case 'A': /* sd */ -+ append(buf, loongarch_cr_normal_name[dec->r1], buflen); -+ break; -+ case 'B': /* sj */ -+ append(buf, loongarch_cr_normal_name[dec->r2], buflen); -+ break; -+ case 'C': /* r3 */ -+ snprintf(tmp, sizeof(tmp), "%x", dec->r3); -+ append(buf, tmp, buflen); -+ break; -+ case 'D': /* r4 */ -+ snprintf(tmp, sizeof(tmp), "%x", dec->r4); -+ append(buf, tmp, buflen); -+ break; -+ case 'E': /* r1 */ -+ snprintf(tmp, sizeof(tmp), "%x", dec->r1); -+ append(buf, tmp, buflen); -+ break; -+ case 'F': /* fcsrd */ -+ append(buf, loongarch_r_normal_name[dec->r1], buflen); -+ break; -+ case 'G': /* fcsrs */ -+ append(buf, loongarch_r_normal_name[dec->r2], buflen); -+ break; -+ case 'H': /* cd */ -+ append(buf, loongarch_c_normal_name[dec->r1], buflen); -+ break; -+ case 'I': /* cj */ -+ append(buf, loongarch_c_normal_name[dec->r2], buflen); -+ break; -+ case 'J': /* code */ -+ snprintf(tmp, sizeof(tmp), "0x%x", dec->code); -+ append(buf, tmp, buflen); -+ break; -+ case 'K': /* cond */ -+ switch (dec->r4) { -+ case 0x0: -+ append(buf, "caf", buflen); -+ break; -+ case 0x1: -+ append(buf, "saf", buflen); -+ break; -+ case 0x2: -+ append(buf, "clt", buflen); -+ break; -+ case 0x3: -+ append(buf, "slt", buflen); -+ break; -+ case 0x4: -+ append(buf, "ceq", buflen); -+ break; -+ case 0x5: -+ append(buf, "seq", buflen); -+ break; -+ case 0x6: -+ append(buf, "cle", buflen); -+ break; -+ case 0x7: -+ append(buf, "sle", buflen); -+ break; -+ case 0x8: -+ append(buf, "cun", buflen); -+ break; -+ case 0x9: -+ append(buf, "sun", buflen); -+ break; -+ case 0xA: -+ append(buf, "cult", buflen); -+ break; -+ case 0xB: -+ append(buf, "sult", buflen); -+ break; -+ case 0xC: -+ append(buf, "cueq", buflen); -+ break; -+ case 0xD: -+ append(buf, "sueq", buflen); -+ break; -+ case 0xE: -+ append(buf, "cule", buflen); -+ break; -+ case 0xF: -+ append(buf, "sule", buflen); -+ break; -+ case 0x10: -+ append(buf, "cne", buflen); -+ break; -+ case 0x11: -+ append(buf, "sne", buflen); -+ break; -+ case 0x14: -+ append(buf, "cor", buflen); -+ break; -+ case 0x15: -+ append(buf, "sor", buflen); -+ break; -+ case 0x18: -+ append(buf, "cune", buflen); -+ break; -+ case 0x19: -+ append(buf, "sune", buflen); -+ break; -+ } -+ break; -+ case 'L': /* ca */ -+ append(buf, loongarch_c_normal_name[dec->r4], buflen); -+ break; -+ case 'M': /* cop */ -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm2) & 0x1f); -+ append(buf, tmp, buflen); -+ break; -+ case 'i': /* sixx d */ -+ snprintf(tmp, sizeof(tmp), "%d", dec->imm); -+ append(buf, tmp, buflen); -+ break; -+ case 'o': /* offset */ -+ snprintf(tmp, sizeof(tmp), "%d", (dec->imm) << 2); -+ append(buf, tmp, buflen); -+ break; -+ case 'x': /* sixx x */ -+ switch (dec->bit) { -+ case IM_5: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x1f); -+ append(buf, tmp, buflen); -+ break; -+ case IM_8: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_12: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_14: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x3fff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_15: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x7fff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_16: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xffff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_20: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfffff); -+ append(buf, tmp, buflen); -+ break; -+ default: -+ snprintf(tmp, sizeof(tmp), "0x%x", dec->imm); -+ append(buf, tmp, buflen); -+ break; -+ } -+ break; -+ case 'X': /* offset x*/ -+ switch (dec->bit) { -+ case IM_16: -+ snprintf(tmp, sizeof(tmp), "0x%x", -+ ((dec->imm) << 2) & 0xffff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_21: -+ snprintf(tmp, sizeof(tmp), "0x%x", -+ ((dec->imm) << 2) & 0x1fffff); -+ append(buf, tmp, buflen); -+ break; -+ case IM_26: -+ snprintf(tmp, sizeof(tmp), "0x%x", -+ ((dec->imm) << 2) & 0x3ffffff); -+ append(buf, tmp, buflen); -+ break; -+ default: -+ snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) << 2); -+ append(buf, tmp, buflen); -+ break; -+ } -+ break; -+ case 'p': /* pc */ -+ snprintf(tmp, sizeof(tmp), " # 0x%"PRIx32"", -+ dec->pc + ((dec->imm) << 2)); -+ append(buf, tmp, buflen); -+ break; -+ default: -+ break; -+ } -+ fmt++; -+ } -+} -+ -+ -+/* disassemble instruction */ -+ -+static void -+disasm_insn(char *buf, size_t buflen, bfd_vma pc, unsigned long int insn) -+{ -+ la_decode dec = { 0 }; -+ dec.pc = pc; -+ dec.insn = insn; -+ decode_insn_opcode(&dec); -+ decode_insn_operands(&dec); -+ format_insn(buf, buflen, 16, &dec); -+} -+ -+int -+print_insn_loongarch(bfd_vma memaddr, struct disassemble_info *info) -+{ -+ char buf[128] = { 0 }; -+ bfd_byte buffer[INSNLEN]; -+ unsigned long insn; -+ int status; -+ -+ status = (*info->read_memory_func)(memaddr, buffer, INSNLEN, info); -+ if (status == 0) { -+ insn = (uint32_t) bfd_getl32(buffer); -+ (*info->fprintf_func)(info->stream, "%08" PRIx64 " ", insn); -+ } else { -+ (*info->memory_error_func)(status, memaddr, info); -+ return -1; -+ } -+ disasm_insn(buf, sizeof(buf), memaddr, insn); -+ (*info->fprintf_func)(info->stream, "\t%s", buf); -+ return INSNLEN; -+} -diff --git a/disas/meson.build b/disas/meson.build -index 449f99e1d..06a69d9d7 100644 ---- a/disas/meson.build -+++ b/disas/meson.build -@@ -12,6 +12,7 @@ common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c')) - common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) - common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) - common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) -+common_ss.add(when: 'CONFIG_LOONGARCH_DIS', if_true: files('loongarch.c')) - common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.cpp')) - common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c')) - common_ss.add(when: 'CONFIG_PPC_DIS', if_true: files('ppc.c')) -diff --git a/gdb-xml/loongarch-base32.xml b/gdb-xml/loongarch-base32.xml -new file mode 100644 -index 000000000..04891e023 ---- /dev/null -+++ b/gdb-xml/loongarch-base32.xml -@@ -0,0 +1,43 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/gdb-xml/loongarch-base64.xml b/gdb-xml/loongarch-base64.xml -new file mode 100644 -index 000000000..6308fb6ec ---- /dev/null -+++ b/gdb-xml/loongarch-base64.xml -@@ -0,0 +1,43 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/gdb-xml/loongarch-fpu32.xml b/gdb-xml/loongarch-fpu32.xml -new file mode 100644 -index 000000000..a5b4d80e6 ---- /dev/null -+++ b/gdb-xml/loongarch-fpu32.xml -@@ -0,0 +1,52 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/gdb-xml/loongarch-fpu64.xml b/gdb-xml/loongarch-fpu64.xml -new file mode 100644 -index 000000000..74ab55a01 ---- /dev/null -+++ b/gdb-xml/loongarch-fpu64.xml -@@ -0,0 +1,57 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ --- -2.43.5 - diff --git a/0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch b/0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch deleted file mode 100644 index af4851e4316b89bedaaca41d70408eb57cb6e9a3..0000000000000000000000000000000000000000 --- a/0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch +++ /dev/null @@ -1,35 +0,0 @@ -From e25884e4e0ee839b591836ae33681ac9a52883ce Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Wed, 25 Aug 2021 12:36:00 +0800 -Subject: [PATCH 6/8] anolis: csv/i386: CSV guest do not need - register/unregister guest secure memory - -CSV guest memory is allocated by firmware in secure processor -from dedicated memory reserved upon system boot up, -consequently it is not necessary to add notifier to pin/unpin memory. - -Signed-off-by: Xin Jiang -Change-Id: I10d5b5ee8dbc3a1bf9ed1935c006c61a094f1e8d ---- - target/i386/sev.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 73a794ef74..36669bbdf4 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -973,7 +973,10 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - goto err; - } - -- ram_block_notifier_add(&sev_ram_notifier); -+ /* CSV guest needs no notifier to reg/unreg memory */ -+ if (!csv_enabled()) { -+ ram_block_notifier_add(&sev_ram_notifier); -+ } - qemu_add_machine_init_done_notifier(&sev_machine_done_notify); - qemu_add_vm_change_state_handler(sev_vm_state_change, sev); - --- -2.17.1 - diff --git a/0007-Modify-kvm-cpu-vga-qapi.patch b/0007-Modify-kvm-cpu-vga-qapi.patch deleted file mode 100644 index 7c09b0a68a65277ce9cf28dd417e84ad7bb46abd..0000000000000000000000000000000000000000 --- a/0007-Modify-kvm-cpu-vga-qapi.patch +++ /dev/null @@ -1,477 +0,0 @@ -From 42c6c2a89fa44100141cd2b7e178f965d1b8f80f Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Sat, 20 Aug 2022 02:18:41 -0400 -Subject: [PATCH 07/28] Modify kvm cpu vga qapi. - -Change-Id: I7923af804bdbe6d44d3f521df1859aa081afceba -Signed-off-by: lixianglai -Signed-off-by: Mao Bibo ---- - hw/acpi/cpu.c | 11 ++++++ - hw/loongarch/iocsr.c | 2 ++ - hw/loongarch/larch_3a.c | 18 +++++----- - hw/meson.build | 1 + - include/disas/dis-asm.h | 1 + - include/elf.h | 2 ++ - include/hw/loongarch/larch.h | 1 - - include/qemu/osdep.h | 3 ++ - include/sysemu/arch_init.h | 1 + - linux-headers/linux/kvm.h | 23 +++++++++++++ - linux-user/elfload.c | 67 ++++++++++++++++++++++++++++++++++++ - linux-user/meson.build | 1 + - linux-user/qemu.h | 2 +- - linux-user/syscall.c | 3 ++ - linux-user/syscall_defs.h | 9 ++--- - meson.build | 1 + - pc-bios/meson.build | 1 + - qapi/machine-target.json | 6 ++-- - qapi/machine.json | 2 +- - qapi/misc-target.json | 1 + - 20 files changed, 138 insertions(+), 18 deletions(-) - -diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c -index b20903ea3..cd73fab65 100644 ---- a/hw/acpi/cpu.c -+++ b/hw/acpi/cpu.c -@@ -371,14 +371,25 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, - aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0)); - - crs = aml_resource_template(); -+#ifdef __loongarch__ -+ aml_append(crs, aml_memory32_fixed(io_base, -+ ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE)); -+#else - aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, - ACPI_CPU_HOTPLUG_REG_LEN)); -+#endif - aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs)); - - /* declare CPU hotplug MMIO region with related access fields */ -+#ifdef __loongarch__ -+ aml_append(cpu_ctrl_dev, -+ aml_operation_region("PRST", AML_SYSTEM_MEMORY, aml_int(io_base), -+ ACPI_CPU_HOTPLUG_REG_LEN)); -+#else - aml_append(cpu_ctrl_dev, - aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base), - ACPI_CPU_HOTPLUG_REG_LEN)); -+#endif - - field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, - AML_WRITE_AS_ZEROS); -diff --git a/hw/loongarch/iocsr.c b/hw/loongarch/iocsr.c -index 14521c2d5..60daafd6e 100644 ---- a/hw/loongarch/iocsr.c -+++ b/hw/loongarch/iocsr.c -@@ -59,6 +59,7 @@ enum { - IOCSR_MAX - }; - -+#ifdef CONFIG_KVM - static uint32_t iocsr_array[IOCSR_MAX] = { - [IOCSR_FEATURES] = LOONGARCH_IOCSR_FEATURES, - [IOCSR_VENDOR] = LOONGARCH_IOCSR_VENDOR, -@@ -66,6 +67,7 @@ static uint32_t iocsr_array[IOCSR_MAX] = { - [IOCSR_NODECNT] = LOONGARCH_IOCSR_NODECNT, - [IOCSR_MISC_FUNC] = LOONGARCH_IOCSR_MISC_FUNC, - }; -+#endif - - - #define TYPE_IOCSR "iocsr" -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 3db269274..3194a822c 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -846,7 +846,7 @@ static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg, - if (0 < initrd_size) { - if (initrd_size > highram_size) { - error_report("initrd size is too big, should below %ld MB", -- highram_size / S_1MiB); -+ highram_size / MiB); - /*prevent write io memory address space*/ - exit(1); - } -@@ -1033,7 +1033,9 @@ static void *ls3a_intctl_init(MachineState *machine, CPULOONGARCHState *env[]) - SysBusDevice *busdev; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *iomem = NULL; -+#ifdef CONFIG_KVM - int i; -+#endif - - s = g_malloc0(sizeof(ls3a_intctlstate)); - -@@ -1214,8 +1216,6 @@ static void loongarch_build_smbios(LoongarchMachineState *lsms) - product = "Loongarch-3A5K-7A1000-TCG"; - } - -- host_cpufreq = get_host_cpu_freq(); -- - smbios_set_defaults("Loongson", product, lsmc->cpu_name, false, - true, NULL, NULL, SMBIOS_ENTRY_POINT_30); - -@@ -1672,15 +1672,15 @@ static void ls3a5k_init(MachineState *args) - - offset += lowram_size; - if (nb_numa_nodes > 0) { -- highram_size = numa_info[0].node_mem - S_256MiB; -- if (numa_info[0].node_mem > S_1GiB) { -- memmap_size = numa_info[0].node_mem - S_1GiB; -+ highram_size = numa_info[0].node_mem - 256 * MiB; -+ if (numa_info[0].node_mem > GiB) { -+ memmap_size = numa_info[0].node_mem - GiB; - la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); - } - } else { -- highram_size = ram_size - S_256MiB; -- if (ram_size > S_1GiB) { -- memmap_size = ram_size - S_1GiB; -+ highram_size = ram_size - 256 * MiB; -+ if (ram_size > GiB) { -+ memmap_size = ram_size - GiB; - la_memmap_add_entry(0xc0000000ULL, memmap_size, SYSTEM_RAM); - } - } -diff --git a/hw/meson.build b/hw/meson.build -index b3366c888..f224f8ad2 100644 ---- a/hw/meson.build -+++ b/hw/meson.build -@@ -17,6 +17,7 @@ subdir('intc') - subdir('ipack') - subdir('ipmi') - subdir('isa') -+subdir('loongarch') - subdir('mem') - subdir('misc') - subdir('net') -diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h -index 08e1beec8..95b93f100 100644 ---- a/include/disas/dis-asm.h -+++ b/include/disas/dis-asm.h -@@ -461,6 +461,7 @@ int print_insn_riscv32 (bfd_vma, disassemble_info*); - int print_insn_riscv64 (bfd_vma, disassemble_info*); - int print_insn_rx(bfd_vma, disassemble_info *); - int print_insn_hexagon(bfd_vma, disassemble_info *); -+int print_insn_loongarch (bfd_vma, disassemble_info*); - - #ifdef CONFIG_CAPSTONE - bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size); -diff --git a/include/elf.h b/include/elf.h -index 4edab8e5a..c614bfb12 100644 ---- a/include/elf.h -+++ b/include/elf.h -@@ -182,6 +182,8 @@ typedef struct mips_elf_abiflags_v0 { - - #define EM_NANOMIPS 249 /* Wave Computing nanoMIPS */ - -+#define EM_LOONGARCH 258 /* Loongarch */ -+ - /* - * This is an interim value that we will use until the committee comes - * up with a final number. -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -index 0886ed52a..62e2830e2 100644 ---- a/include/hw/loongarch/larch.h -+++ b/include/hw/loongarch/larch.h -@@ -159,5 +159,4 @@ bool loongarch_is_acpi_enabled(LoongarchMachineState *vms); - void ls7a_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, bool force_enabled); - void slave_cpu_reset(void *opaque); --extern uint64_t host_cpufreq; - #endif -diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h -index 60718fc34..903475bb2 100644 ---- a/include/qemu/osdep.h -+++ b/include/qemu/osdep.h -@@ -533,6 +533,9 @@ static inline void qemu_cleanup_generic_vfree(void *p) - Valgrind does not support alignments larger than 1 MiB, - therefore we need special code which handles running on Valgrind. */ - # define QEMU_VMALLOC_ALIGN (512 * 4096) -+#elif defined(__linux__) && defined(__loongarch__) -+ /* Use 32 MiB alignment so transparent hugepages can be used by KVM. */ -+# define QEMU_VMALLOC_ALIGN (qemu_real_host_page_size * qemu_real_host_page_size / 8) - #elif defined(__linux__) && defined(__s390x__) - /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */ - # define QEMU_VMALLOC_ALIGN (256 * 4096) -diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h -index 70c579560..62d1a4b92 100644 ---- a/include/sysemu/arch_init.h -+++ b/include/sysemu/arch_init.h -@@ -24,6 +24,7 @@ enum { - QEMU_ARCH_RX = (1 << 20), - QEMU_ARCH_AVR = (1 << 21), - QEMU_ARCH_HEXAGON = (1 << 22), -+ QEMU_ARCH_LOONGARCH64 = (1 << 23), - }; - - extern const uint32_t arch_type; -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index c65930288..0e50d3749 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -2115,6 +2115,29 @@ struct kvm_stats_desc { - char name[]; - }; - -+#ifdef __loongarch__ -+struct kvm_loongarch_vcpu_state { -+ __u8 online_vcpus; -+ __u8 is_migrate; -+ __u32 cpu_freq; -+ __u32 count_ctl; -+ __u64 pending_exceptions; -+ __u64 pending_exceptions_clr; -+ __u64 core_ext_ioisr[4]; -+}; -+ -+#define KVM_CAP_LOONGARCH_FPU 165 -+#define KVM_CAP_LOONGARCH_LSX 166 -+#define KVM_CAP_LOONGARCH_VZ 167 -+#define KVM_REG_LOONGARCH 0x8000000000000000ULL -+#define KVM_LARCH_GET_VCPU_STATE _IOR(KVMIO, 0xc0, struct kvm_loongarch_vcpu_state) -+#define KVM_LARCH_SET_VCPU_STATE _IOW(KVMIO, 0xc1, struct kvm_loongarch_vcpu_state) -+#define KVM_LARCH_GET_CPUCFG _IOR(KVMIO, 0xc2, struct kvm_cpucfg) -+#define KVM_LOONGARCH_GET_IOCSR _IOR(KVMIO, 0xc3, struct kvm_iocsr_entry) -+#define KVM_LOONGARCH_SET_IOCSR _IOW(KVMIO, 0xc4, struct kvm_iocsr_entry) -+#define KVM_LARCH_SET_CPUCFG _IOR(KVMIO, 0xc5, struct kvm_cpucfg) -+#endif -+ - #define KVM_GET_STATS_FD _IO(KVMIO, 0xce) - - /* Available with KVM_CAP_XSAVE2 */ -diff --git a/linux-user/elfload.c b/linux-user/elfload.c -index 767f54c76..9fb632780 100644 ---- a/linux-user/elfload.c -+++ b/linux-user/elfload.c -@@ -1041,6 +1041,73 @@ static uint32_t get_elf_hwcap(void) - - #endif /* TARGET_MIPS */ - -+#ifdef TARGET_LOONGARCH64 -+ -+#define ELF_START_MMAP 0x80000000 -+ -+#define ELF_CLASS ELFCLASS64 -+#define ELF_ARCH EM_LOONGARCH -+ -+#define elf_check_arch(x) ((x) == EM_LOONGARCH) -+ -+static inline void init_thread(struct target_pt_regs *regs, -+ struct image_info *infop) -+{ -+ regs->csr_crmd = 2 << 3; -+ regs->csr_era = infop->entry; -+ regs->regs[3] = infop->start_stack; -+} -+ -+/* See linux kernel: arch/mips/include/asm/elf.h. */ -+#define ELF_NREG 45 -+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; -+ -+/* See linux kernel: arch/loongarch/include/uapi/asm/reg.h */ -+enum { -+ TARGET_EF_R0 = 0, -+ TARGET_EF_R26 = TARGET_EF_R0 + 26, -+ TARGET_EF_R27 = TARGET_EF_R0 + 27, -+ TARGET_EF_CSR_ERA = TARGET_EF_R0 + 32, -+ TARGET_EF_CSR_BADV = TARGET_EF_R0 + 33, -+ TARGET_EF_CSR_CRMD = TARGET_EF_R0 + 34, -+ TARGET_EF_CSR_ESTAT = TARGET_EF_R0 + 38 -+}; -+ -+/* See linux kernel: arch/loongarch/kernel/process.c:elf_dump_regs. */ -+static void elf_core_copy_regs(target_elf_gregset_t *regs, -+ const CPULOONGARCHState *env) -+{ -+ int i; -+ -+ for (i = 0; i < TARGET_EF_R0; i++) { -+ (*regs)[i] = 0; -+ } -+ (*regs)[TARGET_EF_R0] = 0; -+ -+ for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) { -+ (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]); -+ } -+ -+ (*regs)[TARGET_EF_R26] = 0; -+ (*regs)[TARGET_EF_R27] = 0; -+ (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->active_tc.PC); -+ (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV); -+ (*regs)[TARGET_EF_CSR_CRMD] = tswapreg(env->CSR_CRMD); -+ (*regs)[TARGET_EF_CSR_ESTAT] = tswapreg(env->CSR_ESTAT); -+} -+ -+#define USE_ELF_CORE_DUMP -+#define ELF_EXEC_PAGESIZE 4096 -+ -+#define ELF_HWCAP get_elf_hwcap() -+ -+static uint32_t get_elf_hwcap(void) -+{ -+ return 0; -+} -+ -+#endif /* TARGET_LOONGARCH64 */ -+ - #ifdef TARGET_MICROBLAZE - - #define ELF_START_MMAP 0x80000000 -diff --git a/linux-user/meson.build b/linux-user/meson.build -index bf62c13e3..195f9e83a 100644 ---- a/linux-user/meson.build -+++ b/linux-user/meson.build -@@ -39,3 +39,4 @@ subdir('sh4') - subdir('sparc') - subdir('x86_64') - subdir('xtensa') -+subdir('loongarch64') -diff --git a/linux-user/qemu.h b/linux-user/qemu.h -index 5c713fa8a..66ddb25d1 100644 ---- a/linux-user/qemu.h -+++ b/linux-user/qemu.h -@@ -61,7 +61,7 @@ struct image_info { - /* For target-specific processing of NT_GNU_PROPERTY_TYPE_0. */ - uint32_t note_flags; - --#ifdef TARGET_MIPS -+#if defined(TARGET_MIPS) || defined(TARGET_LOONGARCH64) - int fp_abi; - int interp_fp_abi; - #endif -diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index f1cfcc810..729131ecd 100644 ---- a/linux-user/syscall.c -+++ b/linux-user/syscall.c -@@ -1614,6 +1614,9 @@ static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, - #elif defined(TARGET_MIPS) - ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1]; - return host_pipe[0]; -+#elif defined(TARGET_LOONGARCH64) -+ ((CPULOONGARCHState *)cpu_env)->active_tc.gpr[5] = host_pipe[1]; -+ return host_pipe[0]; - #elif defined(TARGET_SH4) - ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; - return host_pipe[0]; -diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h -index 0b1397593..7e2915d53 100644 ---- a/linux-user/syscall_defs.h -+++ b/linux-user/syscall_defs.h -@@ -74,7 +74,7 @@ - || defined(TARGET_M68K) || defined(TARGET_CRIS) \ - || defined(TARGET_S390X) || defined(TARGET_OPENRISC) \ - || defined(TARGET_NIOS2) || defined(TARGET_RISCV) \ -- || defined(TARGET_XTENSA) -+ || defined(TARGET_XTENSA) || defined(TARGET_LOONGARCH64) - - #define TARGET_IOC_SIZEBITS 14 - #define TARGET_IOC_DIRBITS 2 -@@ -450,7 +450,7 @@ struct target_dirent64 { - #define TARGET_SIG_IGN ((abi_long)1) /* ignore signal */ - #define TARGET_SIG_ERR ((abi_long)-1) /* error return from signal */ - --#ifdef TARGET_MIPS -+#if defined(TARGET_MIPS) || defined(TARGET_LOONGARCH64) - #define TARGET_NSIG 128 - #else - #define TARGET_NSIG 64 -@@ -2133,7 +2133,7 @@ struct target_stat64 { - abi_ulong __unused5; - }; - --#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || defined(TARGET_RISCV) -+#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || defined(TARGET_RISCV) || defined(TARGET_LOONGARCH64) - - /* These are the asm-generic versions of the stat and stat64 structures */ - -@@ -2161,7 +2161,7 @@ struct target_stat { - unsigned int __unused5; - }; - --#if !defined(TARGET_RISCV64) -+#if !(defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64)) - #define TARGET_HAS_STRUCT_STAT64 - struct target_stat64 { - uint64_t st_dev; -@@ -2331,6 +2331,7 @@ struct target_statfs64 { - }; - #elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \ - defined(TARGET_SPARC64) || defined(TARGET_AARCH64) || \ -+ defined(TARGET_LOONGARCH64) || \ - defined(TARGET_RISCV)) && !defined(TARGET_ABI32) - struct target_statfs { - abi_long f_type; -diff --git a/meson.build b/meson.build -index 5f6ba86db..fc2dc58f3 100644 ---- a/meson.build -+++ b/meson.build -@@ -1814,6 +1814,7 @@ disassemblers = { - 'sh4' : ['CONFIG_SH4_DIS'], - 'sparc' : ['CONFIG_SPARC_DIS'], - 'xtensa' : ['CONFIG_XTENSA_DIS'], -+ 'loongarch64' : ['CONFIG_LOONGARCH_DIS'], - } - if link_language == 'cpp' - disassemblers += { -diff --git a/pc-bios/meson.build b/pc-bios/meson.build -index b40ff3f2b..a09ca4d03 100644 ---- a/pc-bios/meson.build -+++ b/pc-bios/meson.build -@@ -83,6 +83,7 @@ blobs = files( - 'opensbi-riscv32-generic-fw_dynamic.elf', - 'opensbi-riscv64-generic-fw_dynamic.elf', - 'npcm7xx_bootrom.bin', -+ 'loongarch_bios.bin', - ) - - if get_option('install_blobs') -diff --git a/qapi/machine-target.json b/qapi/machine-target.json -index f5ec4bc17..682dc86b4 100644 ---- a/qapi/machine-target.json -+++ b/qapi/machine-target.json -@@ -324,7 +324,8 @@ - 'TARGET_ARM', - 'TARGET_I386', - 'TARGET_S390X', -- 'TARGET_MIPS' ] } } -+ 'TARGET_MIPS', -+ 'TARGET_LOONGARCH64' ] } } - - ## - # @query-cpu-definitions: -@@ -340,4 +341,5 @@ - 'TARGET_ARM', - 'TARGET_I386', - 'TARGET_S390X', -- 'TARGET_MIPS' ] } } -+ 'TARGET_MIPS', -+ 'TARGET_LOONGARCH64' ] } } -diff --git a/qapi/machine.json b/qapi/machine.json -index a9f33d0f2..cd47b8d6b 100644 ---- a/qapi/machine.json -+++ b/qapi/machine.json -@@ -34,7 +34,7 @@ - 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', - 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', - 'sh4eb', 'sparc', 'sparc64', 'tricore', -- 'x86_64', 'xtensa', 'xtensaeb' ] } -+ 'x86_64', 'xtensa', 'xtensaeb', 'loongarch64' ] } - - ## - # @CpuS390State: -diff --git a/qapi/misc-target.json b/qapi/misc-target.json -index ede905244..2cf4fa418 100644 ---- a/qapi/misc-target.json -+++ b/qapi/misc-target.json -@@ -33,6 +33,7 @@ - 'TARGET_PPC64', - 'TARGET_S390X', - 'TARGET_SH4', -+ 'TARGET_LOONGARCH64', - 'TARGET_SPARC' ] } } - - ## --- -2.43.5 - diff --git a/0007-anolis-target-i386-csv-load-initial-image-to-private.patch b/0007-anolis-target-i386-csv-load-initial-image-to-private.patch deleted file mode 100644 index a40bcfed05f4b54e171af7e505ad1801ec4413c6..0000000000000000000000000000000000000000 --- a/0007-anolis-target-i386-csv-load-initial-image-to-private.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 2df9c321195bd47485867e1d821913f1f3c21fc2 Mon Sep 17 00:00:00 2001 -From: Xin Jiang -Date: Fri, 25 Aug 2023 14:51:16 +0800 -Subject: [PATCH 7/8] anolis: target/i386: csv: load initial image to private - memory - -The initial image of CSV guest should be loaded into private memory -before guest boot. - -Add APIs to implement the image load. - -Signed-off-by: Xin Jiang -Change-Id: I708e7521bfe079216c0e0aea619a9c6bb1d7af04 ---- - hw/i386/pc_sysfw.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c -index c8b17af953..84aad306dc 100644 ---- a/hw/i386/pc_sysfw.c -+++ b/hw/i386/pc_sysfw.c -@@ -38,6 +38,7 @@ - #include "hw/block/flash.h" - #include "sysemu/kvm.h" - #include "sev.h" -+#include "csv.h" - - #define FLASH_SECTOR_SIZE 4096 - -@@ -208,7 +209,10 @@ static void pc_system_flash_map(PCMachineState *pcms, - exit(1); - } - -- sev_encrypt_flash(flash_ptr, flash_size, &error_fatal); -+ if (csv_enabled()) -+ csv_load_data(flash_mem->addr, flash_ptr, flash_size, &error_fatal); -+ else -+ sev_encrypt_flash(flash_ptr, flash_size, &error_fatal); - } - } - } --- -2.17.1 - diff --git a/0008-Modify-compile-script.patch b/0008-Modify-compile-script.patch deleted file mode 100644 index bcf14ccab0a6fd7e6d84d2dd967bae16607360dc..0000000000000000000000000000000000000000 --- a/0008-Modify-compile-script.patch +++ /dev/null @@ -1,36 +0,0 @@ -From c46de76fc41792974d0e1c9896f89ab257cae345 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 22 Aug 2022 08:22:03 -0400 -Subject: [PATCH 08/28] Modify compile script. - -Change-Id: I8573477d64f5974092001869d7aa9bb093f347e8 -Signed-off-by: lixianglai ---- - meson.build | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/meson.build b/meson.build -index fc2dc58f3..c0fb5788f 100644 ---- a/meson.build -+++ b/meson.build -@@ -56,7 +56,7 @@ python = import('python').find_installation() - - supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] - supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64', -- 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64'] -+ 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64', 'loongarch64'] - - cpu = host_machine.cpu_family() - -@@ -77,6 +77,8 @@ elif cpu in ['ppc', 'ppc64'] - kvm_targets = ['ppc-softmmu', 'ppc64-softmmu'] - elif cpu in ['mips', 'mips64'] - kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu'] -+elif cpu == 'loongarch64' -+ kvm_targets = ['loongarch64-softmmu'] - else - kvm_targets = [] - endif --- -2.43.5 - diff --git a/0008-anolis-vga-force-full-update-for-CSV-guest.patch b/0008-anolis-vga-force-full-update-for-CSV-guest.patch deleted file mode 100644 index 40842ec7b5ebf2e728ba997fdc661f220e689b3e..0000000000000000000000000000000000000000 --- a/0008-anolis-vga-force-full-update-for-CSV-guest.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 42d8658a8868721a0c4fb08295a8957e9fdc96c6 Mon Sep 17 00:00:00 2001 -From: Xin Jiang -Date: Thu, 13 Jul 2023 09:35:10 +0800 -Subject: [PATCH 8/8] anolis: vga: force full update for CSV guest - -As CSV's NPT(nested page table) is managed by firmware, VMM is hard -to track the dirty pages of vga buffer. Although VMM could perform -a command to firmware to update read/write attribute of vga buffer -in NPT, it costs more time due to communication between VMM and -firmware. So the simplest method is to fully update vga buffer -always. - -Signed-off-by: Xin Jiang -Change-Id: I51ff00440483011fb9088a75005644beb378f8dd ---- - hw/display/vga.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/hw/display/vga.c b/hw/display/vga.c -index 9d1f66af40..be4282a2f5 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -36,6 +36,9 @@ - #include "migration/vmstate.h" - #include "trace.h" - -+#include "target/i386/sev.h" -+#include "target/i386/csv.h" -+ - //#define DEBUG_VGA_MEM - //#define DEBUG_VGA_REG - -@@ -1779,6 +1782,11 @@ static void vga_update_display(void *opaque) - s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); - full_update = 1; - } -+ -+ /* Force to full update in CSV guest. */ -+ if (csv_enabled()) -+ full_update = 1; -+ - switch(graphic_mode) { - case GMODE_TEXT: - vga_draw_text(s, full_update); --- -2.17.1 - diff --git a/0009-Add-loongarch64-rh-devices.mak.patch b/0009-Add-loongarch64-rh-devices.mak.patch deleted file mode 100644 index a06c1f067bca8236427fe6b668b02f1682242f52..0000000000000000000000000000000000000000 --- a/0009-Add-loongarch64-rh-devices.mak.patch +++ /dev/null @@ -1,3227 +0,0 @@ -From 89fb9c8e0ca11e311417981d46768642d1f8e6d2 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Wed, 24 Aug 2022 22:56:29 -0400 -Subject: [PATCH 09/28] Add loongarch64-rh-devices.mak. - -Change-Id: I375face82c0aa68c053254b879267830d6981756 -Signed-off-by: lixianglai ---- - .../loongarch64-rh-devices.mak | 155 ++ - configure | 5 + - meson.build | 2 + - pc-bios/meson.build | 1 + - tcg/loongarch64/tcg-insn-defs.c.inc | 979 +++++++++ - tcg/loongarch64/tcg-target-con-set.h | 31 + - tcg/loongarch64/tcg-target-con-str.h | 28 + - tcg/loongarch64/tcg-target.c.inc | 1744 +++++++++++++++++ - tcg/loongarch64/tcg-target.h | 178 ++ - 9 files changed, 3123 insertions(+) - create mode 100644 configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak - create mode 100644 tcg/loongarch64/tcg-insn-defs.c.inc - create mode 100644 tcg/loongarch64/tcg-target-con-set.h - create mode 100644 tcg/loongarch64/tcg-target-con-str.h - create mode 100644 tcg/loongarch64/tcg-target.c.inc - create mode 100644 tcg/loongarch64/tcg-target.h - -diff --git a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -new file mode 100644 -index 000000000..e7b5bdc8e ---- /dev/null -+++ b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -@@ -0,0 +1,155 @@ -+ -+include ../rh-virtio.mak -+# Default configuration for loongarch-softmmu -+ -+CONFIG_PCI=y -+CONFIG_ACPI_PCI=y -+# For now, CONFIG_IDE_CORE requires ISA, so we enable it here -+CONFIG_ISA_BUS=y -+CONFIG_VIRTIO_PCI=y -+ -+CONFIG_VGA_PCI=y -+CONFIG_ACPI_SMBUS=y -+#CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+CONFIG_VHOST_USER_SCSI=y -+#CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+CONFIG_VHOST_USER_BLK=y -+CONFIG_VIRTIO=y -+CONFIG_VIRTIO_BALLOON=y -+CONFIG_VIRTIO_BLK=y -+CONFIG_VIRTIO_CRYPTO=y -+CONFIG_VIRTIO_GPU=y -+CONFIG_VIRTIO_INPUT=y -+CONFIG_VIRTIO_NET=y -+CONFIG_VIRTIO_RNG=y -+CONFIG_SCSI=y -+CONFIG_VIRTIO_SCSI=y -+CONFIG_VIRTIO_SERIAL=y -+ -+CONFIG_USB_UHCI=y -+CONFIG_USB_OHCI=y -+CONFIG_USB_OHCI_PCI=y -+CONFIG_USB_XHCI=y -+CONFIG_USB_XHCI_NEC=y -+CONFIG_NE2000_PCI=y -+CONFIG_EEPRO100_PCI=y -+CONFIG_PCNET_PCI=y -+CONFIG_PCNET_COMMON=y -+CONFIG_AC97=y -+CONFIG_HDA=y -+CONFIG_ES1370=y -+CONFIG_SCSI=y -+CONFIG_LSI_SCSI_PCI=y -+CONFIG_VMW_PVSCSI_SCSI_PCI=y -+CONFIG_MEGASAS_SCSI_PCI=y -+CONFIG_MPTSAS_SCSI_PCI=y -+CONFIG_RTL8139_PCI=y -+CONFIG_E1000_PCI=y -+CONFIG_IDE_CORE=y -+CONFIG_IDE_QDEV=y -+CONFIG_IDE_PCI=y -+CONFIG_AHCI=y -+CONFIG_AHCI_ICH9=y -+CONFIG_ESP=y -+CONFIG_ESP_PCI=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_SERIAL_PCI=y -+CONFIG_CAN_BUS=y -+CONFIG_CAN_SJA1000=y -+CONFIG_CAN_PCI=y -+CONFIG_USB_UHCI=y -+CONFIG_USB_OHCI=y -+CONFIG_USB_XHCI=y -+CONFIG_USB_XHCI_NEC=y -+CONFIG_NE2000_PCI=y -+CONFIG_EEPRO100_PCI=y -+CONFIG_PCNET_PCI=y -+CONFIG_PCNET_COMMON=y -+CONFIG_AC97=y -+CONFIG_HDA=y -+CONFIG_ES1370=y -+CONFIG_SCSI=y -+CONFIG_LSI_SCSI_PCI=y -+CONFIG_VMW_PVSCSI_SCSI_PCI=y -+CONFIG_MEGASAS_SCSI_PCI=y -+CONFIG_MPTSAS_SCSI_PCI=y -+CONFIG_RTL8139_PCI=y -+CONFIG_E1000_PCI=y -+CONFIG_IDE_CORE=y -+CONFIG_IDE_QDEV=y -+CONFIG_IDE_PCI=y -+CONFIG_AHCI=y -+CONFIG_ESP=y -+CONFIG_ESP_PCI=y -+CONFIG_SERIAL=y -+CONFIG_SERIAL_ISA=y -+CONFIG_SERIAL_PCI=y -+CONFIG_CAN_BUS=y -+CONFIG_CAN_SJA1000=y -+CONFIG_CAN_PCI=y -+ -+CONFIG_SPICE=y -+CONFIG_QXL=y -+CONFIG_ESP=y -+CONFIG_SCSI=y -+CONFIG_VGA_ISA=y -+CONFIG_VGA_ISA_MM=y -+CONFIG_VGA_CIRRUS=y -+CONFIG_VMWARE_VGA=y -+CONFIG_VIRTIO_VGA=y -+CONFIG_SERIAL_ISA=y -+CONFIG_PARALLEL=y -+CONFIG_I8254=y -+CONFIG_PCSPK=y -+CONFIG_PCKBD=y -+CONFIG_FDC=y -+CONFIG_ACPI=y -+CONFIG_ACPI_MEMORY_HOTPLUG=y -+CONFIG_ACPI_NVDIMM=y -+CONFIG_ACPI_CPU_HOTPLUG=y -+CONFIG_APM=y -+CONFIG_I8257=y -+CONFIG_PIIX4=y -+CONFIG_IDE_ISA=y -+CONFIG_IDE_PIIX=y -+#CONFIG_NE2000_ISA=y -+CONFIG_MIPSNET=y -+CONFIG_PFLASH_CFI01=y -+CONFIG_I8259=y -+CONFIG_MC146818RTC=y -+CONFIG_ISA_TESTDEV=y -+CONFIG_EMPTY_SLOT=y -+CONFIG_I2C=y -+CONFIG_DIMM=y -+CONFIG_MEM_DEVICE=y -+ -+# Arch Specified CONFIG defines -+CONFIG_IDE_VIA=y -+CONFIG_VT82C686=y -+CONFIG_RC4030=y -+CONFIG_DP8393X=y -+CONFIG_DS1225Y=y -+CONFIG_FITLOADER=y -+CONFIG_SMBIOS=y -+ -+CONFIG_PCIE_PORT=y -+CONFIG_I82801B11=y -+CONFIG_XIO3130=y -+CONFIG_PCI_EXPRESS=y -+CONFIG_MSI_NONBROKEN=y -+CONFIG_IOH3420=y -+CONFIG_SD=y -+CONFIG_SDHCI=y -+CONFIG_VIRTFS=y -+CONFIG_VIRTIO_9P=y -+CONFIG_USB_EHCI=y -+CONFIG_USB_EHCI_PCI=y -+CONFIG_USB_EHCI_SYSBUS=y -+CONFIG_USB_STORAGE_BOT=y -+CONFIG_TPM_EMULATOR=y -+CONFIG_TPM_TIS=y -+CONFIG_PLATFORM_BUS=y -+CONFIG_TPM_TIS_SYSBUS=y -+CONFIG_ACPI_LOONGARCH=y -+CONFIG_LS7A_RTC=y -diff --git a/configure b/configure -index 48c21775f..1f932f7ee 100755 ---- a/configure -+++ b/configure -@@ -581,6 +581,8 @@ elif check_define __arm__ ; then - cpu="arm" - elif check_define __aarch64__ ; then - cpu="aarch64" -+elif check_define __loongarch__ ; then -+ cpu="loongarch64" - else - cpu=$(uname -m) - fi -@@ -606,6 +608,9 @@ case "$cpu" in - aarch64) - cpu="aarch64" - ;; -+ loongarch64) -+ cpu="loongarch64" -+ ;; - mips*) - cpu="mips" - ;; -diff --git a/meson.build b/meson.build -index c0fb5788f..c5fdb7856 100644 ---- a/meson.build -+++ b/meson.build -@@ -361,6 +361,8 @@ if not get_option('tcg').disabled() - tcg_arch = 'i386' - elif config_host['ARCH'] == 'ppc64' - tcg_arch = 'ppc' -+ elif config_host['ARCH'] == 'loongarch64' -+ tcg_arch = 'loongarch64' - endif - add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch, - language: ['c', 'cpp', 'objc']) -diff --git a/pc-bios/meson.build b/pc-bios/meson.build -index a09ca4d03..60009bd89 100644 ---- a/pc-bios/meson.build -+++ b/pc-bios/meson.build -@@ -84,6 +84,7 @@ blobs = files( - 'opensbi-riscv64-generic-fw_dynamic.elf', - 'npcm7xx_bootrom.bin', - 'loongarch_bios.bin', -+ 'loongarch_vars.bin', - ) - - if get_option('install_blobs') -diff --git a/tcg/loongarch64/tcg-insn-defs.c.inc b/tcg/loongarch64/tcg-insn-defs.c.inc -new file mode 100644 -index 000000000..d16257185 ---- /dev/null -+++ b/tcg/loongarch64/tcg-insn-defs.c.inc -@@ -0,0 +1,979 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * LoongArch instruction formats, opcodes, and encoders for TCG use. -+ * -+ * This file is auto-generated by genqemutcgdefs from -+ * https://github.com/loongson-community/loongarch-opcodes, -+ * from commit 961f0c60f5b63e574d785995600c71ad5413fdc4. -+ * DO NOT EDIT. -+ */ -+ -+typedef enum { -+ OPC_CLZ_W = 0x00001400, -+ OPC_CTZ_W = 0x00001c00, -+ OPC_CLZ_D = 0x00002400, -+ OPC_CTZ_D = 0x00002c00, -+ OPC_REVB_2H = 0x00003000, -+ OPC_REVB_2W = 0x00003800, -+ OPC_REVB_D = 0x00003c00, -+ OPC_SEXT_H = 0x00005800, -+ OPC_SEXT_B = 0x00005c00, -+ OPC_ADD_W = 0x00100000, -+ OPC_ADD_D = 0x00108000, -+ OPC_SUB_W = 0x00110000, -+ OPC_SUB_D = 0x00118000, -+ OPC_SLT = 0x00120000, -+ OPC_SLTU = 0x00128000, -+ OPC_MASKEQZ = 0x00130000, -+ OPC_MASKNEZ = 0x00138000, -+ OPC_NOR = 0x00140000, -+ OPC_AND = 0x00148000, -+ OPC_OR = 0x00150000, -+ OPC_XOR = 0x00158000, -+ OPC_ORN = 0x00160000, -+ OPC_ANDN = 0x00168000, -+ OPC_SLL_W = 0x00170000, -+ OPC_SRL_W = 0x00178000, -+ OPC_SRA_W = 0x00180000, -+ OPC_SLL_D = 0x00188000, -+ OPC_SRL_D = 0x00190000, -+ OPC_SRA_D = 0x00198000, -+ OPC_ROTR_W = 0x001b0000, -+ OPC_ROTR_D = 0x001b8000, -+ OPC_MUL_W = 0x001c0000, -+ OPC_MULH_W = 0x001c8000, -+ OPC_MULH_WU = 0x001d0000, -+ OPC_MUL_D = 0x001d8000, -+ OPC_MULH_D = 0x001e0000, -+ OPC_MULH_DU = 0x001e8000, -+ OPC_DIV_W = 0x00200000, -+ OPC_MOD_W = 0x00208000, -+ OPC_DIV_WU = 0x00210000, -+ OPC_MOD_WU = 0x00218000, -+ OPC_DIV_D = 0x00220000, -+ OPC_MOD_D = 0x00228000, -+ OPC_DIV_DU = 0x00230000, -+ OPC_MOD_DU = 0x00238000, -+ OPC_SLLI_W = 0x00408000, -+ OPC_SLLI_D = 0x00410000, -+ OPC_SRLI_W = 0x00448000, -+ OPC_SRLI_D = 0x00450000, -+ OPC_SRAI_W = 0x00488000, -+ OPC_SRAI_D = 0x00490000, -+ OPC_ROTRI_W = 0x004c8000, -+ OPC_ROTRI_D = 0x004d0000, -+ OPC_BSTRINS_W = 0x00600000, -+ OPC_BSTRPICK_W = 0x00608000, -+ OPC_BSTRINS_D = 0x00800000, -+ OPC_BSTRPICK_D = 0x00c00000, -+ OPC_SLTI = 0x02000000, -+ OPC_SLTUI = 0x02400000, -+ OPC_ADDI_W = 0x02800000, -+ OPC_ADDI_D = 0x02c00000, -+ OPC_CU52I_D = 0x03000000, -+ OPC_ANDI = 0x03400000, -+ OPC_ORI = 0x03800000, -+ OPC_XORI = 0x03c00000, -+ OPC_LU12I_W = 0x14000000, -+ OPC_CU32I_D = 0x16000000, -+ OPC_PCADDU2I = 0x18000000, -+ OPC_PCALAU12I = 0x1a000000, -+ OPC_PCADDU12I = 0x1c000000, -+ OPC_PCADDU18I = 0x1e000000, -+ OPC_LD_B = 0x28000000, -+ OPC_LD_H = 0x28400000, -+ OPC_LD_W = 0x28800000, -+ OPC_LD_D = 0x28c00000, -+ OPC_ST_B = 0x29000000, -+ OPC_ST_H = 0x29400000, -+ OPC_ST_W = 0x29800000, -+ OPC_ST_D = 0x29c00000, -+ OPC_LD_BU = 0x2a000000, -+ OPC_LD_HU = 0x2a400000, -+ OPC_LD_WU = 0x2a800000, -+ OPC_LDX_B = 0x38000000, -+ OPC_LDX_H = 0x38040000, -+ OPC_LDX_W = 0x38080000, -+ OPC_LDX_D = 0x380c0000, -+ OPC_STX_B = 0x38100000, -+ OPC_STX_H = 0x38140000, -+ OPC_STX_W = 0x38180000, -+ OPC_STX_D = 0x381c0000, -+ OPC_LDX_BU = 0x38200000, -+ OPC_LDX_HU = 0x38240000, -+ OPC_LDX_WU = 0x38280000, -+ OPC_DBAR = 0x38720000, -+ OPC_JIRL = 0x4c000000, -+ OPC_B = 0x50000000, -+ OPC_BL = 0x54000000, -+ OPC_BEQ = 0x58000000, -+ OPC_BNE = 0x5c000000, -+ OPC_BGT = 0x60000000, -+ OPC_BLE = 0x64000000, -+ OPC_BGTU = 0x68000000, -+ OPC_BLEU = 0x6c000000, -+} LoongArchInsn; -+ -+static int32_t __attribute__((unused)) -+encode_d_slot(LoongArchInsn opc, uint32_t d) -+{ -+ return opc | d; -+} -+ -+static int32_t __attribute__((unused)) -+encode_dj_slots(LoongArchInsn opc, uint32_t d, uint32_t j) -+{ -+ return opc | d | j << 5; -+} -+ -+static int32_t __attribute__((unused)) -+encode_djk_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k) -+{ -+ return opc | d | j << 5 | k << 10; -+} -+ -+static int32_t __attribute__((unused)) -+encode_djkm_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k, -+ uint32_t m) -+{ -+ return opc | d | j << 5 | k << 10 | m << 16; -+} -+ -+static int32_t __attribute__((unused)) -+encode_dk_slots(LoongArchInsn opc, uint32_t d, uint32_t k) -+{ -+ return opc | d | k << 10; -+} -+ -+static int32_t __attribute__((unused)) -+encode_dj_insn(LoongArchInsn opc, TCGReg d, TCGReg j) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ return encode_dj_slots(opc, d, j); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djk_insn(LoongArchInsn opc, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(k >= 0 && k <= 0x1f); -+ return encode_djk_slots(opc, d, j, k); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djsk12_insn(LoongArchInsn opc, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(sk12 >= -0x800 && sk12 <= 0x7ff); -+ return encode_djk_slots(opc, d, j, sk12 & 0xfff); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djsk16_insn(LoongArchInsn opc, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(sk16 >= -0x8000 && sk16 <= 0x7fff); -+ return encode_djk_slots(opc, d, j, sk16 & 0xffff); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk12_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk12) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk12 <= 0xfff); -+ return encode_djk_slots(opc, d, j, uk12); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk5_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk5 <= 0x1f); -+ return encode_djk_slots(opc, d, j, uk5); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk5um5_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk5, -+ uint32_t um5) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk5 <= 0x1f); -+ tcg_debug_assert(um5 <= 0x1f); -+ return encode_djkm_slots(opc, d, j, uk5, um5); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk6_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk6 <= 0x3f); -+ return encode_djk_slots(opc, d, j, uk6); -+} -+ -+static int32_t __attribute__((unused)) -+encode_djuk6um6_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk6, -+ uint32_t um6) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(j >= 0 && j <= 0x1f); -+ tcg_debug_assert(uk6 <= 0x3f); -+ tcg_debug_assert(um6 <= 0x3f); -+ return encode_djkm_slots(opc, d, j, uk6, um6); -+} -+ -+static int32_t __attribute__((unused)) -+encode_dsj20_insn(LoongArchInsn opc, TCGReg d, int32_t sj20) -+{ -+ tcg_debug_assert(d >= 0 && d <= 0x1f); -+ tcg_debug_assert(sj20 >= -0x80000 && sj20 <= 0x7ffff); -+ return encode_dj_slots(opc, d, sj20 & 0xfffff); -+} -+ -+static int32_t __attribute__((unused)) -+encode_sd10k16_insn(LoongArchInsn opc, int32_t sd10k16) -+{ -+ tcg_debug_assert(sd10k16 >= -0x2000000 && sd10k16 <= 0x1ffffff); -+ return encode_dk_slots(opc, (sd10k16 >> 16) & 0x3ff, sd10k16 & 0xffff); -+} -+ -+static int32_t __attribute__((unused)) -+encode_ud15_insn(LoongArchInsn opc, uint32_t ud15) -+{ -+ tcg_debug_assert(ud15 <= 0x7fff); -+ return encode_d_slot(opc, ud15); -+} -+ -+/* Emits the `clz.w d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_clz_w(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_CLZ_W, d, j)); -+} -+ -+/* Emits the `ctz.w d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ctz_w(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_CTZ_W, d, j)); -+} -+ -+/* Emits the `clz.d d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_clz_d(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_CLZ_D, d, j)); -+} -+ -+/* Emits the `ctz.d d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ctz_d(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_CTZ_D, d, j)); -+} -+ -+/* Emits the `revb.2h d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_revb_2h(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_REVB_2H, d, j)); -+} -+ -+/* Emits the `revb.2w d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_revb_2w(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_REVB_2W, d, j)); -+} -+ -+/* Emits the `revb.d d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_revb_d(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_REVB_D, d, j)); -+} -+ -+/* Emits the `sext.h d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sext_h(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_SEXT_H, d, j)); -+} -+ -+/* Emits the `sext.b d, j` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sext_b(TCGContext *s, TCGReg d, TCGReg j) -+{ -+ tcg_out32(s, encode_dj_insn(OPC_SEXT_B, d, j)); -+} -+ -+/* Emits the `add.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_add_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ADD_W, d, j, k)); -+} -+ -+/* Emits the `add.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_add_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ADD_D, d, j, k)); -+} -+ -+/* Emits the `sub.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sub_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SUB_W, d, j, k)); -+} -+ -+/* Emits the `sub.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sub_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SUB_D, d, j, k)); -+} -+ -+/* Emits the `slt d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_slt(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SLT, d, j, k)); -+} -+ -+/* Emits the `sltu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sltu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SLTU, d, j, k)); -+} -+ -+/* Emits the `maskeqz d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_maskeqz(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MASKEQZ, d, j, k)); -+} -+ -+/* Emits the `masknez d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_masknez(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MASKNEZ, d, j, k)); -+} -+ -+/* Emits the `nor d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_nor(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_NOR, d, j, k)); -+} -+ -+/* Emits the `and d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_and(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_AND, d, j, k)); -+} -+ -+/* Emits the `or d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_or(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_OR, d, j, k)); -+} -+ -+/* Emits the `xor d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_xor(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_XOR, d, j, k)); -+} -+ -+/* Emits the `orn d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_orn(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ORN, d, j, k)); -+} -+ -+/* Emits the `andn d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_andn(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ANDN, d, j, k)); -+} -+ -+/* Emits the `sll.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sll_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SLL_W, d, j, k)); -+} -+ -+/* Emits the `srl.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srl_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SRL_W, d, j, k)); -+} -+ -+/* Emits the `sra.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sra_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SRA_W, d, j, k)); -+} -+ -+/* Emits the `sll.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sll_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SLL_D, d, j, k)); -+} -+ -+/* Emits the `srl.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srl_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SRL_D, d, j, k)); -+} -+ -+/* Emits the `sra.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sra_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_SRA_D, d, j, k)); -+} -+ -+/* Emits the `rotr.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_rotr_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ROTR_W, d, j, k)); -+} -+ -+/* Emits the `rotr.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_rotr_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_ROTR_D, d, j, k)); -+} -+ -+/* Emits the `mul.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mul_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MUL_W, d, j, k)); -+} -+ -+/* Emits the `mulh.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mulh_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MULH_W, d, j, k)); -+} -+ -+/* Emits the `mulh.wu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mulh_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MULH_WU, d, j, k)); -+} -+ -+/* Emits the `mul.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mul_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MUL_D, d, j, k)); -+} -+ -+/* Emits the `mulh.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mulh_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MULH_D, d, j, k)); -+} -+ -+/* Emits the `mulh.du d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mulh_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MULH_DU, d, j, k)); -+} -+ -+/* Emits the `div.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_div_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_DIV_W, d, j, k)); -+} -+ -+/* Emits the `mod.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mod_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MOD_W, d, j, k)); -+} -+ -+/* Emits the `div.wu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_div_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_DIV_WU, d, j, k)); -+} -+ -+/* Emits the `mod.wu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mod_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MOD_WU, d, j, k)); -+} -+ -+/* Emits the `div.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_div_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_DIV_D, d, j, k)); -+} -+ -+/* Emits the `mod.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mod_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MOD_D, d, j, k)); -+} -+ -+/* Emits the `div.du d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_div_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_DIV_DU, d, j, k)); -+} -+ -+/* Emits the `mod.du d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_mod_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_MOD_DU, d, j, k)); -+} -+ -+/* Emits the `slli.w d, j, uk5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_slli_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_out32(s, encode_djuk5_insn(OPC_SLLI_W, d, j, uk5)); -+} -+ -+/* Emits the `slli.d d, j, uk6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_slli_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_out32(s, encode_djuk6_insn(OPC_SLLI_D, d, j, uk6)); -+} -+ -+/* Emits the `srli.w d, j, uk5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srli_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_out32(s, encode_djuk5_insn(OPC_SRLI_W, d, j, uk5)); -+} -+ -+/* Emits the `srli.d d, j, uk6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srli_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_out32(s, encode_djuk6_insn(OPC_SRLI_D, d, j, uk6)); -+} -+ -+/* Emits the `srai.w d, j, uk5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srai_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_out32(s, encode_djuk5_insn(OPC_SRAI_W, d, j, uk5)); -+} -+ -+/* Emits the `srai.d d, j, uk6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_srai_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_out32(s, encode_djuk6_insn(OPC_SRAI_D, d, j, uk6)); -+} -+ -+/* Emits the `rotri.w d, j, uk5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_rotri_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) -+{ -+ tcg_out32(s, encode_djuk5_insn(OPC_ROTRI_W, d, j, uk5)); -+} -+ -+/* Emits the `rotri.d d, j, uk6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_rotri_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) -+{ -+ tcg_out32(s, encode_djuk6_insn(OPC_ROTRI_D, d, j, uk6)); -+} -+ -+/* Emits the `bstrins.w d, j, uk5, um5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bstrins_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5, -+ uint32_t um5) -+{ -+ tcg_out32(s, encode_djuk5um5_insn(OPC_BSTRINS_W, d, j, uk5, um5)); -+} -+ -+/* Emits the `bstrpick.w d, j, uk5, um5` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bstrpick_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5, -+ uint32_t um5) -+{ -+ tcg_out32(s, encode_djuk5um5_insn(OPC_BSTRPICK_W, d, j, uk5, um5)); -+} -+ -+/* Emits the `bstrins.d d, j, uk6, um6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bstrins_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6, -+ uint32_t um6) -+{ -+ tcg_out32(s, encode_djuk6um6_insn(OPC_BSTRINS_D, d, j, uk6, um6)); -+} -+ -+/* Emits the `bstrpick.d d, j, uk6, um6` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bstrpick_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6, -+ uint32_t um6) -+{ -+ tcg_out32(s, encode_djuk6um6_insn(OPC_BSTRPICK_D, d, j, uk6, um6)); -+} -+ -+/* Emits the `slti d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_slti(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_SLTI, d, j, sk12)); -+} -+ -+/* Emits the `sltui d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_sltui(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_SLTUI, d, j, sk12)); -+} -+ -+/* Emits the `addi.w d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_addi_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ADDI_W, d, j, sk12)); -+} -+ -+/* Emits the `addi.d d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_addi_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ADDI_D, d, j, sk12)); -+} -+ -+/* Emits the `cu52i.d d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_cu52i_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_CU52I_D, d, j, sk12)); -+} -+ -+/* Emits the `andi d, j, uk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_andi(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) -+{ -+ tcg_out32(s, encode_djuk12_insn(OPC_ANDI, d, j, uk12)); -+} -+ -+/* Emits the `ori d, j, uk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ori(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) -+{ -+ tcg_out32(s, encode_djuk12_insn(OPC_ORI, d, j, uk12)); -+} -+ -+/* Emits the `xori d, j, uk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_xori(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) -+{ -+ tcg_out32(s, encode_djuk12_insn(OPC_XORI, d, j, uk12)); -+} -+ -+/* Emits the `lu12i.w d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_lu12i_w(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_LU12I_W, d, sj20)); -+} -+ -+/* Emits the `cu32i.d d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_cu32i_d(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_CU32I_D, d, sj20)); -+} -+ -+/* Emits the `pcaddu2i d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_pcaddu2i(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_PCADDU2I, d, sj20)); -+} -+ -+/* Emits the `pcalau12i d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_pcalau12i(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_PCALAU12I, d, sj20)); -+} -+ -+/* Emits the `pcaddu12i d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_pcaddu12i(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_PCADDU12I, d, sj20)); -+} -+ -+/* Emits the `pcaddu18i d, sj20` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_pcaddu18i(TCGContext *s, TCGReg d, int32_t sj20) -+{ -+ tcg_out32(s, encode_dsj20_insn(OPC_PCADDU18I, d, sj20)); -+} -+ -+/* Emits the `ld.b d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_b(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_B, d, j, sk12)); -+} -+ -+/* Emits the `ld.h d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_h(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_H, d, j, sk12)); -+} -+ -+/* Emits the `ld.w d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_W, d, j, sk12)); -+} -+ -+/* Emits the `ld.d d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_D, d, j, sk12)); -+} -+ -+/* Emits the `st.b d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_st_b(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ST_B, d, j, sk12)); -+} -+ -+/* Emits the `st.h d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_st_h(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ST_H, d, j, sk12)); -+} -+ -+/* Emits the `st.w d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_st_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ST_W, d, j, sk12)); -+} -+ -+/* Emits the `st.d d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_st_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_ST_D, d, j, sk12)); -+} -+ -+/* Emits the `ld.bu d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_bu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_BU, d, j, sk12)); -+} -+ -+/* Emits the `ld.hu d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_hu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_HU, d, j, sk12)); -+} -+ -+/* Emits the `ld.wu d, j, sk12` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ld_wu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) -+{ -+ tcg_out32(s, encode_djsk12_insn(OPC_LD_WU, d, j, sk12)); -+} -+ -+/* Emits the `ldx.b d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_b(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_B, d, j, k)); -+} -+ -+/* Emits the `ldx.h d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_h(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_H, d, j, k)); -+} -+ -+/* Emits the `ldx.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_W, d, j, k)); -+} -+ -+/* Emits the `ldx.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_D, d, j, k)); -+} -+ -+/* Emits the `stx.b d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_stx_b(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_STX_B, d, j, k)); -+} -+ -+/* Emits the `stx.h d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_stx_h(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_STX_H, d, j, k)); -+} -+ -+/* Emits the `stx.w d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_stx_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_STX_W, d, j, k)); -+} -+ -+/* Emits the `stx.d d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_stx_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_STX_D, d, j, k)); -+} -+ -+/* Emits the `ldx.bu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_bu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_BU, d, j, k)); -+} -+ -+/* Emits the `ldx.hu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_hu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_HU, d, j, k)); -+} -+ -+/* Emits the `ldx.wu d, j, k` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ldx_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) -+{ -+ tcg_out32(s, encode_djk_insn(OPC_LDX_WU, d, j, k)); -+} -+ -+/* Emits the `dbar ud15` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_dbar(TCGContext *s, uint32_t ud15) -+{ -+ tcg_out32(s, encode_ud15_insn(OPC_DBAR, ud15)); -+} -+ -+/* Emits the `jirl d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_jirl(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_JIRL, d, j, sk16)); -+} -+ -+/* Emits the `b sd10k16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_b(TCGContext *s, int32_t sd10k16) -+{ -+ tcg_out32(s, encode_sd10k16_insn(OPC_B, sd10k16)); -+} -+ -+/* Emits the `bl sd10k16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bl(TCGContext *s, int32_t sd10k16) -+{ -+ tcg_out32(s, encode_sd10k16_insn(OPC_BL, sd10k16)); -+} -+ -+/* Emits the `beq d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_beq(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BEQ, d, j, sk16)); -+} -+ -+/* Emits the `bne d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bne(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BNE, d, j, sk16)); -+} -+ -+/* Emits the `bgt d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bgt(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BGT, d, j, sk16)); -+} -+ -+/* Emits the `ble d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_ble(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BLE, d, j, sk16)); -+} -+ -+/* Emits the `bgtu d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bgtu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BGTU, d, j, sk16)); -+} -+ -+/* Emits the `bleu d, j, sk16` instruction. */ -+static void __attribute__((unused)) -+tcg_out_opc_bleu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) -+{ -+ tcg_out32(s, encode_djsk16_insn(OPC_BLEU, d, j, sk16)); -+} -+ -+/* End of generated code. */ -diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h -new file mode 100644 -index 000000000..349c67268 ---- /dev/null -+++ b/tcg/loongarch64/tcg-target-con-set.h -@@ -0,0 +1,31 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * Define LoongArch target-specific constraint sets. -+ * -+ * Copyright (c) 2021 WANG Xuerui -+ * -+ * Based on tcg/riscv/tcg-target-con-set.h -+ * -+ * Copyright (c) 2021 Linaro -+ */ -+ -+/* -+ * C_On_Im(...) defines a constraint set with outputs and inputs. -+ * Each operand should be a sequence of constraint letters as defined by -+ * tcg-target-con-str.h; the constraint combination is inclusive or. -+ */ -+C_O0_I1(r) -+C_O0_I2(rZ, r) -+C_O0_I2(rZ, rZ) -+C_O0_I2(LZ, L) -+C_O1_I1(r, r) -+C_O1_I1(r, L) -+C_O1_I2(r, r, rC) -+C_O1_I2(r, r, ri) -+C_O1_I2(r, r, rI) -+C_O1_I2(r, r, rU) -+C_O1_I2(r, r, rW) -+C_O1_I2(r, r, rZ) -+C_O1_I2(r, 0, rZ) -+C_O1_I2(r, rZ, rN) -+C_O1_I2(r, rZ, rZ) -diff --git a/tcg/loongarch64/tcg-target-con-str.h b/tcg/loongarch64/tcg-target-con-str.h -new file mode 100644 -index 000000000..c3986a4fd ---- /dev/null -+++ b/tcg/loongarch64/tcg-target-con-str.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * Define LoongArch target-specific operand constraints. -+ * -+ * Copyright (c) 2021 WANG Xuerui -+ * -+ * Based on tcg/riscv/tcg-target-con-str.h -+ * -+ * Copyright (c) 2021 Linaro -+ */ -+ -+/* -+ * Define constraint letters for register sets: -+ * REGS(letter, register_mask) -+ */ -+REGS('r', ALL_GENERAL_REGS) -+REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) -+ -+/* -+ * Define constraint letters for constants: -+ * CONST(letter, TCG_CT_CONST_* bit set) -+ */ -+CONST('I', TCG_CT_CONST_S12) -+CONST('N', TCG_CT_CONST_N12) -+CONST('U', TCG_CT_CONST_U12) -+CONST('Z', TCG_CT_CONST_ZERO) -+CONST('C', TCG_CT_CONST_C12) -+CONST('W', TCG_CT_CONST_WSZ) -diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc -new file mode 100644 -index 000000000..9b53549ed ---- /dev/null -+++ b/tcg/loongarch64/tcg-target.c.inc -@@ -0,0 +1,1744 @@ -+/* -+ * Tiny Code Generator for QEMU -+ * -+ * Copyright (c) 2021 WANG Xuerui -+ * -+ * Based on tcg/riscv/tcg-target.c.inc -+ * -+ * Copyright (c) 2018 SiFive, Inc -+ * Copyright (c) 2008-2009 Arnaud Patard -+ * Copyright (c) 2009 Aurelien Jarno -+ * Copyright (c) 2008 Fabrice Bellard -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "../tcg-ldst.c.inc" -+ -+#ifdef CONFIG_DEBUG_TCG -+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { -+ "zero", -+ "ra", -+ "tp", -+ "sp", -+ "a0", -+ "a1", -+ "a2", -+ "a3", -+ "a4", -+ "a5", -+ "a6", -+ "a7", -+ "t0", -+ "t1", -+ "t2", -+ "t3", -+ "t4", -+ "t5", -+ "t6", -+ "t7", -+ "t8", -+ "r21", /* reserved in the LP64* ABI, hence no ABI name */ -+ "s9", -+ "s0", -+ "s1", -+ "s2", -+ "s3", -+ "s4", -+ "s5", -+ "s6", -+ "s7", -+ "s8" -+}; -+#endif -+ -+static const int tcg_target_reg_alloc_order[] = { -+ /* Registers preserved across calls */ -+ /* TCG_REG_S0 reserved for TCG_AREG0 */ -+ TCG_REG_S1, -+ TCG_REG_S2, -+ TCG_REG_S3, -+ TCG_REG_S4, -+ TCG_REG_S5, -+ TCG_REG_S6, -+ TCG_REG_S7, -+ TCG_REG_S8, -+ TCG_REG_S9, -+ -+ /* Registers (potentially) clobbered across calls */ -+ TCG_REG_T0, -+ TCG_REG_T1, -+ TCG_REG_T2, -+ TCG_REG_T3, -+ TCG_REG_T4, -+ TCG_REG_T5, -+ TCG_REG_T6, -+ TCG_REG_T7, -+ TCG_REG_T8, -+ -+ /* Argument registers, opposite order of allocation. */ -+ TCG_REG_A7, -+ TCG_REG_A6, -+ TCG_REG_A5, -+ TCG_REG_A4, -+ TCG_REG_A3, -+ TCG_REG_A2, -+ TCG_REG_A1, -+ TCG_REG_A0, -+}; -+ -+static const int tcg_target_call_iarg_regs[] = { -+ TCG_REG_A0, -+ TCG_REG_A1, -+ TCG_REG_A2, -+ TCG_REG_A3, -+ TCG_REG_A4, -+ TCG_REG_A5, -+ TCG_REG_A6, -+ TCG_REG_A7, -+}; -+ -+static const int tcg_target_call_oarg_regs[] = { -+ TCG_REG_A0, -+ TCG_REG_A1, -+}; -+ -+#ifndef CONFIG_SOFTMMU -+#define USE_GUEST_BASE (guest_base != 0) -+#define TCG_GUEST_BASE_REG TCG_REG_S1 -+#endif -+ -+#define TCG_CT_CONST_ZERO 0x100 -+#define TCG_CT_CONST_S12 0x200 -+#define TCG_CT_CONST_N12 0x400 -+#define TCG_CT_CONST_U12 0x800 -+#define TCG_CT_CONST_C12 0x1000 -+#define TCG_CT_CONST_WSZ 0x2000 -+ -+#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32) -+/* -+ * For softmmu, we need to avoid conflicts with the first 5 -+ * argument registers to call the helper. Some of these are -+ * also used for the tlb lookup. -+ */ -+#ifdef CONFIG_SOFTMMU -+#define SOFTMMU_RESERVE_REGS MAKE_64BIT_MASK(TCG_REG_A0, 5) -+#else -+#define SOFTMMU_RESERVE_REGS 0 -+#endif -+ -+ -+static inline tcg_target_long sextreg(tcg_target_long val, int pos, int len) -+{ -+ return sextract64(val, pos, len); -+} -+ -+/* test if a constant matches the constraint */ -+static bool tcg_target_const_match(int64_t val, TCGType type, int ct) -+{ -+ if (ct & TCG_CT_CONST) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_ZERO) && val == 0) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_S12) && val == sextreg(val, 0, 12)) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_N12) && -val == sextreg(-val, 0, 12)) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_U12) && val >= 0 && val <= 0xfff) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_C12) && ~val >= 0 && ~val <= 0xfff) { -+ return true; -+ } -+ if ((ct & TCG_CT_CONST_WSZ) && val == (type == TCG_TYPE_I32 ? 32 : 64)) { -+ return true; -+ } -+ return false; -+} -+ -+/* -+ * Relocations -+ */ -+ -+/* -+ * Relocation records defined in LoongArch ELF psABI v1.00 is way too -+ * complicated; a whopping stack machine is needed to stuff the fields, at -+ * the very least one SOP_PUSH and one SOP_POP (of the correct format) are -+ * needed. -+ * -+ * Hence, define our own simpler relocation types. Numbers are chosen as to -+ * not collide with potential future additions to the true ELF relocation -+ * type enum. -+ */ -+ -+/* Field Sk16, shifted right by 2; suitable for conditional jumps */ -+#define R_LOONGARCH_BR_SK16 256 -+/* Field Sd10k16, shifted right by 2; suitable for B and BL */ -+#define R_LOONGARCH_BR_SD10K16 257 -+ -+static bool reloc_br_sk16(tcg_insn_unit *src_rw, const tcg_insn_unit *target) -+{ -+ const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); -+ intptr_t offset = (intptr_t)target - (intptr_t)src_rx; -+ -+ tcg_debug_assert((offset & 3) == 0); -+ offset >>= 2; -+ if (offset == sextreg(offset, 0, 16)) { -+ *src_rw = deposit64(*src_rw, 10, 16, offset); -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool reloc_br_sd10k16(tcg_insn_unit *src_rw, -+ const tcg_insn_unit *target) -+{ -+ const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); -+ intptr_t offset = (intptr_t)target - (intptr_t)src_rx; -+ -+ tcg_debug_assert((offset & 3) == 0); -+ offset >>= 2; -+ if (offset == sextreg(offset, 0, 26)) { -+ *src_rw = deposit64(*src_rw, 0, 10, offset >> 16); /* slot d10 */ -+ *src_rw = deposit64(*src_rw, 10, 16, offset); /* slot k16 */ -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool patch_reloc(tcg_insn_unit *code_ptr, int type, -+ intptr_t value, intptr_t addend) -+{ -+ tcg_debug_assert(addend == 0); -+ switch (type) { -+ case R_LOONGARCH_BR_SK16: -+ return reloc_br_sk16(code_ptr, (tcg_insn_unit *)value); -+ case R_LOONGARCH_BR_SD10K16: -+ return reloc_br_sd10k16(code_ptr, (tcg_insn_unit *)value); -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+#include "tcg-insn-defs.c.inc" -+ -+/* -+ * TCG intrinsics -+ */ -+ -+static void tcg_out_mb(TCGContext *s, TCGArg a0) -+{ -+ /* Baseline LoongArch only has the full barrier, unfortunately. */ -+ tcg_out_opc_dbar(s, 0); -+} -+ -+static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) -+{ -+ if (ret == arg) { -+ return true; -+ } -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ /* -+ * Conventional register-register move used in LoongArch is -+ * `or dst, src, zero`. -+ */ -+ tcg_out_opc_or(s, ret, arg, TCG_REG_ZERO); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ return true; -+} -+ -+static bool imm_part_needs_loading(bool high_bits_are_ones, -+ tcg_target_long part) -+{ -+ if (high_bits_are_ones) { -+ return part != -1; -+ } else { -+ return part != 0; -+ } -+} -+ -+/* Loads a 32-bit immediate into rd, sign-extended. */ -+static void tcg_out_movi_i32(TCGContext *s, TCGReg rd, int32_t val) -+{ -+ tcg_target_long lo = sextreg(val, 0, 12); -+ tcg_target_long hi12 = sextreg(val, 12, 20); -+ -+ /* Single-instruction cases. */ -+ if (lo == val) { -+ /* val fits in simm12: addi.w rd, zero, val */ -+ tcg_out_opc_addi_w(s, rd, TCG_REG_ZERO, val); -+ return; -+ } -+ if (0x800 <= val && val <= 0xfff) { -+ /* val fits in uimm12: ori rd, zero, val */ -+ tcg_out_opc_ori(s, rd, TCG_REG_ZERO, val); -+ return; -+ } -+ -+ /* High bits must be set; load with lu12i.w + optional ori. */ -+ tcg_out_opc_lu12i_w(s, rd, hi12); -+ if (lo != 0) { -+ tcg_out_opc_ori(s, rd, rd, lo & 0xfff); -+ } -+} -+ -+static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, -+ tcg_target_long val) -+{ -+ /* -+ * LoongArch conventionally loads 64-bit immediates in at most 4 steps, -+ * with dedicated instructions for filling the respective bitfields -+ * below: -+ * -+ * 6 5 4 3 -+ * 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 -+ * +-----------------------+---------------------------------------+... -+ * | hi52 | hi32 | -+ * +-----------------------+---------------------------------------+... -+ * 3 2 1 -+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 -+ * ...+-------------------------------------+-------------------------+ -+ * | hi12 | lo | -+ * ...+-------------------------------------+-------------------------+ -+ * -+ * Check if val belong to one of the several fast cases, before falling -+ * back to the slow path. -+ */ -+ -+ intptr_t pc_offset; -+ tcg_target_long val_lo, val_hi, pc_hi, offset_hi; -+ tcg_target_long hi32, hi52; -+ bool rd_high_bits_are_ones; -+ -+ /* Value fits in signed i32. */ -+ if (type == TCG_TYPE_I32 || val == (int32_t)val) { -+ tcg_out_movi_i32(s, rd, val); -+ return; -+ } -+ -+ /* PC-relative cases. */ -+ pc_offset = tcg_pcrel_diff(s, (void *)val); -+ if (pc_offset == sextreg(pc_offset, 0, 22) && (pc_offset & 3) == 0) { -+ /* Single pcaddu2i. */ -+ tcg_out_opc_pcaddu2i(s, rd, pc_offset >> 2); -+ return; -+ } -+ -+ if (pc_offset == (int32_t)pc_offset) { -+ /* Offset within 32 bits; load with pcalau12i + ori. */ -+ val_lo = sextreg(val, 0, 12); -+ val_hi = val >> 12; -+ pc_hi = (val - pc_offset) >> 12; -+ offset_hi = val_hi - pc_hi; -+ -+ tcg_debug_assert(offset_hi == sextreg(offset_hi, 0, 20)); -+ tcg_out_opc_pcalau12i(s, rd, offset_hi); -+ if (val_lo != 0) { -+ tcg_out_opc_ori(s, rd, rd, val_lo & 0xfff); -+ } -+ return; -+ } -+ -+ hi32 = sextreg(val, 32, 20); -+ hi52 = sextreg(val, 52, 12); -+ -+ /* Single cu52i.d case. */ -+ if (ctz64(val) >= 52) { -+ tcg_out_opc_cu52i_d(s, rd, TCG_REG_ZERO, hi52); -+ return; -+ } -+ -+ /* Slow path. Initialize the low 32 bits, then concat high bits. */ -+ tcg_out_movi_i32(s, rd, val); -+ rd_high_bits_are_ones = (int32_t)val < 0; -+ -+ if (imm_part_needs_loading(rd_high_bits_are_ones, hi32)) { -+ tcg_out_opc_cu32i_d(s, rd, hi32); -+ rd_high_bits_are_ones = hi32 < 0; -+ } -+ -+ if (imm_part_needs_loading(rd_high_bits_are_ones, hi52)) { -+ tcg_out_opc_cu52i_d(s, rd, rd, hi52); -+ } -+} -+ -+static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_andi(s, ret, arg, 0xff); -+} -+ -+static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_bstrpick_w(s, ret, arg, 0, 15); -+} -+ -+static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_bstrpick_d(s, ret, arg, 0, 31); -+} -+ -+static void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_sext_b(s, ret, arg); -+} -+ -+static void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_sext_h(s, ret, arg); -+} -+ -+static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_addi_w(s, ret, arg, 0); -+} -+ -+static void tcg_out_clzctz(TCGContext *s, LoongArchInsn opc, -+ TCGReg a0, TCGReg a1, TCGReg a2, -+ bool c2, bool is_32bit) -+{ -+ if (c2) { -+ /* -+ * Fast path: semantics already satisfied due to constraint and -+ * insn behavior, single instruction is enough. -+ */ -+ tcg_debug_assert(a2 == (is_32bit ? 32 : 64)); -+ /* all clz/ctz insns belong to DJ-format */ -+ tcg_out32(s, encode_dj_insn(opc, a0, a1)); -+ return; -+ } -+ -+ tcg_out32(s, encode_dj_insn(opc, TCG_REG_TMP0, a1)); -+ /* a0 = a1 ? REG_TMP0 : a2 */ -+ tcg_out_opc_maskeqz(s, TCG_REG_TMP0, TCG_REG_TMP0, a1); -+ tcg_out_opc_masknez(s, a0, a2, a1); -+ tcg_out_opc_or(s, a0, TCG_REG_TMP0, a0); -+} -+ -+static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, -+ TCGReg arg1, TCGReg arg2, bool c2) -+{ -+ TCGReg tmp; -+ -+ if (c2) { -+ tcg_debug_assert(arg2 == 0); -+ } -+ -+ switch (cond) { -+ case TCG_COND_EQ: -+ if (c2) { -+ tmp = arg1; -+ } else { -+ tcg_out_opc_sub_d(s, ret, arg1, arg2); -+ tmp = ret; -+ } -+ tcg_out_opc_sltui(s, ret, tmp, 1); -+ break; -+ case TCG_COND_NE: -+ if (c2) { -+ tmp = arg1; -+ } else { -+ tcg_out_opc_sub_d(s, ret, arg1, arg2); -+ tmp = ret; -+ } -+ tcg_out_opc_sltu(s, ret, TCG_REG_ZERO, tmp); -+ break; -+ case TCG_COND_LT: -+ tcg_out_opc_slt(s, ret, arg1, arg2); -+ break; -+ case TCG_COND_GE: -+ tcg_out_opc_slt(s, ret, arg1, arg2); -+ tcg_out_opc_xori(s, ret, ret, 1); -+ break; -+ case TCG_COND_LE: -+ tcg_out_setcond(s, TCG_COND_GE, ret, arg2, arg1, false); -+ break; -+ case TCG_COND_GT: -+ tcg_out_setcond(s, TCG_COND_LT, ret, arg2, arg1, false); -+ break; -+ case TCG_COND_LTU: -+ tcg_out_opc_sltu(s, ret, arg1, arg2); -+ break; -+ case TCG_COND_GEU: -+ tcg_out_opc_sltu(s, ret, arg1, arg2); -+ tcg_out_opc_xori(s, ret, ret, 1); -+ break; -+ case TCG_COND_LEU: -+ tcg_out_setcond(s, TCG_COND_GEU, ret, arg2, arg1, false); -+ break; -+ case TCG_COND_GTU: -+ tcg_out_setcond(s, TCG_COND_LTU, ret, arg2, arg1, false); -+ break; -+ default: -+ g_assert_not_reached(); -+ break; -+ } -+} -+ -+/* -+ * Branch helpers -+ */ -+ -+static const struct { -+ LoongArchInsn op; -+ bool swap; -+} tcg_brcond_to_loongarch[] = { -+ [TCG_COND_EQ] = { OPC_BEQ, false }, -+ [TCG_COND_NE] = { OPC_BNE, false }, -+ [TCG_COND_LT] = { OPC_BGT, true }, -+ [TCG_COND_GE] = { OPC_BLE, true }, -+ [TCG_COND_LE] = { OPC_BLE, false }, -+ [TCG_COND_GT] = { OPC_BGT, false }, -+ [TCG_COND_LTU] = { OPC_BGTU, true }, -+ [TCG_COND_GEU] = { OPC_BLEU, true }, -+ [TCG_COND_LEU] = { OPC_BLEU, false }, -+ [TCG_COND_GTU] = { OPC_BGTU, false } -+}; -+ -+static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, -+ TCGReg arg2, TCGLabel *l) -+{ -+ LoongArchInsn op = tcg_brcond_to_loongarch[cond].op; -+ -+ tcg_debug_assert(op != 0); -+ -+ if (tcg_brcond_to_loongarch[cond].swap) { -+ TCGReg t = arg1; -+ arg1 = arg2; -+ arg2 = t; -+ } -+ -+ /* all conditional branch insns belong to DJSk16-format */ -+ tcg_out_reloc(s, s->code_ptr, R_LOONGARCH_BR_SK16, l, 0); -+ tcg_out32(s, encode_djsk16_insn(op, arg1, arg2, 0)); -+} -+ -+static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) -+{ -+ TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA; -+ ptrdiff_t offset = tcg_pcrel_diff(s, arg); -+ -+ tcg_debug_assert((offset & 3) == 0); -+ if (offset == sextreg(offset, 0, 28)) { -+ /* short jump: +/- 256MiB */ -+ if (tail) { -+ tcg_out_opc_b(s, offset >> 2); -+ } else { -+ tcg_out_opc_bl(s, offset >> 2); -+ } -+ } else if (offset == sextreg(offset, 0, 38)) { -+ /* long jump: +/- 256GiB */ -+ tcg_target_long lo = sextreg(offset, 0, 18); -+ tcg_target_long hi = offset - lo; -+ tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, hi >> 18); -+ tcg_out_opc_jirl(s, link, TCG_REG_TMP0, lo >> 2); -+ } else { -+ /* far jump: 64-bit */ -+ tcg_target_long lo = sextreg((tcg_target_long)arg, 0, 18); -+ tcg_target_long hi = (tcg_target_long)arg - lo; -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, hi); -+ tcg_out_opc_jirl(s, link, TCG_REG_TMP0, lo >> 2); -+ } -+} -+ -+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg) -+{ -+ tcg_out_call_int(s, arg, false); -+} -+ -+/* -+ * Load/store helpers -+ */ -+ -+static void tcg_out_ldst(TCGContext *s, LoongArchInsn opc, TCGReg data, -+ TCGReg addr, intptr_t offset) -+{ -+ intptr_t imm12 = sextreg(offset, 0, 12); -+ -+ if (offset != imm12) { -+ intptr_t diff = offset - (uintptr_t)s->code_ptr; -+ -+ if (addr == TCG_REG_ZERO && diff == (int32_t)diff) { -+ imm12 = sextreg(diff, 0, 12); -+ tcg_out_opc_pcaddu12i(s, TCG_REG_TMP2, (diff - imm12) >> 12); -+ } else { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP2, offset - imm12); -+ if (addr != TCG_REG_ZERO) { -+ tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, addr); -+ } -+ } -+ addr = TCG_REG_TMP2; -+ } -+ -+ switch (opc) { -+ case OPC_LD_B: -+ case OPC_LD_BU: -+ case OPC_LD_H: -+ case OPC_LD_HU: -+ case OPC_LD_W: -+ case OPC_LD_WU: -+ case OPC_LD_D: -+ case OPC_ST_B: -+ case OPC_ST_H: -+ case OPC_ST_W: -+ case OPC_ST_D: -+ tcg_out32(s, encode_djsk12_insn(opc, data, addr, imm12)); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg, -+ TCGReg arg1, intptr_t arg2) -+{ -+ bool is_32bit = type == TCG_TYPE_I32; -+ tcg_out_ldst(s, is_32bit ? OPC_LD_W : OPC_LD_D, arg, arg1, arg2); -+} -+ -+static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, -+ TCGReg arg1, intptr_t arg2) -+{ -+ bool is_32bit = type == TCG_TYPE_I32; -+ tcg_out_ldst(s, is_32bit ? OPC_ST_W : OPC_ST_D, arg, arg1, arg2); -+} -+ -+static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, -+ TCGReg base, intptr_t ofs) -+{ -+ if (val == 0) { -+ tcg_out_st(s, type, TCG_REG_ZERO, base, ofs); -+ return true; -+ } -+ return false; -+} -+ -+/* -+ * Load/store helpers for SoftMMU, and qemu_ld/st implementations -+ */ -+ -+#if defined(CONFIG_SOFTMMU) -+/* -+ * helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, -+ * MemOpIdx oi, uintptr_t ra) -+ */ -+static void * const qemu_ld_helpers[4] = { -+ [MO_8] = helper_ret_ldub_mmu, -+ [MO_16] = helper_le_lduw_mmu, -+ [MO_32] = helper_le_ldul_mmu, -+ [MO_64] = helper_le_ldq_mmu, -+}; -+ -+/* -+ * helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr, -+ * uintxx_t val, MemOpIdx oi, -+ * uintptr_t ra) -+ */ -+static void * const qemu_st_helpers[4] = { -+ [MO_8] = helper_ret_stb_mmu, -+ [MO_16] = helper_le_stw_mmu, -+ [MO_32] = helper_le_stl_mmu, -+ [MO_64] = helper_le_stq_mmu, -+}; -+ -+/* We expect to use a 12-bit negative offset from ENV. */ -+QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0); -+QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 11)); -+ -+static bool tcg_out_goto(TCGContext *s, const tcg_insn_unit *target) -+{ -+ tcg_out_opc_b(s, 0); -+ return reloc_br_sd10k16(s->code_ptr - 1, target); -+} -+ -+/* -+ * Emits common code for TLB addend lookup, that eventually loads the -+ * addend in TCG_REG_TMP2. -+ */ -+static void tcg_out_tlb_load(TCGContext *s, TCGReg addrl, MemOpIdx oi, -+ tcg_insn_unit **label_ptr, bool is_load) -+{ -+ MemOp opc = get_memop(oi); -+ unsigned s_bits = opc & MO_SIZE; -+ unsigned a_bits = get_alignment_bits(opc); -+ tcg_target_long compare_mask; -+ int mem_index = get_mmuidx(oi); -+ int fast_ofs = TLB_MASK_TABLE_OFS(mem_index); -+ int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask); -+ int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table); -+ -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_AREG0, mask_ofs); -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs); -+ -+ tcg_out_opc_srli_d(s, TCG_REG_TMP2, addrl, -+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); -+ tcg_out_opc_and(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0); -+ tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1); -+ -+ /* Load the tlb comparator and the addend. */ -+ tcg_out_ld(s, TCG_TYPE_TL, TCG_REG_TMP0, TCG_REG_TMP2, -+ is_load ? offsetof(CPUTLBEntry, addr_read) -+ : offsetof(CPUTLBEntry, addr_write)); -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_REG_TMP2, -+ offsetof(CPUTLBEntry, addend)); -+ -+ /* We don't support unaligned accesses. */ -+ if (a_bits < s_bits) { -+ a_bits = s_bits; -+ } -+ /* Clear the non-page, non-alignment bits from the address. */ -+ compare_mask = (tcg_target_long)TARGET_PAGE_MASK | ((1 << a_bits) - 1); -+ tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_TMP1, compare_mask); -+ tcg_out_opc_and(s, TCG_REG_TMP1, TCG_REG_TMP1, addrl); -+ -+ /* Compare masked address with the TLB entry. */ -+ label_ptr[0] = s->code_ptr; -+ tcg_out_opc_bne(s, TCG_REG_TMP0, TCG_REG_TMP1, 0); -+ -+ /* TLB Hit - addend in TCG_REG_TMP2, ready for use. */ -+} -+ -+static void add_qemu_ldst_label(TCGContext *s, int is_ld, MemOpIdx oi, -+ TCGType type, -+ TCGReg datalo, TCGReg addrlo, -+ void *raddr, tcg_insn_unit **label_ptr) -+{ -+ TCGLabelQemuLdst *label = new_ldst_label(s); -+ -+ label->is_ld = is_ld; -+ label->oi = oi; -+ label->type = type; -+ label->datalo_reg = datalo; -+ label->datahi_reg = 0; /* unused */ -+ label->addrlo_reg = addrlo; -+ label->addrhi_reg = 0; /* unused */ -+ label->raddr = tcg_splitwx_to_rx(raddr); -+ label->label_ptr[0] = label_ptr[0]; -+} -+ -+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ MemOpIdx oi = l->oi; -+ MemOp opc = get_memop(oi); -+ MemOp size = opc & MO_SIZE; -+ TCGType type = l->type; -+ -+ /* resolve label address */ -+ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { -+ return false; -+ } -+ -+ /* call load helper */ -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0); -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A1, l->addrlo_reg); -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A2, oi); -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, (tcg_target_long)l->raddr); -+ -+ tcg_out_call(s, qemu_ld_helpers[size]); -+ -+ switch (opc & MO_SSIZE) { -+ case MO_SB: -+ tcg_out_ext8s(s, l->datalo_reg, TCG_REG_A0); -+ break; -+ case MO_SW: -+ tcg_out_ext16s(s, l->datalo_reg, TCG_REG_A0); -+ break; -+ case MO_SL: -+ tcg_out_ext32s(s, l->datalo_reg, TCG_REG_A0); -+ break; -+ case MO_UL: -+ if (type == TCG_TYPE_I32) { -+ /* MO_UL loads of i32 should be sign-extended too */ -+ tcg_out_ext32s(s, l->datalo_reg, TCG_REG_A0); -+ break; -+ } -+ /* fallthrough */ -+ default: -+ tcg_out_mov(s, type, l->datalo_reg, TCG_REG_A0); -+ break; -+ } -+ -+ return tcg_out_goto(s, l->raddr); -+} -+ -+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ MemOpIdx oi = l->oi; -+ MemOp opc = get_memop(oi); -+ MemOp size = opc & MO_SIZE; -+ -+ /* resolve label address */ -+ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { -+ return false; -+ } -+ -+ /* call store helper */ -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0); -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A1, l->addrlo_reg); -+ switch (size) { -+ case MO_8: -+ tcg_out_ext8u(s, TCG_REG_A2, l->datalo_reg); -+ break; -+ case MO_16: -+ tcg_out_ext16u(s, TCG_REG_A2, l->datalo_reg); -+ break; -+ case MO_32: -+ tcg_out_ext32u(s, TCG_REG_A2, l->datalo_reg); -+ break; -+ case MO_64: -+ tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_A2, l->datalo_reg); -+ break; -+ default: -+ g_assert_not_reached(); -+ break; -+ } -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A3, oi); -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A4, (tcg_target_long)l->raddr); -+ -+ tcg_out_call(s, qemu_st_helpers[size]); -+ -+ return tcg_out_goto(s, l->raddr); -+} -+#else -+ -+/* -+ * Alignment helpers for user-mode emulation -+ */ -+ -+static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addr_reg, -+ unsigned a_bits) -+{ -+ TCGLabelQemuLdst *l = new_ldst_label(s); -+ -+ l->is_ld = is_ld; -+ l->addrlo_reg = addr_reg; -+ -+ /* -+ * Without micro-architecture details, we don't know which of bstrpick or -+ * andi is faster, so use bstrpick as it's not constrained by imm field -+ * width. (Not to say alignments >= 2^12 are going to happen any time -+ * soon, though) -+ */ -+ tcg_out_opc_bstrpick_d(s, TCG_REG_TMP1, addr_reg, 0, a_bits - 1); -+ -+ l->label_ptr[0] = s->code_ptr; -+ tcg_out_opc_bne(s, TCG_REG_TMP1, TCG_REG_ZERO, 0); -+ -+ l->raddr = tcg_splitwx_to_rx(s->code_ptr); -+} -+ -+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ /* resolve label address */ -+ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { -+ return false; -+ } -+ -+ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_A1, l->addrlo_reg); -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0); -+ -+ /* tail call, with the return address back inline. */ -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RA, (uintptr_t)l->raddr); -+ tcg_out_call_int(s, (const void *)(l->is_ld ? helper_unaligned_ld -+ : helper_unaligned_st), true); -+ return true; -+} -+ -+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ return tcg_out_fail_alignment(s, l); -+} -+ -+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ return tcg_out_fail_alignment(s, l); -+} -+ -+#endif /* CONFIG_SOFTMMU */ -+ -+/* -+ * `ext32u` the address register into the temp register given, -+ * if target is 32-bit, no-op otherwise. -+ * -+ * Returns the address register ready for use with TLB addend. -+ */ -+static TCGReg tcg_out_zext_addr_if_32_bit(TCGContext *s, -+ TCGReg addr, TCGReg tmp) -+{ -+ if (TARGET_LONG_BITS == 32) { -+ tcg_out_ext32u(s, tmp, addr); -+ return tmp; -+ } -+ return addr; -+} -+ -+static void tcg_out_qemu_ld_indexed(TCGContext *s, TCGReg rd, TCGReg rj, -+ TCGReg rk, MemOp opc, TCGType type) -+{ -+ /* Byte swapping is left to middle-end expansion. */ -+ tcg_debug_assert((opc & MO_BSWAP) == 0); -+ -+ switch (opc & MO_SSIZE) { -+ case MO_UB: -+ tcg_out_opc_ldx_bu(s, rd, rj, rk); -+ break; -+ case MO_SB: -+ tcg_out_opc_ldx_b(s, rd, rj, rk); -+ break; -+ case MO_UW: -+ tcg_out_opc_ldx_hu(s, rd, rj, rk); -+ break; -+ case MO_SW: -+ tcg_out_opc_ldx_h(s, rd, rj, rk); -+ break; -+ case MO_UL: -+ if (type == TCG_TYPE_I64) { -+ tcg_out_opc_ldx_wu(s, rd, rj, rk); -+ break; -+ } -+ /* fallthrough */ -+ case MO_SL: -+ tcg_out_opc_ldx_w(s, rd, rj, rk); -+ break; -+ case MO_Q: -+ tcg_out_opc_ldx_d(s, rd, rj, rk); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, TCGType type) -+{ -+ TCGReg addr_regl; -+ TCGReg data_regl; -+ MemOpIdx oi; -+ MemOp opc; -+#if defined(CONFIG_SOFTMMU) -+ tcg_insn_unit *label_ptr[1]; -+#else -+ unsigned a_bits; -+#endif -+ TCGReg base; -+ -+ data_regl = *args++; -+ addr_regl = *args++; -+ oi = *args++; -+ opc = get_memop(oi); -+ -+#if defined(CONFIG_SOFTMMU) -+ tcg_out_tlb_load(s, addr_regl, oi, label_ptr, 1); -+ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); -+ tcg_out_qemu_ld_indexed(s, data_regl, base, TCG_REG_TMP2, opc, type); -+ add_qemu_ldst_label(s, 1, oi, type, -+ data_regl, addr_regl, -+ s->code_ptr, label_ptr); -+#else -+ a_bits = get_alignment_bits(opc); -+ if (a_bits) { -+ tcg_out_test_alignment(s, true, addr_regl, a_bits); -+ } -+ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); -+ TCGReg guest_base_reg = USE_GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_ZERO; -+ tcg_out_qemu_ld_indexed(s, data_regl, base, guest_base_reg, opc, type); -+#endif -+} -+ -+static void tcg_out_qemu_st_indexed(TCGContext *s, TCGReg data, -+ TCGReg rj, TCGReg rk, MemOp opc) -+{ -+ /* Byte swapping is left to middle-end expansion. */ -+ tcg_debug_assert((opc & MO_BSWAP) == 0); -+ -+ switch (opc & MO_SIZE) { -+ case MO_8: -+ tcg_out_opc_stx_b(s, data, rj, rk); -+ break; -+ case MO_16: -+ tcg_out_opc_stx_h(s, data, rj, rk); -+ break; -+ case MO_32: -+ tcg_out_opc_stx_w(s, data, rj, rk); -+ break; -+ case MO_64: -+ tcg_out_opc_stx_d(s, data, rj, rk); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args) -+{ -+ TCGReg addr_regl; -+ TCGReg data_regl; -+ MemOpIdx oi; -+ MemOp opc; -+#if defined(CONFIG_SOFTMMU) -+ tcg_insn_unit *label_ptr[1]; -+#else -+ unsigned a_bits; -+#endif -+ TCGReg base; -+ -+ data_regl = *args++; -+ addr_regl = *args++; -+ oi = *args++; -+ opc = get_memop(oi); -+ -+#if defined(CONFIG_SOFTMMU) -+ tcg_out_tlb_load(s, addr_regl, oi, label_ptr, 0); -+ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); -+ tcg_out_qemu_st_indexed(s, data_regl, base, TCG_REG_TMP2, opc); -+ add_qemu_ldst_label(s, 0, oi, -+ 0, /* type param is unused for stores */ -+ data_regl, addr_regl, -+ s->code_ptr, label_ptr); -+#else -+ a_bits = get_alignment_bits(opc); -+ if (a_bits) { -+ tcg_out_test_alignment(s, false, addr_regl, a_bits); -+ } -+ base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0); -+ TCGReg guest_base_reg = USE_GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_ZERO; -+ tcg_out_qemu_st_indexed(s, data_regl, base, guest_base_reg, opc); -+#endif -+} -+ -+/* -+ * Entry-points -+ */ -+ -+static const tcg_insn_unit *tb_ret_addr; -+ -+static void tcg_out_op(TCGContext *s, TCGOpcode opc, -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) -+{ -+ TCGArg a0 = args[0]; -+ TCGArg a1 = args[1]; -+ TCGArg a2 = args[2]; -+ int c2 = const_args[2]; -+ -+ switch (opc) { -+ case INDEX_op_exit_tb: -+ /* Reuse the zeroing that exists for goto_ptr. */ -+ if (a0 == 0) { -+ tcg_out_call_int(s, tcg_code_gen_epilogue, true); -+ } else { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0); -+ tcg_out_call_int(s, tb_ret_addr, true); -+ } -+ break; -+ -+ case INDEX_op_goto_tb: -+ assert(s->tb_jmp_insn_offset == 0); -+ /* indirect jump method */ -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, -+ (uintptr_t)(s->tb_jmp_target_addr + a0)); -+ tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0); -+ set_jmp_reset_offset(s, a0); -+ break; -+ -+ case INDEX_op_mb: -+ tcg_out_mb(s, a0); -+ break; -+ -+ case INDEX_op_goto_ptr: -+ tcg_out_opc_jirl(s, TCG_REG_ZERO, a0, 0); -+ break; -+ -+ case INDEX_op_br: -+ tcg_out_reloc(s, s->code_ptr, R_LOONGARCH_BR_SD10K16, arg_label(a0), -+ 0); -+ tcg_out_opc_b(s, 0); -+ break; -+ -+ case INDEX_op_brcond_i32: -+ case INDEX_op_brcond_i64: -+ tcg_out_brcond(s, a2, a0, a1, arg_label(args[3])); -+ break; -+ -+ case INDEX_op_ext8s_i32: -+ case INDEX_op_ext8s_i64: -+ tcg_out_ext8s(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext8u_i32: -+ case INDEX_op_ext8u_i64: -+ tcg_out_ext8u(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext16s_i32: -+ case INDEX_op_ext16s_i64: -+ tcg_out_ext16s(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext16u_i32: -+ case INDEX_op_ext16u_i64: -+ tcg_out_ext16u(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext32u_i64: -+ case INDEX_op_extu_i32_i64: -+ tcg_out_ext32u(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext32s_i64: -+ case INDEX_op_extrl_i64_i32: -+ case INDEX_op_ext_i32_i64: -+ tcg_out_ext32s(s, a0, a1); -+ break; -+ -+ case INDEX_op_extrh_i64_i32: -+ tcg_out_opc_srai_d(s, a0, a1, 32); -+ break; -+ -+ case INDEX_op_not_i32: -+ case INDEX_op_not_i64: -+ tcg_out_opc_nor(s, a0, a1, TCG_REG_ZERO); -+ break; -+ -+ case INDEX_op_nor_i32: -+ case INDEX_op_nor_i64: -+ if (c2) { -+ tcg_out_opc_ori(s, a0, a1, a2); -+ tcg_out_opc_nor(s, a0, a0, TCG_REG_ZERO); -+ } else { -+ tcg_out_opc_nor(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_andc_i32: -+ case INDEX_op_andc_i64: -+ if (c2) { -+ /* guaranteed to fit due to constraint */ -+ tcg_out_opc_andi(s, a0, a1, ~a2); -+ } else { -+ tcg_out_opc_andn(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_orc_i32: -+ case INDEX_op_orc_i64: -+ if (c2) { -+ /* guaranteed to fit due to constraint */ -+ tcg_out_opc_ori(s, a0, a1, ~a2); -+ } else { -+ tcg_out_opc_orn(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_and_i32: -+ case INDEX_op_and_i64: -+ if (c2) { -+ tcg_out_opc_andi(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_and(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_or_i32: -+ case INDEX_op_or_i64: -+ if (c2) { -+ tcg_out_opc_ori(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_or(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_xor_i32: -+ case INDEX_op_xor_i64: -+ if (c2) { -+ tcg_out_opc_xori(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_xor(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_extract_i32: -+ tcg_out_opc_bstrpick_w(s, a0, a1, a2, a2 + args[3] - 1); -+ break; -+ case INDEX_op_extract_i64: -+ tcg_out_opc_bstrpick_d(s, a0, a1, a2, a2 + args[3] - 1); -+ break; -+ -+ case INDEX_op_deposit_i32: -+ tcg_out_opc_bstrins_w(s, a0, a2, args[3], args[3] + args[4] - 1); -+ break; -+ case INDEX_op_deposit_i64: -+ tcg_out_opc_bstrins_d(s, a0, a2, args[3], args[3] + args[4] - 1); -+ break; -+ -+ case INDEX_op_bswap16_i32: -+ case INDEX_op_bswap16_i64: -+ tcg_out_opc_revb_2h(s, a0, a1); -+ if (a2 & TCG_BSWAP_OS) { -+ tcg_out_ext16s(s, a0, a0); -+ } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { -+ tcg_out_ext16u(s, a0, a0); -+ } -+ break; -+ -+ case INDEX_op_bswap32_i32: -+ /* All 32-bit values are computed sign-extended in the register. */ -+ a2 = TCG_BSWAP_OS; -+ /* fallthrough */ -+ case INDEX_op_bswap32_i64: -+ tcg_out_opc_revb_2w(s, a0, a1); -+ if (a2 & TCG_BSWAP_OS) { -+ tcg_out_ext32s(s, a0, a0); -+ } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { -+ tcg_out_ext32u(s, a0, a0); -+ } -+ break; -+ -+ case INDEX_op_bswap64_i64: -+ tcg_out_opc_revb_d(s, a0, a1); -+ break; -+ -+ case INDEX_op_clz_i32: -+ tcg_out_clzctz(s, OPC_CLZ_W, a0, a1, a2, c2, true); -+ break; -+ case INDEX_op_clz_i64: -+ tcg_out_clzctz(s, OPC_CLZ_D, a0, a1, a2, c2, false); -+ break; -+ -+ case INDEX_op_ctz_i32: -+ tcg_out_clzctz(s, OPC_CTZ_W, a0, a1, a2, c2, true); -+ break; -+ case INDEX_op_ctz_i64: -+ tcg_out_clzctz(s, OPC_CTZ_D, a0, a1, a2, c2, false); -+ break; -+ -+ case INDEX_op_shl_i32: -+ if (c2) { -+ tcg_out_opc_slli_w(s, a0, a1, a2 & 0x1f); -+ } else { -+ tcg_out_opc_sll_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_shl_i64: -+ if (c2) { -+ tcg_out_opc_slli_d(s, a0, a1, a2 & 0x3f); -+ } else { -+ tcg_out_opc_sll_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_shr_i32: -+ if (c2) { -+ tcg_out_opc_srli_w(s, a0, a1, a2 & 0x1f); -+ } else { -+ tcg_out_opc_srl_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_shr_i64: -+ if (c2) { -+ tcg_out_opc_srli_d(s, a0, a1, a2 & 0x3f); -+ } else { -+ tcg_out_opc_srl_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_sar_i32: -+ if (c2) { -+ tcg_out_opc_srai_w(s, a0, a1, a2 & 0x1f); -+ } else { -+ tcg_out_opc_sra_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_sar_i64: -+ if (c2) { -+ tcg_out_opc_srai_d(s, a0, a1, a2 & 0x3f); -+ } else { -+ tcg_out_opc_sra_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_rotl_i32: -+ /* transform into equivalent rotr/rotri */ -+ if (c2) { -+ tcg_out_opc_rotri_w(s, a0, a1, (32 - a2) & 0x1f); -+ } else { -+ tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2); -+ tcg_out_opc_rotr_w(s, a0, a1, TCG_REG_TMP0); -+ } -+ break; -+ case INDEX_op_rotl_i64: -+ /* transform into equivalent rotr/rotri */ -+ if (c2) { -+ tcg_out_opc_rotri_d(s, a0, a1, (64 - a2) & 0x3f); -+ } else { -+ tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2); -+ tcg_out_opc_rotr_d(s, a0, a1, TCG_REG_TMP0); -+ } -+ break; -+ -+ case INDEX_op_rotr_i32: -+ if (c2) { -+ tcg_out_opc_rotri_w(s, a0, a1, a2 & 0x1f); -+ } else { -+ tcg_out_opc_rotr_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_rotr_i64: -+ if (c2) { -+ tcg_out_opc_rotri_d(s, a0, a1, a2 & 0x3f); -+ } else { -+ tcg_out_opc_rotr_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_add_i32: -+ if (c2) { -+ tcg_out_opc_addi_w(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_add_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_add_i64: -+ if (c2) { -+ tcg_out_opc_addi_d(s, a0, a1, a2); -+ } else { -+ tcg_out_opc_add_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_sub_i32: -+ if (c2) { -+ tcg_out_opc_addi_w(s, a0, a1, -a2); -+ } else { -+ tcg_out_opc_sub_w(s, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_sub_i64: -+ if (c2) { -+ tcg_out_opc_addi_d(s, a0, a1, -a2); -+ } else { -+ tcg_out_opc_sub_d(s, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_mul_i32: -+ tcg_out_opc_mul_w(s, a0, a1, a2); -+ break; -+ case INDEX_op_mul_i64: -+ tcg_out_opc_mul_d(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_mulsh_i32: -+ tcg_out_opc_mulh_w(s, a0, a1, a2); -+ break; -+ case INDEX_op_mulsh_i64: -+ tcg_out_opc_mulh_d(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_muluh_i32: -+ tcg_out_opc_mulh_wu(s, a0, a1, a2); -+ break; -+ case INDEX_op_muluh_i64: -+ tcg_out_opc_mulh_du(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_div_i32: -+ tcg_out_opc_div_w(s, a0, a1, a2); -+ break; -+ case INDEX_op_div_i64: -+ tcg_out_opc_div_d(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_divu_i32: -+ tcg_out_opc_div_wu(s, a0, a1, a2); -+ break; -+ case INDEX_op_divu_i64: -+ tcg_out_opc_div_du(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_rem_i32: -+ tcg_out_opc_mod_w(s, a0, a1, a2); -+ break; -+ case INDEX_op_rem_i64: -+ tcg_out_opc_mod_d(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_remu_i32: -+ tcg_out_opc_mod_wu(s, a0, a1, a2); -+ break; -+ case INDEX_op_remu_i64: -+ tcg_out_opc_mod_du(s, a0, a1, a2); -+ break; -+ -+ case INDEX_op_setcond_i32: -+ case INDEX_op_setcond_i64: -+ tcg_out_setcond(s, args[3], a0, a1, a2, c2); -+ break; -+ -+ case INDEX_op_ld8s_i32: -+ case INDEX_op_ld8s_i64: -+ tcg_out_ldst(s, OPC_LD_B, a0, a1, a2); -+ break; -+ case INDEX_op_ld8u_i32: -+ case INDEX_op_ld8u_i64: -+ tcg_out_ldst(s, OPC_LD_BU, a0, a1, a2); -+ break; -+ case INDEX_op_ld16s_i32: -+ case INDEX_op_ld16s_i64: -+ tcg_out_ldst(s, OPC_LD_H, a0, a1, a2); -+ break; -+ case INDEX_op_ld16u_i32: -+ case INDEX_op_ld16u_i64: -+ tcg_out_ldst(s, OPC_LD_HU, a0, a1, a2); -+ break; -+ case INDEX_op_ld_i32: -+ case INDEX_op_ld32s_i64: -+ tcg_out_ldst(s, OPC_LD_W, a0, a1, a2); -+ break; -+ case INDEX_op_ld32u_i64: -+ tcg_out_ldst(s, OPC_LD_WU, a0, a1, a2); -+ break; -+ case INDEX_op_ld_i64: -+ tcg_out_ldst(s, OPC_LD_D, a0, a1, a2); -+ break; -+ -+ case INDEX_op_st8_i32: -+ case INDEX_op_st8_i64: -+ tcg_out_ldst(s, OPC_ST_B, a0, a1, a2); -+ break; -+ case INDEX_op_st16_i32: -+ case INDEX_op_st16_i64: -+ tcg_out_ldst(s, OPC_ST_H, a0, a1, a2); -+ break; -+ case INDEX_op_st_i32: -+ case INDEX_op_st32_i64: -+ tcg_out_ldst(s, OPC_ST_W, a0, a1, a2); -+ break; -+ case INDEX_op_st_i64: -+ tcg_out_ldst(s, OPC_ST_D, a0, a1, a2); -+ break; -+ -+ case INDEX_op_qemu_ld_i32: -+ tcg_out_qemu_ld(s, args, TCG_TYPE_I32); -+ break; -+ case INDEX_op_qemu_ld_i64: -+ tcg_out_qemu_ld(s, args, TCG_TYPE_I64); -+ break; -+ case INDEX_op_qemu_st_i32: -+ tcg_out_qemu_st(s, args); -+ break; -+ case INDEX_op_qemu_st_i64: -+ tcg_out_qemu_st(s, args); -+ break; -+ -+ case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ -+ case INDEX_op_mov_i64: -+ case INDEX_op_call: /* Always emitted via tcg_out_call. */ -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) -+{ -+ switch (op) { -+ case INDEX_op_goto_ptr: -+ return C_O0_I1(r); -+ -+ case INDEX_op_st8_i32: -+ case INDEX_op_st8_i64: -+ case INDEX_op_st16_i32: -+ case INDEX_op_st16_i64: -+ case INDEX_op_st32_i64: -+ case INDEX_op_st_i32: -+ case INDEX_op_st_i64: -+ return C_O0_I2(rZ, r); -+ -+ case INDEX_op_brcond_i32: -+ case INDEX_op_brcond_i64: -+ return C_O0_I2(rZ, rZ); -+ -+ case INDEX_op_qemu_st_i32: -+ case INDEX_op_qemu_st_i64: -+ return C_O0_I2(LZ, L); -+ -+ case INDEX_op_ext8s_i32: -+ case INDEX_op_ext8s_i64: -+ case INDEX_op_ext8u_i32: -+ case INDEX_op_ext8u_i64: -+ case INDEX_op_ext16s_i32: -+ case INDEX_op_ext16s_i64: -+ case INDEX_op_ext16u_i32: -+ case INDEX_op_ext16u_i64: -+ case INDEX_op_ext32s_i64: -+ case INDEX_op_ext32u_i64: -+ case INDEX_op_extu_i32_i64: -+ case INDEX_op_extrl_i64_i32: -+ case INDEX_op_extrh_i64_i32: -+ case INDEX_op_ext_i32_i64: -+ case INDEX_op_not_i32: -+ case INDEX_op_not_i64: -+ case INDEX_op_extract_i32: -+ case INDEX_op_extract_i64: -+ case INDEX_op_bswap16_i32: -+ case INDEX_op_bswap16_i64: -+ case INDEX_op_bswap32_i32: -+ case INDEX_op_bswap32_i64: -+ case INDEX_op_bswap64_i64: -+ case INDEX_op_ld8s_i32: -+ case INDEX_op_ld8s_i64: -+ case INDEX_op_ld8u_i32: -+ case INDEX_op_ld8u_i64: -+ case INDEX_op_ld16s_i32: -+ case INDEX_op_ld16s_i64: -+ case INDEX_op_ld16u_i32: -+ case INDEX_op_ld16u_i64: -+ case INDEX_op_ld32s_i64: -+ case INDEX_op_ld32u_i64: -+ case INDEX_op_ld_i32: -+ case INDEX_op_ld_i64: -+ return C_O1_I1(r, r); -+ -+ case INDEX_op_qemu_ld_i32: -+ case INDEX_op_qemu_ld_i64: -+ return C_O1_I1(r, L); -+ -+ case INDEX_op_andc_i32: -+ case INDEX_op_andc_i64: -+ case INDEX_op_orc_i32: -+ case INDEX_op_orc_i64: -+ /* -+ * LoongArch insns for these ops don't have reg-imm forms, but we -+ * can express using andi/ori if ~constant satisfies -+ * TCG_CT_CONST_U12. -+ */ -+ return C_O1_I2(r, r, rC); -+ -+ case INDEX_op_shl_i32: -+ case INDEX_op_shl_i64: -+ case INDEX_op_shr_i32: -+ case INDEX_op_shr_i64: -+ case INDEX_op_sar_i32: -+ case INDEX_op_sar_i64: -+ case INDEX_op_rotl_i32: -+ case INDEX_op_rotl_i64: -+ case INDEX_op_rotr_i32: -+ case INDEX_op_rotr_i64: -+ return C_O1_I2(r, r, ri); -+ -+ case INDEX_op_add_i32: -+ case INDEX_op_add_i64: -+ return C_O1_I2(r, r, rI); -+ -+ case INDEX_op_and_i32: -+ case INDEX_op_and_i64: -+ case INDEX_op_nor_i32: -+ case INDEX_op_nor_i64: -+ case INDEX_op_or_i32: -+ case INDEX_op_or_i64: -+ case INDEX_op_xor_i32: -+ case INDEX_op_xor_i64: -+ /* LoongArch reg-imm bitops have their imms ZERO-extended */ -+ return C_O1_I2(r, r, rU); -+ -+ case INDEX_op_clz_i32: -+ case INDEX_op_clz_i64: -+ case INDEX_op_ctz_i32: -+ case INDEX_op_ctz_i64: -+ return C_O1_I2(r, r, rW); -+ -+ case INDEX_op_setcond_i32: -+ case INDEX_op_setcond_i64: -+ return C_O1_I2(r, r, rZ); -+ -+ case INDEX_op_deposit_i32: -+ case INDEX_op_deposit_i64: -+ /* Must deposit into the same register as input */ -+ return C_O1_I2(r, 0, rZ); -+ -+ case INDEX_op_sub_i32: -+ case INDEX_op_sub_i64: -+ return C_O1_I2(r, rZ, rN); -+ -+ case INDEX_op_mul_i32: -+ case INDEX_op_mul_i64: -+ case INDEX_op_mulsh_i32: -+ case INDEX_op_mulsh_i64: -+ case INDEX_op_muluh_i32: -+ case INDEX_op_muluh_i64: -+ case INDEX_op_div_i32: -+ case INDEX_op_div_i64: -+ case INDEX_op_divu_i32: -+ case INDEX_op_divu_i64: -+ case INDEX_op_rem_i32: -+ case INDEX_op_rem_i64: -+ case INDEX_op_remu_i32: -+ case INDEX_op_remu_i64: -+ return C_O1_I2(r, rZ, rZ); -+ -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static const int tcg_target_callee_save_regs[] = { -+ TCG_REG_S0, /* used for the global env (TCG_AREG0) */ -+ TCG_REG_S1, -+ TCG_REG_S2, -+ TCG_REG_S3, -+ TCG_REG_S4, -+ TCG_REG_S5, -+ TCG_REG_S6, -+ TCG_REG_S7, -+ TCG_REG_S8, -+ TCG_REG_S9, -+ TCG_REG_RA, /* should be last for ABI compliance */ -+}; -+ -+/* Stack frame parameters. */ -+#define REG_SIZE (TCG_TARGET_REG_BITS / 8) -+#define SAVE_SIZE ((int)ARRAY_SIZE(tcg_target_callee_save_regs) * REG_SIZE) -+#define TEMP_SIZE (CPU_TEMP_BUF_NLONGS * (int)sizeof(long)) -+#define FRAME_SIZE ((TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE + SAVE_SIZE \ -+ + TCG_TARGET_STACK_ALIGN - 1) \ -+ & -TCG_TARGET_STACK_ALIGN) -+#define SAVE_OFS (TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE) -+ -+/* We're expecting to be able to use an immediate for frame allocation. */ -+QEMU_BUILD_BUG_ON(FRAME_SIZE > 0x7ff); -+ -+/* Generate global QEMU prologue and epilogue code */ -+static void tcg_target_qemu_prologue(TCGContext *s) -+{ -+ int i; -+ -+ tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, TEMP_SIZE); -+ -+ /* TB prologue */ -+ tcg_out_opc_addi_d(s, TCG_REG_SP, TCG_REG_SP, -FRAME_SIZE); -+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { -+ tcg_out_st(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i], -+ TCG_REG_SP, SAVE_OFS + i * REG_SIZE); -+ } -+ -+#if !defined(CONFIG_SOFTMMU) -+ if (USE_GUEST_BASE) { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); -+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); -+ } -+#endif -+ -+ /* Call generated code */ -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); -+ tcg_out_opc_jirl(s, TCG_REG_ZERO, tcg_target_call_iarg_regs[1], 0); -+ -+ /* Return path for goto_ptr. Set return value to 0 */ -+ tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr); -+ tcg_out_mov(s, TCG_TYPE_REG, TCG_REG_A0, TCG_REG_ZERO); -+ -+ /* TB epilogue */ -+ tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr); -+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { -+ tcg_out_ld(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i], -+ TCG_REG_SP, SAVE_OFS + i * REG_SIZE); -+ } -+ -+ tcg_out_opc_addi_d(s, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE); -+ tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_RA, 0); -+} -+ -+static void tcg_target_init(TCGContext *s) -+{ -+ tcg_target_available_regs[TCG_TYPE_I32] = ALL_GENERAL_REGS; -+ tcg_target_available_regs[TCG_TYPE_I64] = ALL_GENERAL_REGS; -+ -+ tcg_target_call_clobber_regs = ALL_GENERAL_REGS; -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S0); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S1); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S2); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S3); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S4); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S5); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S6); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S7); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S8); -+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S9); -+ -+ s->reserved_regs = 0; -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP0); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP1); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TP); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_RESERVED); -+} -+ -+typedef struct { -+ DebugFrameHeader h; -+ uint8_t fde_def_cfa[4]; -+ uint8_t fde_reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2]; -+} DebugFrame; -+ -+#define ELF_HOST_MACHINE EM_LOONGARCH -+ -+static const DebugFrame debug_frame = { -+ .h.cie.len = sizeof(DebugFrameCIE) - 4, /* length after .len member */ -+ .h.cie.id = -1, -+ .h.cie.version = 1, -+ .h.cie.code_align = 1, -+ .h.cie.data_align = -(TCG_TARGET_REG_BITS / 8) & 0x7f, /* sleb128 */ -+ .h.cie.return_column = TCG_REG_RA, -+ -+ /* Total FDE size does not include the "len" member. */ -+ .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset), -+ -+ .fde_def_cfa = { -+ 12, TCG_REG_SP, /* DW_CFA_def_cfa sp, ... */ -+ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ -+ (FRAME_SIZE >> 7) -+ }, -+ .fde_reg_ofs = { -+ 0x80 + 23, 11, /* DW_CFA_offset, s0, -88 */ -+ 0x80 + 24, 10, /* DW_CFA_offset, s1, -80 */ -+ 0x80 + 25, 9, /* DW_CFA_offset, s2, -72 */ -+ 0x80 + 26, 8, /* DW_CFA_offset, s3, -64 */ -+ 0x80 + 27, 7, /* DW_CFA_offset, s4, -56 */ -+ 0x80 + 28, 6, /* DW_CFA_offset, s5, -48 */ -+ 0x80 + 29, 5, /* DW_CFA_offset, s6, -40 */ -+ 0x80 + 30, 4, /* DW_CFA_offset, s7, -32 */ -+ 0x80 + 31, 3, /* DW_CFA_offset, s8, -24 */ -+ 0x80 + 22, 2, /* DW_CFA_offset, s9, -16 */ -+ 0x80 + 1 , 1, /* DW_CFA_offset, ra, -8 */ -+ } -+}; -+ -+void tcg_register_jit(const void *buf, size_t buf_size) -+{ -+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); -+} -diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h -new file mode 100644 -index 000000000..d58a6162f ---- /dev/null -+++ b/tcg/loongarch64/tcg-target.h -@@ -0,0 +1,178 @@ -+/* -+ * Tiny Code Generator for QEMU -+ * -+ * Copyright (c) 2021 WANG Xuerui -+ * -+ * Based on tcg/riscv/tcg-target.h -+ * -+ * Copyright (c) 2018 SiFive, Inc -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#ifndef LOONGARCH_TCG_TARGET_H -+#define LOONGARCH_TCG_TARGET_H -+ -+/* -+ * Loongson removed the (incomplete) 32-bit support from kernel and toolchain -+ * for the initial upstreaming of this architecture, so don't bother and just -+ * support the LP64* ABI for now. -+ */ -+#if defined(__loongarch64) -+# define TCG_TARGET_REG_BITS 64 -+#else -+# error unsupported LoongArch register size -+#endif -+ -+#define TCG_TARGET_INSN_UNIT_SIZE 4 -+#define TCG_TARGET_NB_REGS 32 -+#define MAX_CODE_GEN_BUFFER_SIZE SIZE_MAX -+ -+typedef enum { -+ TCG_REG_ZERO, -+ TCG_REG_RA, -+ TCG_REG_TP, -+ TCG_REG_SP, -+ TCG_REG_A0, -+ TCG_REG_A1, -+ TCG_REG_A2, -+ TCG_REG_A3, -+ TCG_REG_A4, -+ TCG_REG_A5, -+ TCG_REG_A6, -+ TCG_REG_A7, -+ TCG_REG_T0, -+ TCG_REG_T1, -+ TCG_REG_T2, -+ TCG_REG_T3, -+ TCG_REG_T4, -+ TCG_REG_T5, -+ TCG_REG_T6, -+ TCG_REG_T7, -+ TCG_REG_T8, -+ TCG_REG_RESERVED, -+ TCG_REG_S9, -+ TCG_REG_S0, -+ TCG_REG_S1, -+ TCG_REG_S2, -+ TCG_REG_S3, -+ TCG_REG_S4, -+ TCG_REG_S5, -+ TCG_REG_S6, -+ TCG_REG_S7, -+ TCG_REG_S8, -+ -+ /* aliases */ -+ TCG_AREG0 = TCG_REG_S0, -+ TCG_REG_TMP0 = TCG_REG_T8, -+ TCG_REG_TMP1 = TCG_REG_T7, -+ TCG_REG_TMP2 = TCG_REG_T6, -+} TCGReg; -+ -+/* used for function call generation */ -+#define TCG_REG_CALL_STACK TCG_REG_SP -+#define TCG_TARGET_STACK_ALIGN 16 -+#define TCG_TARGET_CALL_ALIGN_ARGS 1 -+#define TCG_TARGET_CALL_STACK_OFFSET 0 -+ -+/* optional instructions */ -+#define TCG_TARGET_HAS_movcond_i32 0 -+#define TCG_TARGET_HAS_div_i32 1 -+#define TCG_TARGET_HAS_rem_i32 1 -+#define TCG_TARGET_HAS_div2_i32 0 -+#define TCG_TARGET_HAS_rot_i32 1 -+#define TCG_TARGET_HAS_deposit_i32 1 -+#define TCG_TARGET_HAS_extract_i32 1 -+#define TCG_TARGET_HAS_sextract_i32 0 -+#define TCG_TARGET_HAS_extract2_i32 0 -+#define TCG_TARGET_HAS_add2_i32 0 -+#define TCG_TARGET_HAS_sub2_i32 0 -+#define TCG_TARGET_HAS_mulu2_i32 0 -+#define TCG_TARGET_HAS_muls2_i32 0 -+#define TCG_TARGET_HAS_muluh_i32 1 -+#define TCG_TARGET_HAS_mulsh_i32 1 -+#define TCG_TARGET_HAS_ext8s_i32 1 -+#define TCG_TARGET_HAS_ext16s_i32 1 -+#define TCG_TARGET_HAS_ext8u_i32 1 -+#define TCG_TARGET_HAS_ext16u_i32 1 -+#define TCG_TARGET_HAS_bswap16_i32 1 -+#define TCG_TARGET_HAS_bswap32_i32 1 -+#define TCG_TARGET_HAS_not_i32 1 -+#define TCG_TARGET_HAS_neg_i32 0 -+#define TCG_TARGET_HAS_andc_i32 1 -+#define TCG_TARGET_HAS_orc_i32 1 -+#define TCG_TARGET_HAS_eqv_i32 0 -+#define TCG_TARGET_HAS_nand_i32 0 -+#define TCG_TARGET_HAS_nor_i32 1 -+#define TCG_TARGET_HAS_clz_i32 1 -+#define TCG_TARGET_HAS_ctz_i32 1 -+#define TCG_TARGET_HAS_ctpop_i32 0 -+#define TCG_TARGET_HAS_direct_jump 0 -+#define TCG_TARGET_HAS_brcond2 0 -+#define TCG_TARGET_HAS_setcond2 0 -+#define TCG_TARGET_HAS_qemu_st8_i32 0 -+ -+/* 64-bit operations */ -+#define TCG_TARGET_HAS_movcond_i64 0 -+#define TCG_TARGET_HAS_div_i64 1 -+#define TCG_TARGET_HAS_rem_i64 1 -+#define TCG_TARGET_HAS_div2_i64 0 -+#define TCG_TARGET_HAS_rot_i64 1 -+#define TCG_TARGET_HAS_deposit_i64 1 -+#define TCG_TARGET_HAS_extract_i64 1 -+#define TCG_TARGET_HAS_sextract_i64 0 -+#define TCG_TARGET_HAS_extract2_i64 0 -+#define TCG_TARGET_HAS_extrl_i64_i32 1 -+#define TCG_TARGET_HAS_extrh_i64_i32 1 -+#define TCG_TARGET_HAS_ext8s_i64 1 -+#define TCG_TARGET_HAS_ext16s_i64 1 -+#define TCG_TARGET_HAS_ext32s_i64 1 -+#define TCG_TARGET_HAS_ext8u_i64 1 -+#define TCG_TARGET_HAS_ext16u_i64 1 -+#define TCG_TARGET_HAS_ext32u_i64 1 -+#define TCG_TARGET_HAS_bswap16_i64 1 -+#define TCG_TARGET_HAS_bswap32_i64 1 -+#define TCG_TARGET_HAS_bswap64_i64 1 -+#define TCG_TARGET_HAS_not_i64 1 -+#define TCG_TARGET_HAS_neg_i64 0 -+#define TCG_TARGET_HAS_andc_i64 1 -+#define TCG_TARGET_HAS_orc_i64 1 -+#define TCG_TARGET_HAS_eqv_i64 0 -+#define TCG_TARGET_HAS_nand_i64 0 -+#define TCG_TARGET_HAS_nor_i64 1 -+#define TCG_TARGET_HAS_clz_i64 1 -+#define TCG_TARGET_HAS_ctz_i64 1 -+#define TCG_TARGET_HAS_ctpop_i64 0 -+#define TCG_TARGET_HAS_add2_i64 0 -+#define TCG_TARGET_HAS_sub2_i64 0 -+#define TCG_TARGET_HAS_mulu2_i64 0 -+#define TCG_TARGET_HAS_muls2_i64 0 -+#define TCG_TARGET_HAS_muluh_i64 1 -+#define TCG_TARGET_HAS_mulsh_i64 1 -+ -+/* not defined -- call should be eliminated at compile time */ -+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); -+ -+#define TCG_TARGET_DEFAULT_MO (0) -+ -+#define TCG_TARGET_NEED_LDST_LABELS -+ -+#define TCG_TARGET_HAS_MEMORY_BSWAP 0 -+ -+#endif /* LOONGARCH_TCG_TARGET_H */ --- -2.43.5 - diff --git a/1038-doc-update-AMD-SEV-to-include-Live-migration-flow.patch b/1038-doc-update-AMD-SEV-to-include-Live-migration-flow.patch deleted file mode 100644 index 6672e3ff24320b3337acbfc49922cb263fb1d385..0000000000000000000000000000000000000000 --- a/1038-doc-update-AMD-SEV-to-include-Live-migration-flow.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 5152d49cc4aead7dc06e9f788e9c078701c5a160 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Thu, 7 May 2020 22:26:17 +0000 -Subject: [PATCH 01/29] doc: update AMD SEV to include Live migration flow - -cherry-picked from https://github.com/AMDESE/qemu/commit/0e2b3d80e3. - -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Brijesh Singh -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - docs/amd-memory-encryption.txt | 40 +++++++++++++++++++++++++++++++++- - 1 file changed, 39 insertions(+), 1 deletion(-) - -diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt -index ffca382b5..17e2714d9 100644 ---- a/docs/amd-memory-encryption.txt -+++ b/docs/amd-memory-encryption.txt -@@ -126,7 +126,45 @@ TODO - - Live Migration - ---------------- --TODO -+AMD SEV encrypts the memory of VMs and because a different key is used -+in each VM, the hypervisor will be unable to simply copy the -+ciphertext from one VM to another to migrate the VM. Instead the AMD SEV Key -+Management API provides sets of function which the hypervisor can use -+to package a guest page for migration, while maintaining the confidentiality -+provided by AMD SEV. -+ -+SEV guest VMs have the concept of private and shared memory. The private -+memory is encrypted with the guest-specific key, while shared memory may -+be encrypted with the hypervisor key. The migration APIs provided by the -+SEV API spec should be used for migrating the private pages. The -+KVM_GET_PAGE_ENC_BITMAP ioctl can be used to get the guest page encryption -+bitmap. The bitmap can be used to check if the given guest page is -+private or shared. -+ -+Before initiating the migration, we need to know the targets machine's public -+Diffie-Hellman key (PDH) and certificate chain. It can be retrieved -+with the 'query-sev-capabilities' QMP command or using the sev-tool. The -+migrate-set-parameter can be used to pass the target machine's PDH and -+certificate chain. -+ -+During the migration flow, the SEND_START is called on the source hypervisor -+to create an outgoing encryption context. The SEV guest policy dictates whether -+the certificate passed through the migrate-sev-set-info command will be -+validated. SEND_UPDATE_DATA is called to encrypt the guest private pages. -+After migration is completed, SEND_FINISH is called to destroy the encryption -+context and make the VM non-runnable to protect it against cloning. -+ -+On the target machine, RECEIVE_START is called first to create an -+incoming encryption context. The RECEIVE_UPDATE_DATA is called to copy -+the received encrypted page into guest memory. After migration has -+completed, RECEIVE_FINISH is called to make the VM runnable. -+ -+For more information about the migration see SEV API Appendix A -+Usage flow (Live migration section). -+ -+NOTE: -+To protect against the memory clone SEV APIs are designed to make the VM -+unrunnable in case of the migration failure. - - References - ----------------- --- -2.31.1 - diff --git a/1039-migration.json-add-AMD-SEV-specific-migration-parame.patch b/1039-migration.json-add-AMD-SEV-specific-migration-parame.patch deleted file mode 100644 index bd46ba75d2d137171ea2cdc6ace9ec8274192816..0000000000000000000000000000000000000000 --- a/1039-migration.json-add-AMD-SEV-specific-migration-parame.patch +++ /dev/null @@ -1,253 +0,0 @@ -From 7dc7f0659bfe9c8be64f65873df9595b3791dce5 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 11:27:00 +0000 -Subject: [PATCH 02/29] migration.json: add AMD SEV specific migration - parameters - -cherry-picked from https://github.com/AMDESE/qemu/commit/d6a23bde6b6e. - -AMD SEV migration flow requires that target machine's public Diffie-Hellman -key (PDH) and certificate chain must be passed before initiating the guest -migration. User can use QMP 'migrate-set-parameters' to pass the certificate -chain. The certificate chain will be used while creating the outgoing -encryption context. - -Signed-off-by: Brijesh Singh -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - migration/migration.c | 66 +++++++++++++++++++++++++++++++++++++++++++ - monitor/hmp-cmds.c | 18 ++++++++++++ - qapi/migration.json | 40 ++++++++++++++++++++++++-- - 3 files changed, 121 insertions(+), 3 deletions(-) - -diff --git a/migration/migration.c b/migration/migration.c -index 0885549de..6810bcefc 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -932,6 +932,12 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) - params->announce_rounds = s->parameters.announce_rounds; - params->has_announce_step = true; - params->announce_step = s->parameters.announce_step; -+ params->has_sev_pdh = true; -+ params->sev_pdh = g_strdup(s->parameters.sev_pdh); -+ params->has_sev_plat_cert = true; -+ params->sev_plat_cert = g_strdup(s->parameters.sev_plat_cert); -+ params->has_sev_amd_cert = true; -+ params->sev_amd_cert = g_strdup(s->parameters.sev_amd_cert); - - if (s->parameters.has_block_bitmap_mapping) { - params->has_block_bitmap_mapping = true; -@@ -1633,6 +1639,19 @@ static void migrate_params_test_apply(MigrateSetParameters *params, - dest->has_block_bitmap_mapping = true; - dest->block_bitmap_mapping = params->block_bitmap_mapping; - } -+ -+ if (params->has_sev_pdh) { -+ assert(params->sev_pdh->type == QTYPE_QSTRING); -+ dest->sev_pdh = g_strdup(params->sev_pdh->u.s); -+ } -+ if (params->has_sev_plat_cert) { -+ assert(params->sev_plat_cert->type == QTYPE_QSTRING); -+ dest->sev_plat_cert = g_strdup(params->sev_plat_cert->u.s); -+ } -+ if (params->has_sev_amd_cert) { -+ assert(params->sev_amd_cert->type == QTYPE_QSTRING); -+ dest->sev_amd_cert = g_strdup(params->sev_amd_cert->u.s); -+ } - } - - static void migrate_params_apply(MigrateSetParameters *params, Error **errp) -@@ -1755,6 +1774,22 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) - QAPI_CLONE(BitmapMigrationNodeAliasList, - params->block_bitmap_mapping); - } -+ -+ if (params->has_sev_pdh) { -+ g_free(s->parameters.sev_pdh); -+ assert(params->sev_pdh->type == QTYPE_QSTRING); -+ s->parameters.sev_pdh = g_strdup(params->sev_pdh->u.s); -+ } -+ if (params->has_sev_plat_cert) { -+ g_free(s->parameters.sev_plat_cert); -+ assert(params->sev_plat_cert->type == QTYPE_QSTRING); -+ s->parameters.sev_plat_cert = g_strdup(params->sev_plat_cert->u.s); -+ } -+ if (params->has_sev_amd_cert) { -+ g_free(s->parameters.sev_amd_cert); -+ assert(params->sev_amd_cert->type == QTYPE_QSTRING); -+ s->parameters.sev_amd_cert = g_strdup(params->sev_amd_cert->u.s); -+ } - } - - void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) -@@ -1775,6 +1810,27 @@ void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) - params->tls_hostname->type = QTYPE_QSTRING; - params->tls_hostname->u.s = strdup(""); - } -+ /* TODO Rewrite "" to null instead */ -+ if (params->has_sev_pdh -+ && params->sev_pdh->type == QTYPE_QNULL) { -+ qobject_unref(params->sev_pdh->u.n); -+ params->sev_pdh->type = QTYPE_QSTRING; -+ params->sev_pdh->u.s = strdup(""); -+ } -+ /* TODO Rewrite "" to null instead */ -+ if (params->has_sev_plat_cert -+ && params->sev_plat_cert->type == QTYPE_QNULL) { -+ qobject_unref(params->sev_plat_cert->u.n); -+ params->sev_plat_cert->type = QTYPE_QSTRING; -+ params->sev_plat_cert->u.s = strdup(""); -+ } -+ /* TODO Rewrite "" to null instead */ -+ if (params->has_sev_amd_cert -+ && params->sev_amd_cert->type == QTYPE_QNULL) { -+ qobject_unref(params->sev_amd_cert->u.n); -+ params->sev_amd_cert->type = QTYPE_QSTRING; -+ params->sev_amd_cert->u.s = strdup(""); -+ } - - migrate_params_test_apply(params, &tmp); - -@@ -4332,6 +4388,9 @@ static void migration_instance_finalize(Object *obj) - qemu_mutex_destroy(&ms->qemu_file_lock); - g_free(params->tls_hostname); - g_free(params->tls_creds); -+ g_free(params->sev_pdh); -+ g_free(params->sev_plat_cert); -+ g_free(params->sev_amd_cert); - qemu_sem_destroy(&ms->wait_unplug_sem); - qemu_sem_destroy(&ms->rate_limit_sem); - qemu_sem_destroy(&ms->pause_sem); -@@ -4383,6 +4442,13 @@ static void migration_instance_init(Object *obj) - params->has_tls_hostname = true; - params->has_tls_authz = true; - -+ params->sev_pdh = g_strdup(""); -+ params->sev_plat_cert = g_strdup(""); -+ params->sev_amd_cert = g_strdup(""); -+ params->has_sev_pdh = true; -+ params->has_sev_plat_cert = true; -+ params->has_sev_amd_cert = true; -+ - qemu_sem_init(&ms->postcopy_pause_sem, 0); - qemu_sem_init(&ms->postcopy_pause_rp_sem, 0); - qemu_sem_init(&ms->rp_state.rp_sem, 0); -diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c -index f7216ab5d..409bd15a6 100644 ---- a/monitor/hmp-cmds.c -+++ b/monitor/hmp-cmds.c -@@ -1349,6 +1349,24 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) - error_setg(&err, "The block-bitmap-mapping parameter can only be set " - "through QMP"); - break; -+ case MIGRATION_PARAMETER_SEV_PDH: -+ p->has_sev_pdh = true; -+ p->sev_pdh = g_new0(StrOrNull, 1); -+ p->sev_pdh->type = QTYPE_QSTRING; -+ visit_type_str(v, param, &p->sev_pdh->u.s, &err); -+ break; -+ case MIGRATION_PARAMETER_SEV_PLAT_CERT: -+ p->has_sev_plat_cert = true; -+ p->sev_plat_cert = g_new0(StrOrNull, 1); -+ p->sev_plat_cert->type = QTYPE_QSTRING; -+ visit_type_str(v, param, &p->sev_plat_cert->u.s, &err); -+ break; -+ case MIGRATION_PARAMETER_SEV_AMD_CERT: -+ p->has_sev_amd_cert = true; -+ p->sev_amd_cert = g_new0(StrOrNull, 1); -+ p->sev_amd_cert->type = QTYPE_QSTRING; -+ visit_type_str(v, param, &p->sev_amd_cert->u.s, &err); -+ break; - default: - assert(0); - } -diff --git a/qapi/migration.json b/qapi/migration.json -index 94bc5c69d..bad53a2f8 100644 ---- a/qapi/migration.json -+++ b/qapi/migration.json -@@ -774,6 +774,15 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# (Since 4.2) -+# -+# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# (Since 4.2) -+# -+# @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in -+# base64 (Since 4.2) -+# - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. - # -@@ -794,7 +803,8 @@ - 'xbzrle-cache-size', 'max-postcopy-bandwidth', - 'max-cpu-throttle', 'multifd-compression', - 'multifd-zlib-level' ,'multifd-zstd-level', -- 'block-bitmap-mapping' ] } -+ 'block-bitmap-mapping', -+ 'sev-pdh', 'sev-plat-cert', 'sev-amd-cert' ] } - - ## - # @MigrateSetParameters: -@@ -939,6 +949,15 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# (Since 4.2) -+# -+# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# (Since 4.2) -+# -+# @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in -+# base64 (Since 4.2) -+# - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. - # -@@ -974,7 +993,10 @@ - '*multifd-compression': 'MultiFDCompression', - '*multifd-zlib-level': 'uint8', - '*multifd-zstd-level': 'uint8', -- '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } -+ '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ], -+ '*sev-pdh':'StrOrNull', -+ '*sev-plat-cert': 'StrOrNull', -+ '*sev-amd-cert' : 'StrOrNull' } } - - ## - # @migrate-set-parameters: -@@ -1139,6 +1161,15 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# (Since 4.2) -+# -+# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# (Since 4.2) -+# -+# @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in -+# base64 (Since 4.2) -+# - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. - # -@@ -1172,7 +1203,10 @@ - '*multifd-compression': 'MultiFDCompression', - '*multifd-zlib-level': 'uint8', - '*multifd-zstd-level': 'uint8', -- '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } -+ '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ], -+ '*sev-pdh':'str', -+ '*sev-plat-cert': 'str', -+ '*sev-amd-cert' : 'str'} } - - ## - # @query-migrate-parameters: --- -2.31.1 - diff --git a/1040-confidential-guest-support-introduce-ConfidentialGue.patch b/1040-confidential-guest-support-introduce-ConfidentialGue.patch deleted file mode 100644 index c76a7dcdbf7a2f1f78f9a7e0ab70068707d406cf..0000000000000000000000000000000000000000 --- a/1040-confidential-guest-support-introduce-ConfidentialGue.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 7b50e920f4faacb529a43230565ae9e022e61649 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 11:41:37 +0000 -Subject: [PATCH 03/29] confidential guest support: introduce - ConfidentialGuestMemoryEncryptionOps for encrypted VMs - -cherry-picked from https://github.com/AMDESE/qemu/commit/74fce7be9bd. - -When memory encryption is enabled in VM, the guest RAM will be encrypted -with the guest-specific key, to protect the confidentiality of data while -in transit we need to platform specific hooks to save or migrate the -guest RAM. - -Introduce the new ConfidentialGuestMemoryEncryptionOps in this patch -which will be later used by the encrypted guest for migration. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 27 +++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index ba2dd4b5d..343f686fc 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -53,8 +53,35 @@ struct ConfidentialGuestSupport { - bool ready; - }; - -+/** -+ * The functions registers with ConfidentialGuestMemoryEncryptionOps will be -+ * used during the encrypted guest migration. -+ */ -+struct ConfidentialGuestMemoryEncryptionOps { -+ /* Initialize the platform specific state before starting the migration */ -+ int (*save_setup)(const char *pdh, const char *plat_cert, -+ const char *amd_cert); -+ -+ /* Write the encrypted page and metadata associated with it */ -+ int (*save_outgoing_page)(QEMUFile *f, uint8_t *ptr, uint32_t size, -+ uint64_t *bytes_sent); -+ -+ /* Load the incoming encrypted page into guest memory */ -+ int (*load_incoming_page)(QEMUFile *f, uint8_t *ptr); -+ -+ /* Check if gfn is in shared/unencrypted region */ -+ bool (*is_gfn_in_unshared_region)(unsigned long gfn); -+ -+ /* Write the shared regions list */ -+ int (*save_outgoing_shared_regions_list)(QEMUFile *f); -+ -+ /* Load the shared regions list */ -+ int (*load_incoming_shared_regions_list)(QEMUFile *f); -+}; -+ - typedef struct ConfidentialGuestSupportClass { - ObjectClass parent; -+ struct ConfidentialGuestMemoryEncryptionOps *memory_encryption_ops; - } ConfidentialGuestSupportClass; - - #endif /* !CONFIG_USER_ONLY */ --- -2.31.1 - diff --git a/1041-target-i386-sev-provide-callback-to-setup-outgoing-c.patch b/1041-target-i386-sev-provide-callback-to-setup-outgoing-c.patch deleted file mode 100644 index f7c60e27f27c6ee986796d38fafb182e683be2b7..0000000000000000000000000000000000000000 --- a/1041-target-i386-sev-provide-callback-to-setup-outgoing-c.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 4e400056b6e3d895814d091da819ba742602581b Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 12:10:23 +0000 -Subject: [PATCH 04/29] target/i386: sev: provide callback to setup outgoing - context - -cherry-picked from https://github.com/AMDESE/qemu/commit/7521883afc0. - -The user provides the target machine's Platform Diffie-Hellman key (PDH) -and certificate chain before starting the SEV guest migration. Cache the -certificate chain as we need them while creating the outgoing context. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ - target/i386/sev.h | 2 ++ - 2 files changed, 61 insertions(+) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 36669bbdf..5dd6c0a3f 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -76,6 +76,12 @@ struct SevGuestState { - int sev_fd; - SevState state; - gchar *measurement; -+ guchar *remote_pdh; -+ size_t remote_pdh_len; -+ guchar *remote_plat_cert; -+ size_t remote_plat_cert_len; -+ guchar *amd_cert; -+ size_t amd_cert_len; - - uint32_t reset_cs; - uint32_t reset_ip; -@@ -160,6 +166,12 @@ static const char *const sev_fw_errlist[] = { - - #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist) - -+#define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */ -+ -+static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { -+ .save_setup = sev_save_setup, -+}; -+ - static int - sev_ioctl(int fd, int cmd, void *data, int *error) - { -@@ -872,6 +884,48 @@ sev_vm_state_change(void *opaque, bool running, RunState state) - } - } - -+static inline bool check_blob_length(size_t value) -+{ -+ if (value > SEV_FW_BLOB_MAX_SIZE) { -+ error_report("invalid length max=%d got=%ld", -+ SEV_FW_BLOB_MAX_SIZE, value); -+ return false; -+ } -+ -+ return true; -+} -+ -+int sev_save_setup(const char *pdh, const char *plat_cert, -+ const char *amd_cert) -+{ -+ SevGuestState *s = sev_guest; -+ -+ s->remote_pdh = g_base64_decode(pdh, &s->remote_pdh_len); -+ if (!check_blob_length(s->remote_pdh_len)) { -+ goto error; -+ } -+ -+ s->remote_plat_cert = g_base64_decode(plat_cert, -+ &s->remote_plat_cert_len); -+ if (!check_blob_length(s->remote_plat_cert_len)) { -+ goto error; -+ } -+ -+ s->amd_cert = g_base64_decode(amd_cert, &s->amd_cert_len); -+ if (!check_blob_length(s->amd_cert_len)) { -+ goto error; -+ } -+ -+ return 0; -+ -+error: -+ g_free(s->remote_pdh); -+ g_free(s->remote_plat_cert); -+ g_free(s->amd_cert); -+ -+ return 1; -+} -+ - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - { - SevGuestState *sev -@@ -886,6 +940,9 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - return 0; - } - -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(cgs)); -+ - ret = ram_block_discard_disable(true); - if (ret) { - error_report("%s: cannot disable RAM discard", __func__); -@@ -980,6 +1037,8 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - qemu_add_machine_init_done_notifier(&sev_machine_done_notify); - qemu_add_vm_change_state_handler(sev_vm_state_change, sev); - -+ cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; -+ - cgs->ready = true; - - return 0; -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 1c97bff99..14801ec44 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -51,6 +51,8 @@ extern uint32_t sev_get_reduced_phys_bits(void); - extern bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp); - - int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp); -+int sev_save_setup(const char *pdh, const char *plat_cert, -+ const char *amd_cert); - int sev_inject_launch_secret(const char *hdr, const char *secret, - uint64_t gpa, Error **errp); - --- -2.31.1 - diff --git a/1042-target-i386-sev-do-not-create-launch-context-for-an-.patch b/1042-target-i386-sev-do-not-create-launch-context-for-an-.patch deleted file mode 100644 index da664a3f08bc7b89cc27f3e6f4f59b0921b81b64..0000000000000000000000000000000000000000 --- a/1042-target-i386-sev-do-not-create-launch-context-for-an-.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 36b08d0392f2baec061e6fb90416db42dfad20f7 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 12:16:09 +0000 -Subject: [PATCH 05/29] target/i386: sev: do not create launch context for an - incoming guest - -cherry-picked from https://github.com/AMDESE/qemu/commit/b85694233495. - -The LAUNCH_START is used for creating an encryption context to encrypt -newly created guest, for an incoming guest the RECEIVE_START should be -used. - -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Brijesh Singh -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 5dd6c0a3f..fc8a2bb61 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -1024,10 +1024,16 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - } - } - -- ret = sev_launch_start(sev); -- if (ret) { -- error_setg(errp, "%s: failed to create encryption context", __func__); -- goto err; -+ /* -+ * The LAUNCH context is used for new guest, if its an incoming guest -+ * then RECEIVE context will be created after the connection is established. -+ */ -+ if (!runstate_check(RUN_STATE_INMIGRATE)) { -+ ret = sev_launch_start(sev); -+ if (ret) { -+ error_setg(errp, "%s: failed to create encryption context", __func__); -+ goto err; -+ } - } - - /* CSV guest needs no notifier to reg/unreg memory */ --- -2.31.1 - diff --git a/1043-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch b/1043-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch deleted file mode 100644 index f0a412a1bedbe3248da3954bdac6be6327853a01..0000000000000000000000000000000000000000 --- a/1043-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch +++ /dev/null @@ -1,324 +0,0 @@ -From 196380db46216f207e57b00e4bbc95178683d0cf Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 12:55:25 +0000 -Subject: [PATCH 06/29] target/i386: sev: add support to encrypt the outgoing - page - -cherry-picked from https://github.com/AMDESE/qemu/commit/5187c6f86bd. - -The sev_save_outgoing_page() provide the implementation to encrypt the -guest private pages during the transit. The routines uses the SEND_START -command to create the outgoing encryption context on the first call then -uses the SEND_UPDATE_DATA command to encrypt the data before writing it -to the socket. While encrypting the data SEND_UPDATE_DATA produces some -metadata (e.g MAC, IV). The metadata is also sent to the target machine. -After migration is completed, we issue the SEND_FINISH command to transition -the SEV guest state from sending to unrunnable state. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 221 +++++++++++++++++++++++++++++++++++++++ - target/i386/sev.h | 2 + - target/i386/trace-events | 3 + - 3 files changed, 226 insertions(+) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index fc8a2bb61..622150106 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -31,6 +31,8 @@ - #include "sysemu/runstate.h" - #include "trace.h" - #include "migration/blocker.h" -+#include "migration/qemu-file.h" -+#include "migration/misc.h" - #include "qom/object.h" - #include "monitor/monitor.h" - #include "monitor/hmp-target.h" -@@ -82,6 +84,8 @@ struct SevGuestState { - size_t remote_plat_cert_len; - guchar *amd_cert; - size_t amd_cert_len; -+ gchar *send_packet_hdr; -+ size_t send_packet_hdr_len; - - uint32_t reset_cs; - uint32_t reset_ip; -@@ -170,6 +174,7 @@ static const char *const sev_fw_errlist[] = { - - static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, -+ .save_outgoing_page = sev_save_outgoing_page, - }; - - static int -@@ -926,6 +931,40 @@ error: - return 1; - } - -+static void -+sev_send_finish(void) -+{ -+ int ret, error; -+ -+ trace_kvm_sev_send_finish(); -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_FINISH, 0, &error); -+ if (ret) { -+ error_report("%s: SEND_FINISH ret=%d fw_error=%d '%s'", -+ __func__, ret, error, fw_error_to_str(error)); -+ } -+ -+ g_free(sev_guest->send_packet_hdr); -+ sev_set_guest_state(sev_guest, SEV_STATE_RUNNING); -+} -+ -+static void -+sev_migration_state_notifier(Notifier *notifier, void *data) -+{ -+ MigrationState *s = data; -+ -+ if (migration_has_finished(s) || -+ migration_in_postcopy_after_devices(s) || -+ migration_has_failed(s)) { -+ if (sev_check_state(sev_guest, SEV_STATE_SEND_UPDATE)) { -+ sev_send_finish(); -+ } -+ } -+} -+ -+static Notifier sev_migration_state_notify = { -+ .notify = sev_migration_state_notifier, -+}; -+ - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - { - SevGuestState *sev -@@ -1042,6 +1081,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - } - qemu_add_machine_init_done_notifier(&sev_machine_done_notify); - qemu_add_vm_change_state_handler(sev_vm_state_change, sev); -+ add_migration_state_change_notifier(&sev_migration_state_notify); - - cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; - -@@ -1283,6 +1323,187 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size) - return 0; - } - -+static int -+sev_get_send_session_length(void) -+{ -+ int ret, fw_err = 0; -+ struct kvm_sev_send_start start = {}; -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_START, &start, &fw_err); -+ if (fw_err != SEV_RET_INVALID_LEN) { -+ ret = -1; -+ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_err, fw_error_to_str(fw_err)); -+ goto err; -+ } -+ -+ ret = start.session_len; -+err: -+ return ret; -+} -+ -+static int -+sev_send_start(SevGuestState *s, QEMUFile *f, uint64_t *bytes_sent) -+{ -+ gsize pdh_len = 0, plat_cert_len; -+ int session_len, ret, fw_error; -+ struct kvm_sev_send_start start = { }; -+ guchar *pdh = NULL, *plat_cert = NULL, *session = NULL; -+ Error *local_err = NULL; -+ -+ if (!s->remote_pdh || !s->remote_plat_cert || !s->amd_cert_len) { -+ error_report("%s: missing remote PDH or PLAT_CERT", __func__); -+ return 1; -+ } -+ -+ start.pdh_cert_uaddr = (uintptr_t) s->remote_pdh; -+ start.pdh_cert_len = s->remote_pdh_len; -+ -+ start.plat_certs_uaddr = (uintptr_t)s->remote_plat_cert; -+ start.plat_certs_len = s->remote_plat_cert_len; -+ -+ start.amd_certs_uaddr = (uintptr_t)s->amd_cert; -+ start.amd_certs_len = s->amd_cert_len; -+ -+ /* get the session length */ -+ session_len = sev_get_send_session_length(); -+ if (session_len < 0) { -+ ret = 1; -+ goto err; -+ } -+ -+ session = g_new0(guchar, session_len); -+ start.session_uaddr = (unsigned long)session; -+ start.session_len = session_len; -+ -+ /* Get our PDH certificate */ -+ ret = sev_get_pdh_info(s->sev_fd, &pdh, &pdh_len, -+ &plat_cert, &plat_cert_len, &local_err); -+ if (ret) { -+ error_report("Failed to get our PDH cert"); -+ goto err; -+ } -+ -+ trace_kvm_sev_send_start(start.pdh_cert_uaddr, start.pdh_cert_len, -+ start.plat_certs_uaddr, start.plat_certs_len, -+ start.amd_certs_uaddr, start.amd_certs_len); -+ -+ ret = sev_ioctl(s->sev_fd, KVM_SEV_SEND_START, &start, &fw_error); -+ if (ret < 0) { -+ error_report("%s: SEND_START ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ qemu_put_be32(f, start.policy); -+ qemu_put_be32(f, pdh_len); -+ qemu_put_buffer(f, (uint8_t *)pdh, pdh_len); -+ qemu_put_be32(f, start.session_len); -+ qemu_put_buffer(f, (uint8_t *)start.session_uaddr, start.session_len); -+ *bytes_sent = 12 + pdh_len + start.session_len; -+ -+ sev_set_guest_state(s, SEV_STATE_SEND_UPDATE); -+ -+err: -+ g_free(pdh); -+ g_free(plat_cert); -+ return ret; -+} -+ -+static int -+sev_send_get_packet_len(int *fw_err) -+{ -+ int ret; -+ struct kvm_sev_send_update_data update = { 0, }; -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_UPDATE_DATA, -+ &update, fw_err); -+ if (*fw_err != SEV_RET_INVALID_LEN) { -+ ret = -1; -+ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ goto err; -+ } -+ -+ ret = update.hdr_len; -+ -+err: -+ return ret; -+} -+ -+static int -+sev_send_update_data(SevGuestState *s, QEMUFile *f, uint8_t *ptr, uint32_t size, -+ uint64_t *bytes_sent) -+{ -+ int ret, fw_error; -+ guchar *trans; -+ struct kvm_sev_send_update_data update = { }; -+ -+ /* -+ * If this is first call then query the packet header bytes and allocate -+ * the packet buffer. -+ */ -+ if (!s->send_packet_hdr) { -+ s->send_packet_hdr_len = sev_send_get_packet_len(&fw_error); -+ if (s->send_packet_hdr_len < 1) { -+ error_report("%s: SEND_UPDATE fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ -+ s->send_packet_hdr = g_new(gchar, s->send_packet_hdr_len); -+ } -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, size); -+ -+ update.hdr_uaddr = (uintptr_t)s->send_packet_hdr; -+ update.hdr_len = s->send_packet_hdr_len; -+ update.guest_uaddr = (uintptr_t)ptr; -+ update.guest_len = size; -+ update.trans_uaddr = (uintptr_t)trans; -+ update.trans_len = size; -+ -+ trace_kvm_sev_send_update_data(ptr, trans, size); -+ -+ ret = sev_ioctl(s->sev_fd, KVM_SEV_SEND_UPDATE_DATA, &update, &fw_error); -+ if (ret) { -+ error_report("%s: SEND_UPDATE_DATA ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ qemu_put_be32(f, update.hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); -+ *bytes_sent = 4 + update.hdr_len; -+ -+ qemu_put_be32(f, update.trans_len); -+ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ *bytes_sent += (4 + update.trans_len); -+ -+err: -+ g_free(trans); -+ return ret; -+} -+ -+int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, -+ uint32_t sz, uint64_t *bytes_sent) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* -+ * If this is a first buffer then create outgoing encryption context -+ * and write our PDH, policy and session data. -+ */ -+ if (!sev_check_state(s, SEV_STATE_SEND_UPDATE) && -+ sev_send_start(s, f, bytes_sent)) { -+ error_report("Failed to create outgoing context"); -+ return 1; -+ } -+ -+ return sev_send_update_data(s, f, ptr, sz, bytes_sent); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 14801ec44..19d3136dd 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -53,6 +53,8 @@ extern bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **er - int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp); - int sev_save_setup(const char *pdh, const char *plat_cert, - const char *amd_cert); -+int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, -+ uint32_t size, uint64_t *bytes_sent); - int sev_inject_launch_secret(const char *hdr, const char *secret, - uint64_t gpa, Error **errp); - -diff --git a/target/i386/trace-events b/target/i386/trace-events -index b7da9bd74..c165e3737 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -11,6 +11,9 @@ kvm_sev_launch_measurement(const char *value) "data %s" - kvm_sev_launch_finish(void) "" - kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d" - kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s" -+kvm_sev_send_start(uint64_t pdh, int l1, uint64_t plat, int l2, uint64_t amd, int l3) "pdh 0x%" PRIx64 " len %d plat 0x%" PRIx64 " len %d amd 0x%" PRIx64 " len %d" -+kvm_sev_send_update_data(void *src, void *dst, int len) "guest %p trans %p len %d" -+kvm_sev_send_finish(void) "" - - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 --- -2.31.1 - diff --git a/1044-target-i386-sev-add-support-to-load-incoming-encrypt.patch b/1044-target-i386-sev-add-support-to-load-incoming-encrypt.patch deleted file mode 100644 index cf10880f4f496086547e9a234f48925431b51e3a..0000000000000000000000000000000000000000 --- a/1044-target-i386-sev-add-support-to-load-incoming-encrypt.patch +++ /dev/null @@ -1,224 +0,0 @@ -From 10e03772a0a14f65602c496d65a4392b5b70da51 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 13:00:50 +0000 -Subject: [PATCH 07/29] target/i386: sev: add support to load incoming - encrypted page - -cherry-picked from https://github.com/AMDESE/qemu/commit/e86e5dccb045. - -The sev_load_incoming_page() provide the implementation to read the -incoming guest private pages from the socket and load it into the guest -memory. The routines uses the RECEIVE_START command to create the -incoming encryption context on the first call then uses the -RECEIEVE_UPDATE_DATA command to load the encrypted pages into the guest -memory. After migration is completed, we issue the RECEIVE_FINISH command -to transition the SEV guest to the runnable state so that it can be -executed. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 137 ++++++++++++++++++++++++++++++++++++++- - target/i386/sev.h | 1 + - target/i386/trace-events | 3 + - 3 files changed, 140 insertions(+), 1 deletion(-) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 622150106..bdd77fd0e 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -175,6 +175,7 @@ static const char *const sev_fw_errlist[] = { - static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = sev_save_outgoing_page, -+ .load_incoming_page = sev_load_incoming_page, - }; - - static int -@@ -877,13 +878,33 @@ sev_launch_finish(SevGuestState *sev) - migrate_add_blocker(sev_mig_blocker, &error_fatal); - } - -+static int -+sev_receive_finish(SevGuestState *s) -+{ -+ int error, ret = 1; -+ -+ trace_kvm_sev_receive_finish(); -+ ret = sev_ioctl(s->sev_fd, KVM_SEV_RECEIVE_FINISH, 0, &error); -+ if (ret) { -+ error_report("%s: RECEIVE_FINISH ret=%d fw_error=%d '%s'", -+ __func__, ret, error, fw_error_to_str(error)); -+ goto err; -+ } -+ -+ sev_set_guest_state(s, SEV_STATE_RUNNING); -+err: -+ return ret; -+} -+ - static void - sev_vm_state_change(void *opaque, bool running, RunState state) - { - SevGuestState *sev = opaque; - - if (running) { -- if (!sev_check_state(sev, SEV_STATE_RUNNING)) { -+ if (sev_check_state(sev, SEV_STATE_RECEIVE_UPDATE)) { -+ sev_receive_finish(sev); -+ } else if (!sev_check_state(sev, SEV_STATE_RUNNING)) { - sev_launch_finish(sev); - } - } -@@ -1504,6 +1525,120 @@ int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, - return sev_send_update_data(s, f, ptr, sz, bytes_sent); - } - -+static int -+sev_receive_start(SevGuestState *sev, QEMUFile *f) -+{ -+ int ret = 1; -+ int fw_error; -+ struct kvm_sev_receive_start start = { }; -+ gchar *session = NULL, *pdh_cert = NULL; -+ -+ /* get SEV guest handle */ -+ start.handle = object_property_get_int(OBJECT(sev), "handle", -+ &error_abort); -+ -+ /* get the source policy */ -+ start.policy = qemu_get_be32(f); -+ -+ /* get source PDH key */ -+ start.pdh_len = qemu_get_be32(f); -+ if (!check_blob_length(start.pdh_len)) { -+ return 1; -+ } -+ -+ pdh_cert = g_new(gchar, start.pdh_len); -+ qemu_get_buffer(f, (uint8_t *)pdh_cert, start.pdh_len); -+ start.pdh_uaddr = (uintptr_t)pdh_cert; -+ -+ /* get source session data */ -+ start.session_len = qemu_get_be32(f); -+ if (!check_blob_length(start.session_len)) { -+ return 1; -+ } -+ session = g_new(gchar, start.session_len); -+ qemu_get_buffer(f, (uint8_t *)session, start.session_len); -+ start.session_uaddr = (uintptr_t)session; -+ -+ trace_kvm_sev_receive_start(start.policy, session, pdh_cert); -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_RECEIVE_START, -+ &start, &fw_error); -+ if (ret < 0) { -+ error_report("Error RECEIVE_START ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ object_property_set_int(OBJECT(sev), "handle", start.handle, &error_abort); -+ sev_set_guest_state(sev, SEV_STATE_RECEIVE_UPDATE); -+err: -+ g_free(session); -+ g_free(pdh_cert); -+ -+ return ret; -+} -+ -+static int sev_receive_update_data(QEMUFile *f, uint8_t *ptr) -+{ -+ int ret = 1, fw_error = 0; -+ gchar *hdr = NULL, *trans = NULL; -+ struct kvm_sev_receive_update_data update = {}; -+ -+ /* get packet header */ -+ update.hdr_len = qemu_get_be32(f); -+ if (!check_blob_length(update.hdr_len)) { -+ return 1; -+ } -+ -+ hdr = g_new(gchar, update.hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); -+ update.hdr_uaddr = (uintptr_t)hdr; -+ -+ /* get transport buffer */ -+ update.trans_len = qemu_get_be32(f); -+ if (!check_blob_length(update.trans_len)) { -+ goto err; -+ } -+ -+ trans = g_new(gchar, update.trans_len); -+ update.trans_uaddr = (uintptr_t)trans; -+ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+ update.guest_uaddr = (uintptr_t) ptr; -+ update.guest_len = update.trans_len; -+ -+ trace_kvm_sev_receive_update_data(trans, ptr, update.guest_len, -+ hdr, update.hdr_len); -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_RECEIVE_UPDATE_DATA, -+ &update, &fw_error); -+ if (ret) { -+ error_report("Error RECEIVE_UPDATE_DATA ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+err: -+ g_free(trans); -+ g_free(hdr); -+ return ret; -+} -+ -+int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* -+ * If this is first buffer and SEV is not in recieiving state then -+ * use RECEIVE_START command to create a encryption context. -+ */ -+ if (!sev_check_state(s, SEV_STATE_RECEIVE_UPDATE) && -+ sev_receive_start(s, f)) { -+ return 1; -+ } -+ -+ return sev_receive_update_data(f, ptr); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 19d3136dd..1040b0cb2 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -55,6 +55,7 @@ int sev_save_setup(const char *pdh, const char *plat_cert, - const char *amd_cert); - int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, - uint32_t size, uint64_t *bytes_sent); -+int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr); - int sev_inject_launch_secret(const char *hdr, const char *secret, - uint64_t gpa, Error **errp); - -diff --git a/target/i386/trace-events b/target/i386/trace-events -index c165e3737..e32b0319b 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -14,6 +14,9 @@ kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data - kvm_sev_send_start(uint64_t pdh, int l1, uint64_t plat, int l2, uint64_t amd, int l3) "pdh 0x%" PRIx64 " len %d plat 0x%" PRIx64 " len %d amd 0x%" PRIx64 " len %d" - kvm_sev_send_update_data(void *src, void *dst, int len) "guest %p trans %p len %d" - kvm_sev_send_finish(void) "" -+kvm_sev_receive_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p" -+kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_len) "guest %p trans %p len %d hdr %p hdr_len %d" -+kvm_sev_receive_finish(void) "" - - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 --- -2.31.1 - diff --git a/1045-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch b/1045-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch deleted file mode 100644 index 27daa6b4a3e53ba382064110007e3099d34e11cf..0000000000000000000000000000000000000000 --- a/1045-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch +++ /dev/null @@ -1,293 +0,0 @@ -From da756577d513a92fdfd4c1bdda3961dc704ccf12 Mon Sep 17 00:00:00 2001 -From: Ashish Kalra -Date: Tue, 27 Jul 2021 15:05:49 +0000 -Subject: [PATCH 08/29] kvm: Add support for SEV shared regions list and - KVM_EXIT_HYPERCALL. - -cherry-picked from https://github.com/AMDESE/qemu/commit/fcbbd9b19ac. - -KVM_HC_MAP_GPA_RANGE hypercall is used by the SEV guest to notify a -change in the page encryption status to the hypervisor. The hypercall -should be invoked only when the encryption attribute is changed from -encrypted -> decrypted and vice versa. By default all guest pages are -considered encrypted. - -The hypercall exits to userspace with KVM_EXIT_HYPERCALL exit code, -currently this is used only by SEV guests for guest page encryptiion -status tracking. Add support to handle this exit and invoke SEV -shared regions list handlers. - -Add support for SEV guest shared regions and implementation of the -SEV shared regions list. - -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - linux-headers/linux/kvm.h | 3 ++ - target/i386/kvm/kvm.c | 48 +++++++++++++++++ - target/i386/sev.c | 105 ++++++++++++++++++++++++++++++++++++++ - target/i386/sev.h | 3 ++ - 4 files changed, 159 insertions(+) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 3bc062a18..b640e72c8 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -344,6 +344,7 @@ struct kvm_run { - } mmio; - /* KVM_EXIT_HYPERCALL */ - struct { -+#define KVM_HC_MAP_GPA_RANGE 12 - __u64 nr; - __u64 args[6]; - __u64 ret; -@@ -1154,6 +1155,8 @@ struct kvm_ppc_resize_hpt { - #define KVM_CAP_S390_ZPCI_OP 221 - #define KVM_CAP_S390_CPU_TOPOLOGY 222 - -+#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) -+ - #ifdef KVM_CAP_IRQ_ROUTING - - struct kvm_irq_routing_irqchip { -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index a06221d3e..5262806c4 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -127,6 +127,7 @@ static int has_xsave2; - static int has_xcrs; - static int has_pit_state2; - static int has_exception_payload; -+static int has_map_gpa_range; - - static bool has_msr_mcg_ext_ctl; - -@@ -2052,6 +2053,17 @@ int kvm_arch_init_vcpu(CPUState *cs) - c->eax = MAX(c->eax, KVM_CPUID_SIGNATURE | 0x10); - } - -+ if (sev_enabled()) { -+ c = cpuid_find_entry(&cpuid_data.cpuid, -+ KVM_CPUID_FEATURES | kvm_base, 0); -+ if (c) { -+ c->eax |= (1 << KVM_FEATURE_MIGRATION_CONTROL); -+ if (has_map_gpa_range) { -+ c->eax |= (1 << KVM_FEATURE_HC_MAP_GPA_RANGE); -+ } -+ } -+ } -+ - cpuid_data.cpuid.nent = cpuid_i; - - cpuid_data.cpuid.padding = 0; -@@ -2397,6 +2409,17 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - } - } - -+ has_map_gpa_range = kvm_check_extension(s, KVM_CAP_EXIT_HYPERCALL); -+ if (has_map_gpa_range) { -+ ret = kvm_vm_enable_cap(s, KVM_CAP_EXIT_HYPERCALL, 0, -+ KVM_EXIT_HYPERCALL_VALID_MASK); -+ if (ret < 0) { -+ error_report("kvm: Failed to enable MAP_GPA_RANGE cap: %s", -+ strerror(-ret)); -+ return ret; -+ } -+ } -+ - ret = kvm_get_supported_msrs(s); - if (ret < 0) { - return ret; -@@ -4612,6 +4635,28 @@ static int kvm_handle_tpr_access(X86CPU *cpu) - return 1; - } - -+static int kvm_handle_exit_hypercall(X86CPU *cpu, struct kvm_run *run) -+{ -+ /* -+ * Currently this exit is only used by SEV guests for -+ * guest page encryption status tracking. -+ */ -+ if (run->hypercall.nr == KVM_HC_MAP_GPA_RANGE) { -+ unsigned long enc = run->hypercall.args[2]; -+ unsigned long gpa = run->hypercall.args[0]; -+ unsigned long npages = run->hypercall.args[1]; -+ unsigned long gfn_start = gpa >> TARGET_PAGE_BITS; -+ unsigned long gfn_end = gfn_start + npages; -+ -+ if (enc) { -+ sev_remove_shared_regions_list(gfn_start, gfn_end); -+ } else { -+ sev_add_shared_regions_list(gfn_start, gfn_end); -+ } -+ } -+ return 0; -+} -+ - int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) - { - static const uint8_t int3 = 0xcc; -@@ -4902,6 +4947,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) - /* already handled in kvm_arch_post_run */ - ret = 0; - break; -+ case KVM_EXIT_HYPERCALL: -+ ret = kvm_handle_exit_hypercall(cpu, run); -+ break; - default: - fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); - ret = -1; -diff --git a/target/i386/sev.c b/target/i386/sev.c -index bdd77fd0e..de57b0a27 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -45,6 +45,10 @@ - #define TYPE_SEV_GUEST "sev-guest" - OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST) - -+struct shared_region { -+ unsigned long gfn_start, gfn_end; -+ QTAILQ_ENTRY(shared_region) list; -+}; - - extern struct sev_ops sev_ops; - -@@ -90,6 +94,8 @@ struct SevGuestState { - uint32_t reset_cs; - uint32_t reset_ip; - bool reset_data_valid; -+ -+ QTAILQ_HEAD(, shared_region) shared_regions_list; - }; - - #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ -@@ -1105,6 +1111,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - add_migration_state_change_notifier(&sev_migration_state_notify); - - cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; -+ QTAILQ_INIT(&sev->shared_regions_list); - - cgs->ready = true; - -@@ -1639,6 +1646,104 @@ int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) - return sev_receive_update_data(f, ptr); - } - -+int sev_remove_shared_regions_list(unsigned long start, unsigned long end) -+{ -+ SevGuestState *s = sev_guest; -+ struct shared_region *pos; -+ -+ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ unsigned long l, r; -+ unsigned long curr_gfn_end = pos->gfn_end; -+ -+ /* -+ * Find if any intersection exists ? -+ * left bound for intersecting segment -+ */ -+ l = MAX(start, pos->gfn_start); -+ /* right bound for intersecting segment */ -+ r = MIN(end, pos->gfn_end); -+ if (l <= r) { -+ if (pos->gfn_start == l && pos->gfn_end == r) { -+ QTAILQ_REMOVE(&s->shared_regions_list, pos, list); -+ } else if (l == pos->gfn_start) { -+ pos->gfn_start = r; -+ } else if (r == pos->gfn_end) { -+ pos->gfn_end = l; -+ } else { -+ /* Do a de-merge -- split linked list nodes */ -+ struct shared_region *shrd_region; -+ -+ pos->gfn_end = l; -+ shrd_region = g_malloc0(sizeof(*shrd_region)); -+ if (!shrd_region) { -+ return 0; -+ } -+ shrd_region->gfn_start = r; -+ shrd_region->gfn_end = curr_gfn_end; -+ QTAILQ_INSERT_AFTER(&s->shared_regions_list, pos, -+ shrd_region, list); -+ } -+ } -+ if (end <= curr_gfn_end) { -+ break; -+ } -+ } -+ return 0; -+} -+ -+int sev_add_shared_regions_list(unsigned long start, unsigned long end) -+{ -+ struct shared_region *shrd_region; -+ struct shared_region *pos; -+ SevGuestState *s = sev_guest; -+ -+ if (QTAILQ_EMPTY(&s->shared_regions_list)) { -+ shrd_region = g_malloc0(sizeof(*shrd_region)); -+ if (!shrd_region) { -+ return -1; -+ } -+ shrd_region->gfn_start = start; -+ shrd_region->gfn_end = end; -+ QTAILQ_INSERT_TAIL(&s->shared_regions_list, shrd_region, list); -+ return 0; -+ } -+ -+ /* -+ * shared regions list is a sorted list in ascending order -+ * of guest PA's and also merges consecutive range of guest PA's -+ */ -+ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ /* handle duplicate overlapping regions */ -+ if (start >= pos->gfn_start && end <= pos->gfn_end) { -+ return 0; -+ } -+ if (pos->gfn_end < start) { -+ continue; -+ } -+ /* merge consecutive guest PA(s) -- forward merge */ -+ if (pos->gfn_start <= start && pos->gfn_end >= start) { -+ pos->gfn_end = end; -+ return 0; -+ } -+ break; -+ } -+ /* -+ * Add a new node -+ */ -+ shrd_region = g_malloc0(sizeof(*shrd_region)); -+ if (!shrd_region) { -+ return -1; -+ } -+ shrd_region->gfn_start = start; -+ shrd_region->gfn_end = end; -+ if (pos) { -+ QTAILQ_INSERT_BEFORE(pos, shrd_region, list); -+ } else { -+ QTAILQ_INSERT_TAIL(&s->shared_regions_list, shrd_region, list); -+ } -+ return 1; -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 1040b0cb2..8423b5522 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -61,6 +61,9 @@ int sev_inject_launch_secret(const char *hdr, const char *secret, - - int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size); - void sev_es_set_reset_vector(CPUState *cpu); -+int sev_remove_shared_regions_list(unsigned long gfn_start, -+ unsigned long gfn_end); -+int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - --- -2.31.1 - diff --git a/1046-migration-add-support-to-migrate-shared-regions-list.patch b/1046-migration-add-support-to-migrate-shared-regions-list.patch deleted file mode 100644 index 72e8cbe7d0a7e92ca524e40c7b0b31bb10aa55be..0000000000000000000000000000000000000000 --- a/1046-migration-add-support-to-migrate-shared-regions-list.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 9f9b6fbfc4cf9f73a001686954d34c40b29e3538 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 16:31:36 +0000 -Subject: [PATCH 09/29] migration: add support to migrate shared regions list - -cherry-picked from https://github.com/AMDESE/qemu/commit/9236f522e48b6. - -When memory encryption is enabled, the hypervisor maintains a shared -regions list which is referred by hypervisor during migration to check -if page is private or shared. This list is built during the VM bootup and -must be migrated to the target host so that hypervisor on target host can -use it for future migration. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/sev.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - target/i386/sev.h | 2 ++ - 2 files changed, 45 insertions(+) - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index de57b0a27..30cd436ab 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -178,10 +178,15 @@ static const char *const sev_fw_errlist[] = { - - #define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */ - -+#define SHARED_REGION_LIST_CONT 0x1 -+#define SHARED_REGION_LIST_END 0x2 -+ - static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = sev_save_outgoing_page, - .load_incoming_page = sev_load_incoming_page, -+ .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, -+ .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - }; - - static int -@@ -1744,6 +1749,44 @@ int sev_add_shared_regions_list(unsigned long start, unsigned long end) - return 1; - } - -+int sev_save_outgoing_shared_regions_list(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ struct shared_region *pos; -+ -+ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ qemu_put_be32(f, SHARED_REGION_LIST_CONT); -+ qemu_put_be32(f, pos->gfn_start); -+ qemu_put_be32(f, pos->gfn_end); -+ } -+ -+ qemu_put_be32(f, SHARED_REGION_LIST_END); -+ return 0; -+} -+ -+int sev_load_incoming_shared_regions_list(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ struct shared_region *shrd_region; -+ int status; -+ -+ status = qemu_get_be32(f); -+ while (status == SHARED_REGION_LIST_CONT) { -+ -+ shrd_region = g_malloc0(sizeof(*shrd_region)); -+ if (!shrd_region) { -+ return 0; -+ } -+ shrd_region->gfn_start = qemu_get_be32(f); -+ shrd_region->gfn_end = qemu_get_be32(f); -+ -+ QTAILQ_INSERT_TAIL(&s->shared_regions_list, shrd_region, list); -+ -+ status = qemu_get_be32(f); -+ } -+ return 0; -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 8423b5522..34814b9f2 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -64,6 +64,8 @@ void sev_es_set_reset_vector(CPUState *cpu); - int sev_remove_shared_regions_list(unsigned long gfn_start, - unsigned long gfn_end); - int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); -+int sev_save_outgoing_shared_regions_list(QEMUFile *f); -+int sev_load_incoming_shared_regions_list(QEMUFile *f); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - --- -2.31.1 - diff --git a/1047-migration-ram-add-support-to-send-encrypted-pages.patch b/1047-migration-ram-add-support-to-send-encrypted-pages.patch deleted file mode 100644 index 42223d6b7d6fe6c08de040212718b9579dc7ec14..0000000000000000000000000000000000000000 --- a/1047-migration-ram-add-support-to-send-encrypted-pages.patch +++ /dev/null @@ -1,338 +0,0 @@ -From a973e7ee1489c9ee089f8c502f9b10f5ca4a4772 Mon Sep 17 00:00:00 2001 -From: Brijesh Singh -Date: Tue, 27 Jul 2021 16:53:19 +0000 -Subject: [PATCH 10/29] migration/ram: add support to send encrypted pages - -cherry-picked from https://github.com/AMDESE/qemu/commit/2d6bda0d4cf. - -When memory encryption is enabled, the guest memory will be encrypted with -the guest specific key. The patch introduces RAM_SAVE_FLAG_ENCRYPTED_PAGE -flag to distinguish the encrypted data from plaintext. Encrypted pages -may need special handling. The sev_save_outgoing_page() is used -by the sender to write the encrypted pages onto the socket, similarly the -sev_load_incoming_page() is used by the target to read the -encrypted pages from the socket and load into the guest memory. - -Signed-off-by: Brijesh Singh -Co-developed-by: Ashish Kalra -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - migration/migration.h | 2 + - migration/ram.c | 163 +++++++++++++++++++++++++++++++++++++++++- - target/i386/sev.c | 14 ++++ - target/i386/sev.h | 4 ++ - 4 files changed, 182 insertions(+), 1 deletion(-) - -diff --git a/migration/migration.h b/migration/migration.h -index 0ae213332..596668d80 100644 ---- a/migration/migration.h -+++ b/migration/migration.h -@@ -403,4 +403,6 @@ void migration_cancel(const Error *error); - - void populate_vfio_info(MigrationInfo *info); - -+bool memcrypt_enabled(void); -+ - #endif -diff --git a/migration/ram.c b/migration/ram.c -index 93cdb456a..57f2c01bf 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -55,6 +55,10 @@ - #include "qemu/iov.h" - #include "multifd.h" - #include "sysemu/runstate.h" -+#include "exec/confidential-guest-support.h" -+ -+/* Defines RAM_SAVE_ENCRYPTED_PAGE and RAM_SAVE_SHARED_REGION_LIST */ -+#include "target/i386/sev.h" - - #include "hw/boards.h" /* for machine_dump_guest_core() */ - -@@ -80,6 +84,16 @@ - #define RAM_SAVE_FLAG_XBZRLE 0x40 - /* 0x80 is reserved in migration.h start with 0x100 next */ - #define RAM_SAVE_FLAG_COMPRESS_PAGE 0x100 -+#define RAM_SAVE_FLAG_ENCRYPTED_DATA 0x200 -+ -+bool memcrypt_enabled(void) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ if(ms->cgs) -+ return ms->cgs->ready; -+ else -+ return false; -+} - - static inline bool is_zero_range(uint8_t *p, uint64_t size) - { -@@ -468,6 +482,8 @@ static QemuCond decomp_done_cond; - - static bool do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block, - ram_addr_t offset, uint8_t *source_buf); -+static int ram_save_encrypted_page(RAMState *rs, PageSearchStatus *pss, -+ bool last_stage); - - static void *do_data_compress(void *opaque) - { -@@ -1301,6 +1317,80 @@ static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, - return 1; - } - -+/** -+ * ram_save_encrypted_page - send the given encrypted page to the stream -+ */ -+static int ram_save_encrypted_page(RAMState *rs, PageSearchStatus *pss, -+ bool last_stage) -+{ -+ int ret; -+ uint8_t *p; -+ RAMBlock *block = pss->block; -+ ram_addr_t offset = pss->page << TARGET_PAGE_BITS; -+ uint64_t bytes_xmit; -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ p = block->host + offset; -+ -+ ram_counters.transferred += -+ save_page_header(rs, rs->f, block, -+ offset | RAM_SAVE_FLAG_ENCRYPTED_DATA); -+ -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_PAGE); -+ ret = ops->save_outgoing_page(rs->f, p, TARGET_PAGE_SIZE, &bytes_xmit); -+ if (ret) { -+ return -1; -+ } -+ -+ ram_counters.transferred += bytes_xmit; -+ ram_counters.normal++; -+ -+ return 1; -+} -+ -+/** -+ * ram_save_shared_region_list: send the shared region list -+ */ -+static int ram_save_shared_region_list(RAMState *rs, QEMUFile *f) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ save_page_header(rs, rs->f, rs->last_seen_block, -+ RAM_SAVE_FLAG_ENCRYPTED_DATA); -+ qemu_put_be32(rs->f, RAM_SAVE_SHARED_REGIONS_LIST); -+ return ops->save_outgoing_shared_regions_list(rs->f); -+} -+ -+static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ int flag; -+ -+ flag = qemu_get_be32(f); -+ -+ if (flag == RAM_SAVE_ENCRYPTED_PAGE) { -+ return ops->load_incoming_page(f, ptr); -+ } else if (flag == RAM_SAVE_SHARED_REGIONS_LIST) { -+ return ops->load_incoming_shared_regions_list(f); -+ } else { -+ error_report("unknown encrypted flag %x", flag); -+ return 1; -+ } -+} -+ - /** - * ram_save_page: send the given page to the stream - * -@@ -2144,6 +2234,35 @@ static bool save_compress_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) - return false; - } - -+/** -+ * encrypted_test_list: check if the page is encrypted -+ * -+ * Returns a bool indicating whether the page is encrypted. -+ */ -+static bool encrypted_test_list(RAMState *rs, RAMBlock *block, -+ unsigned long page) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ unsigned long gfn; -+ -+ /* ROM devices contains the unencrypted data */ -+ if (memory_region_is_rom(block->mr)) { -+ return false; -+ } -+ -+ /* -+ * Translate page in ram_addr_t address space to GPA address -+ * space using memory region. -+ */ -+ gfn = page + (block->mr->addr >> TARGET_PAGE_BITS); -+ -+ return ops->is_gfn_in_unshared_region(gfn); -+} -+ - /** - * ram_save_target_page: save one target page - * -@@ -2164,6 +2283,17 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, - return res; - } - -+ /* -+ * If memory encryption is enabled then use memory encryption APIs -+ * to write the outgoing buffer to the wire. The encryption APIs -+ * will take care of accessing the guest memory and re-encrypt it -+ * for the transport purposes. -+ */ -+ if (memcrypt_enabled() && -+ encrypted_test_list(rs, pss->block, pss->page)) { -+ return ram_save_encrypted_page(rs, pss, last_stage); -+ } -+ - if (save_compress_page(rs, block, offset)) { - return 1; - } -@@ -2990,6 +3120,18 @@ void qemu_guest_free_page_hint(void *addr, size_t len) - } - } - -+static int ram_encrypted_save_setup(void) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ MigrationParameters *p = &migrate_get_current()->parameters; -+ -+ return ops->save_setup(p->sev_pdh, p->sev_plat_cert, p->sev_amd_cert); -+} -+ - /* - * Each of ram_save_setup, ram_save_iterate and ram_save_complete has - * long-running RCU critical section. When rcu-reclaims in the code -@@ -3025,6 +3167,13 @@ static int ram_save_setup(QEMUFile *f, void *opaque) - (*rsp)->f = f; - - WITH_RCU_READ_LOCK_GUARD() { -+ -+ if (memcrypt_enabled()) { -+ if (ram_encrypted_save_setup()) { -+ return -1; -+ } -+ } -+ - qemu_put_be64(f, ram_bytes_total_common(true) | RAM_SAVE_FLAG_MEM_SIZE); - - RAMBLOCK_FOREACH_MIGRATABLE(block) { -@@ -3217,6 +3366,11 @@ static int ram_save_complete(QEMUFile *f, void *opaque) - - flush_compressed_data(rs); - ram_control_after_iterate(f, RAM_CONTROL_FINISH); -+ -+ /* send the shared regions list */ -+ if (memcrypt_enabled()) { -+ ret = ram_save_shared_region_list(rs, f); -+ } - } - - if (ret < 0) { -@@ -4038,7 +4192,8 @@ static int ram_load_precopy(QEMUFile *f) - } - - if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE | -- RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE)) { -+ RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE | -+ RAM_SAVE_FLAG_ENCRYPTED_DATA)) { - RAMBlock *block = ram_block_from_stream(f, flags); - - host = host_from_ram_block_offset(block, addr); -@@ -4167,6 +4322,12 @@ static int ram_load_precopy(QEMUFile *f) - break; - } - break; -+ case RAM_SAVE_FLAG_ENCRYPTED_DATA: -+ if (load_encrypted_data(f, host)) { -+ error_report("Failed to load encrypted data"); -+ ret = -EINVAL; -+ } -+ break; - case RAM_SAVE_FLAG_EOS: - /* normal exit */ - multifd_recv_sync_main(); -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 30cd436ab..cc63a1aef 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -185,6 +185,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = sev_save_outgoing_page, - .load_incoming_page = sev_load_incoming_page, -+ .is_gfn_in_unshared_region = sev_is_gfn_in_unshared_region, - .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - }; -@@ -1787,6 +1788,19 @@ int sev_load_incoming_shared_regions_list(QEMUFile *f) - return 0; - } - -+bool sev_is_gfn_in_unshared_region(unsigned long gfn) -+{ -+ SevGuestState *s = sev_guest; -+ struct shared_region *pos; -+ -+ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ if (gfn >= pos->gfn_start && gfn < pos->gfn_end) { -+ return false; -+ } -+ } -+ return true; -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 34814b9f2..b8ad84014 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -38,6 +38,9 @@ typedef struct SevKernelLoaderContext { - size_t cmdline_size; - } SevKernelLoaderContext; - -+#define RAM_SAVE_ENCRYPTED_PAGE 0x1 -+#define RAM_SAVE_SHARED_REGIONS_LIST 0x2 -+ - #ifdef CONFIG_SEV - bool sev_enabled(void); - bool sev_es_enabled(void); -@@ -66,6 +69,7 @@ int sev_remove_shared_regions_list(unsigned long gfn_start, - int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); - int sev_save_outgoing_shared_regions_list(QEMUFile *f); - int sev_load_incoming_shared_regions_list(QEMUFile *f); -+bool sev_is_gfn_in_unshared_region(unsigned long gfn); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - --- -2.31.1 - diff --git a/1048-migration-ram-Force-encrypted-status-for-flash0-flas.patch b/1048-migration-ram-Force-encrypted-status-for-flash0-flas.patch deleted file mode 100644 index 8202afc3cf26d55da3f0e4570327b34be7cd8571..0000000000000000000000000000000000000000 --- a/1048-migration-ram-Force-encrypted-status-for-flash0-flas.patch +++ /dev/null @@ -1,44 +0,0 @@ -From aae5a6ae741a985ff74b0ae7540d3c6ce3ef2fd0 Mon Sep 17 00:00:00 2001 -From: Ashish Kalra -Date: Tue, 27 Jul 2021 18:05:25 +0000 -Subject: [PATCH 11/29] migration/ram: Force encrypted status for flash0 & - flash1 devices. - -cherry-picked from https://github.com/AMDESE/qemu/commit/803d6a4c8d. - -Currently OVMF clears the C-bit and marks NonExistent memory space -as decrypted in the page encryption bitmap. By marking the -NonExistent memory space as decrypted it gurantees any future MMIO adds -will work correctly, but this marks flash0 device space as decrypted. -At reset the SEV core will be in forced encrypted state, so this -decrypted marking of flash0 device space will cause VCPU reset to fail -as flash0 device pages will be migrated incorrectly. - -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - migration/ram.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 57f2c01bf..da7a80994 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -2254,6 +2254,14 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, - return false; - } - -+ if (!strcmp(memory_region_name(block->mr), "system.flash0")) { -+ return true; -+ } -+ -+ if (!strcmp(memory_region_name(block->mr), "system.flash1")) { -+ return false; -+ } -+ - /* - * Translate page in ram_addr_t address space to GPA address - * space using memory region. --- -2.31.1 - diff --git a/1049-migration-for-SEV-live-migration-bump-downtime-limit.patch b/1049-migration-for-SEV-live-migration-bump-downtime-limit.patch deleted file mode 100644 index 70e9213e42c607b79906296778f6a28e666dff31..0000000000000000000000000000000000000000 --- a/1049-migration-for-SEV-live-migration-bump-downtime-limit.patch +++ /dev/null @@ -1,64 +0,0 @@ -From a102d449e9601125c226cf40bc57b705bd1e3c28 Mon Sep 17 00:00:00 2001 -From: Ashish Kalra -Date: Tue, 3 Aug 2021 16:06:27 +0000 -Subject: [PATCH 12/29] migration: for SEV live migration bump downtime limit - to 1s. - -cherry-picked from https://github.com/AMDESE/qemu/commit/b1468803a2200. - -Now, qemu has a default expected downtime of 300 ms and -SEV Live migration has a page-per-second bandwidth of 350-450 pages -( SEV Live migration being generally slow due to guest RAM pages -being migrated after encryption using the security processor ). -With this expected downtime of 300ms and 350-450 pps bandwith, -the threshold size = <1/3 of the PPS bandwidth = ~100 pages. - -Now, this threshold size is the maximum pages/bytes that can be -sent in the final completion phase of Live migration -(where the source VM is stopped) with the expected downtime. -Therefore, with the threshold size computed above, -the migration completion phase which halts the source VM -and then transfers the leftover dirty pages, -is only reached in SEV live migration case when # of dirty pages are ~100. - -The dirty-pages-rate with larger guest RAM configuration like 4G, 8G, etc. -is much higher, typically in the range of 300-400+ pages, hence, -we always remain in the "dirty-sync" phase of migration and never -reach the migration completion phase with above guest RAM configs. - -To summarize, with larger guest RAM configs, -the dirty-pages-rate > threshold_size (with the default qemu expected downtime of 300ms). - -So, the fix is to increase qemu's expected downtime. - -This is a tweakable parameter which can be set using "migrate_set_downtime". - -With a downtime of 1 second, we get a threshold size of ~350-450 pages, -which will handle the "dirty-pages-rate" of 300+ pages and complete -the migration process, so we bump the default downtime to 1s in case -of SEV live migration being active. - -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - migration/migration.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/migration/migration.c b/migration/migration.c -index 6810bcefc..27c875c6c 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -3663,6 +3663,10 @@ static void migration_update_counters(MigrationState *s, - transferred = current_bytes - s->iteration_initial_bytes; - time_spent = current_time - s->iteration_start_time; - bandwidth = (double)transferred / time_spent; -+ if (memcrypt_enabled() && -+ s->parameters.downtime_limit < 1000) { -+ s->parameters.downtime_limit = 1000; -+ } - s->threshold_size = bandwidth * s->parameters.downtime_limit; - - s->mbps = (((double) transferred * 8.0) / --- -2.31.1 - diff --git a/1050-i386-kvm-Add-support-for-MSR-filtering.patch b/1050-i386-kvm-Add-support-for-MSR-filtering.patch deleted file mode 100644 index c967cf53f26f3e1b6d59f4350bc459bc90ca85bc..0000000000000000000000000000000000000000 --- a/1050-i386-kvm-Add-support-for-MSR-filtering.patch +++ /dev/null @@ -1,201 +0,0 @@ -From b45eabe2febd210065e964b6425f73f1d53af43e Mon Sep 17 00:00:00 2001 -From: Alexander Graf -Date: Wed, 5 Oct 2022 00:56:42 +0200 -Subject: [PATCH 13/29] i386: kvm: Add support for MSR filtering - -commit 860054d8ce4067ef2bc3deb2a98cf93350fc03e4 upstream. - -KVM has grown support to deflect arbitrary MSRs to user space since -Linux 5.10. For now we don't expect to make a lot of use of this -feature, so let's expose it the easiest way possible: With up to 16 -individually maskable MSRs. - -This patch adds a kvm_filter_msr() function that other code can call -to install a hook on KVM MSR reads or writes. - -Signed-off-by: Alexander Graf -Message-Id: <20221004225643.65036-3-agraf@csgraf.de> -Signed-off-by: Paolo Bonzini ---- - target/i386/kvm/kvm.c | 123 +++++++++++++++++++++++++++++++++++++ - target/i386/kvm/kvm_i386.h | 11 ++++ - 2 files changed, 134 insertions(+) - -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 5262806c4..607469fb3 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -135,6 +135,8 @@ static struct kvm_cpuid2 *cpuid_cache; - static struct kvm_cpuid2 *hv_cpuid_cache; - static struct kvm_msr_list *kvm_feature_msrs; - -+static KVMMSRHandlers msr_handlers[KVM_MSR_FILTER_MAX_RANGES]; -+ - #define BUS_LOCK_SLICE_TIME 1000000000ULL /* ns */ - static RateLimit bus_lock_ratelimit_ctrl; - -@@ -2524,6 +2526,15 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - x86ms->bus_lock_ratelimit, BUS_LOCK_SLICE_TIME); - } - } -+ if (kvm_vm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR)) { -+ ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0, -+ KVM_MSR_EXIT_REASON_FILTER); -+ if (ret) { -+ error_report("Could not enable user space MSRs: %s", -+ strerror(-ret)); -+ exit(1); -+ } -+ } - - return 0; - } -@@ -4848,6 +4859,108 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) - } - } - -+static bool kvm_install_msr_filters(KVMState *s) -+{ -+ uint64_t zero = 0; -+ struct kvm_msr_filter filter = { -+ .flags = KVM_MSR_FILTER_DEFAULT_ALLOW, -+ }; -+ int r, i, j = 0; -+ -+ for (i = 0; i < KVM_MSR_FILTER_MAX_RANGES; i++) { -+ KVMMSRHandlers *handler = &msr_handlers[i]; -+ if (handler->msr) { -+ struct kvm_msr_filter_range *range = &filter.ranges[j++]; -+ -+ *range = (struct kvm_msr_filter_range) { -+ .flags = 0, -+ .nmsrs = 1, -+ .base = handler->msr, -+ .bitmap = (__u8 *)&zero, -+ }; -+ -+ if (handler->rdmsr) { -+ range->flags |= KVM_MSR_FILTER_READ; -+ } -+ -+ if (handler->wrmsr) { -+ range->flags |= KVM_MSR_FILTER_WRITE; -+ } -+ } -+ } -+ -+ r = kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter); -+ if (r) { -+ return false; -+ } -+ -+ return true; -+} -+ -+bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr, -+ QEMUWRMSRHandler *wrmsr) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) { -+ if (!msr_handlers[i].msr) { -+ msr_handlers[i] = (KVMMSRHandlers) { -+ .msr = msr, -+ .rdmsr = rdmsr, -+ .wrmsr = wrmsr, -+ }; -+ -+ if (!kvm_install_msr_filters(s)) { -+ msr_handlers[i] = (KVMMSRHandlers) { }; -+ return false; -+ } -+ -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+static int kvm_handle_rdmsr(X86CPU *cpu, struct kvm_run *run) -+{ -+ int i; -+ bool r; -+ -+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) { -+ KVMMSRHandlers *handler = &msr_handlers[i]; -+ if (run->msr.index == handler->msr) { -+ if (handler->rdmsr) { -+ r = handler->rdmsr(cpu, handler->msr, -+ (uint64_t *)&run->msr.data); -+ run->msr.error = r ? 0 : 1; -+ return 0; -+ } -+ } -+ } -+ -+ assert(false); -+} -+ -+static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run) -+{ -+ int i; -+ bool r; -+ -+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) { -+ KVMMSRHandlers *handler = &msr_handlers[i]; -+ if (run->msr.index == handler->msr) { -+ if (handler->wrmsr) { -+ r = handler->wrmsr(cpu, handler->msr, run->msr.data); -+ run->msr.error = r ? 0 : 1; -+ return 0; -+ } -+ } -+ } -+ -+ assert(false); -+} -+ - static bool has_sgx_provisioning; - - static bool __kvm_enable_sgx_provisioning(KVMState *s) -@@ -4947,6 +5060,16 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) - /* already handled in kvm_arch_post_run */ - ret = 0; - break; -+ case KVM_EXIT_X86_RDMSR: -+ /* We only enable MSR filtering, any other exit is bogus */ -+ assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER); -+ ret = kvm_handle_rdmsr(cpu, run); -+ break; -+ case KVM_EXIT_X86_WRMSR: -+ /* We only enable MSR filtering, any other exit is bogus */ -+ assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER); -+ ret = kvm_handle_wrmsr(cpu, run); -+ break; - case KVM_EXIT_HYPERCALL: - ret = kvm_handle_exit_hypercall(cpu, run); - break; -diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h -index 4124912c2..2ed586c11 100644 ---- a/target/i386/kvm/kvm_i386.h -+++ b/target/i386/kvm/kvm_i386.h -@@ -54,4 +54,15 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address); - bool kvm_enable_sgx_provisioning(KVMState *s); - void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask); - -+typedef bool QEMURDMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t *val); -+typedef bool QEMUWRMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t val); -+typedef struct kvm_msr_handlers { -+ uint32_t msr; -+ QEMURDMSRHandler *rdmsr; -+ QEMUWRMSRHandler *wrmsr; -+} KVMMSRHandlers; -+ -+bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr, -+ QEMUWRMSRHandler *wrmsr); -+ - #endif --- -2.31.1 - diff --git a/1051-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch b/1051-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch deleted file mode 100644 index 998be40766f3c5ede01fa12f90c399e8000797a5..0000000000000000000000000000000000000000 --- a/1051-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch +++ /dev/null @@ -1,118 +0,0 @@ -From f2f9d5860a3a32431b397f4a643de16423b5e4b3 Mon Sep 17 00:00:00 2001 -From: Ashish Kalra -Date: Tue, 27 Jul 2021 17:59:33 +0000 -Subject: [PATCH 14/29] kvm: Add support for userspace MSR filtering and - handling of MSR_KVM_MIGRATION_CONTROL. - -cherry-picked from https://github.com/AMDESE/qemu/commit/67935c3fd5f. - -Add support for userspace MSR filtering using KVM_X86_SET_MSR_FILTER -ioctl and handling of MSRs in userspace. Currently this is only used -for SEV guests which use MSR_KVM_MIGRATION_CONTROL to indicate if the -guest is enabled and ready for migration. - -KVM arch code calls into SEV guest specific code to delete the -SEV migrate blocker which has been setup at SEV_LAUNCH_FINISH. - -Signed-off-by: Ashish Kalra -Signed-off-by: hanliyang ---- - target/i386/kvm/kvm.c | 37 +++++++++++++++++++++++++++++++++++++ - target/i386/sev.c | 6 ++++++ - target/i386/sev.h | 1 + - 3 files changed, 44 insertions(+) - -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 607469fb3..a833219d0 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -2330,6 +2330,32 @@ static int kvm_get_supported_msrs(KVMState *s) - return ret; - } - -+/* -+ * Currently this exit is only used by SEV guests for -+ * MSR_KVM_MIGRATION_CONTROL to indicate if the guest -+ * is ready for migration. -+ */ -+static uint64_t msr_kvm_migration_control; -+ -+static bool kvm_rdmsr_kvm_migration_control(X86CPU *cpu, uint32_t msr, -+ uint64_t *val) -+{ -+ *val = msr_kvm_migration_control; -+ -+ return true; -+} -+ -+static bool kvm_wrmsr_kvm_migration_control(X86CPU *cpu, uint32_t msr, -+ uint64_t val) -+{ -+ msr_kvm_migration_control = val; -+ -+ if (val == KVM_MIGRATION_READY) -+ sev_del_migrate_blocker(); -+ -+ return true; -+} -+ - static Notifier smram_machine_done; - static KVMMemoryListener smram_listener; - static AddressSpace smram_address_space; -@@ -2527,6 +2553,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - } - } - if (kvm_vm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR)) { -+ bool r; -+ - ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0, - KVM_MSR_EXIT_REASON_FILTER); - if (ret) { -@@ -2534,6 +2562,15 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - strerror(-ret)); - exit(1); - } -+ -+ r = kvm_filter_msr(s, MSR_KVM_MIGRATION_CONTROL, -+ kvm_rdmsr_kvm_migration_control, -+ kvm_wrmsr_kvm_migration_control); -+ if (!r) { -+ error_report("Could not install MSR_KVM_MIGRATION_CONTROL handler: %s", -+ strerror(-ret)); -+ exit(1); -+ } - } - - return 0; -diff --git a/target/i386/sev.c b/target/i386/sev.c -index cc63a1aef..b66665021 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -890,6 +890,12 @@ sev_launch_finish(SevGuestState *sev) - migrate_add_blocker(sev_mig_blocker, &error_fatal); - } - -+void -+sev_del_migrate_blocker(void) -+{ -+ migrate_del_blocker(sev_mig_blocker); -+} -+ - static int - sev_receive_finish(SevGuestState *s) - { -diff --git a/target/i386/sev.h b/target/i386/sev.h -index b8ad84014..7e53f8461 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -70,6 +70,7 @@ int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); - int sev_save_outgoing_shared_regions_list(QEMUFile *f); - int sev_load_incoming_shared_regions_list(QEMUFile *f); - bool sev_is_gfn_in_unshared_region(unsigned long gfn); -+void sev_del_migrate_blocker(void); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - --- -2.31.1 - diff --git a/1052-anolis-migration-ram-Force-encrypted-status-for-VGA-.patch b/1052-anolis-migration-ram-Force-encrypted-status-for-VGA-.patch deleted file mode 100644 index b9cfa6e482d6cffe5ae88e926ad899db5c1a4337..0000000000000000000000000000000000000000 --- a/1052-anolis-migration-ram-Force-encrypted-status-for-VGA-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 1e332429c9aa4c996191ec703e3ec10a6bd459b3 Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Tue, 8 Dec 2020 22:57:46 -0500 -Subject: [PATCH 15/29] anolis: migration/ram: Force encrypted status for VGA - vram - -The VGA vram memory region act as frame buffer of VM. This memory -is decrypted in the QEMU process. For CSV VM live migration, we -should avoid memory encryption status check on VGA vram. - -Signed-off-by: hanliyang ---- - migration/ram.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index da7a80994..fb05ff44e 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -2262,6 +2262,10 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, - return false; - } - -+ if (!strcmp(memory_region_name(block->mr), "vga.vram")) { -+ return false; -+ } -+ - /* - * Translate page in ram_addr_t address space to GPA address - * space using memory region. --- -2.31.1 - diff --git a/1053-anolis-target-i386-sev-Clear-shared_regions_list-whe.patch b/1053-anolis-target-i386-sev-Clear-shared_regions_list-whe.patch deleted file mode 100644 index 9e00e5478a02a482daa4036f21aa281cb670fbf6..0000000000000000000000000000000000000000 --- a/1053-anolis-target-i386-sev-Clear-shared_regions_list-whe.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 6ff9e3e73b0a756c9a42f2df43178ef52cf5aa26 Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Sun, 16 Jan 2022 19:57:58 -0500 -Subject: [PATCH 16/29] anolis: target/i386: sev: Clear shared_regions_list - when reboot CSV Guest - -Also fix memory leak in sev_remove_shared_regions_list(). - -Signed-off-by: hanliyang ---- - target/i386/kvm/kvm.c | 6 ++++++ - target/i386/sev.c | 5 +++-- - 2 files changed, 9 insertions(+), 2 deletions(-) - -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index a833219d0..f0b61ec3c 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -2143,6 +2143,12 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) - - hyperv_x86_synic_reset(cpu); - } -+ -+ if (cpu_is_bsp(cpu) && -+ sev_enabled() && has_map_gpa_range) { -+ sev_remove_shared_regions_list(0, -1); -+ } -+ - /* enabled by default */ - env->poll_control_msr = 1; - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index b66665021..e3eab4119 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -1661,9 +1661,9 @@ int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) - int sev_remove_shared_regions_list(unsigned long start, unsigned long end) - { - SevGuestState *s = sev_guest; -- struct shared_region *pos; -+ struct shared_region *pos, *next_pos; - -- QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { -+ QTAILQ_FOREACH_SAFE(pos, &s->shared_regions_list, list, next_pos) { - unsigned long l, r; - unsigned long curr_gfn_end = pos->gfn_end; - -@@ -1677,6 +1677,7 @@ int sev_remove_shared_regions_list(unsigned long start, unsigned long end) - if (l <= r) { - if (pos->gfn_start == l && pos->gfn_end == r) { - QTAILQ_REMOVE(&s->shared_regions_list, pos, list); -+ g_free(pos); - } else if (l == pos->gfn_start) { - pos->gfn_start = r; - } else if (r == pos->gfn_end) { --- -2.31.1 - diff --git a/1054-anolis-migration-ram-Fix-calculation-of-gfn-correpon.patch b/1054-anolis-migration-ram-Fix-calculation-of-gfn-correpon.patch deleted file mode 100644 index d385706e40ad6a607d1a03e9f63fcc9b911ab945..0000000000000000000000000000000000000000 --- a/1054-anolis-migration-ram-Fix-calculation-of-gfn-correpon.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 7a8e357130982817732272c89a53adbb13408832 Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Sun, 16 Jan 2022 20:05:02 -0500 -Subject: [PATCH 17/29] anolis: migration/ram: Fix calculation of gfn correpond - to a page in ramblock - -A RAMBlock contains a host memory region which may consist of many -discontiguous MemoryRegion in AddressSpace of a Guest, so we cannot -get gpa by MemoryRegion.addr. Since KVM memslot records the relationship -between gpa and hva, so we can pass the hva of page in RAMBlock to -kvm_phisical_memory_addr_from_host() to get the expected gpa. - -Signed-off-by: hanliyang ---- - migration/ram.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/migration/ram.c b/migration/ram.c -index fb05ff44e..33e2c9d5f 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -59,6 +59,7 @@ - - /* Defines RAM_SAVE_ENCRYPTED_PAGE and RAM_SAVE_SHARED_REGION_LIST */ - #include "target/i386/sev.h" -+#include "sysemu/kvm.h" - - #include "hw/boards.h" /* for machine_dump_guest_core() */ - -@@ -2248,6 +2249,8 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, - struct ConfidentialGuestMemoryEncryptionOps *ops = - cgs_class->memory_encryption_ops; - unsigned long gfn; -+ hwaddr paddr = 0; -+ int ret; - - /* ROM devices contains the unencrypted data */ - if (memory_region_is_rom(block->mr)) { -@@ -2270,7 +2273,14 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, - * Translate page in ram_addr_t address space to GPA address - * space using memory region. - */ -- gfn = page + (block->mr->addr >> TARGET_PAGE_BITS); -+ if (kvm_enabled()) { -+ ret = kvm_physical_memory_addr_from_host(kvm_state, -+ block->host + (page << TARGET_PAGE_BITS), &paddr); -+ if (ret == 0) { -+ return false; -+ } -+ } -+ gfn = paddr >> TARGET_PAGE_BITS; - - return ops->is_gfn_in_unshared_region(gfn); - } --- -2.31.1 - diff --git a/1055-anolis-target-i386-csv-Move-is_hygon_cpu-to-header-f.patch b/1055-anolis-target-i386-csv-Move-is_hygon_cpu-to-header-f.patch deleted file mode 100644 index 41c62695afc73330f7081d283a548a5671b6f729..0000000000000000000000000000000000000000 --- a/1055-anolis-target-i386-csv-Move-is_hygon_cpu-to-header-f.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 00e7b439f3c514d8ae20c20d5f18d24d71351c7d Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Wed, 1 Nov 2023 06:00:11 +0000 -Subject: [PATCH 18/29] anolis: target/i386: csv: Move is_hygon_cpu() to header - file csv.h - -The helper function is_hygon_cpu() will be called by functions out of -target/i386/csv.c. Move it to header file csv.h so that it can be a -common helper function. - -Signed-off-by: hanliyang ---- - target/i386/csv.c | 20 -------------------- - target/i386/csv.h | 22 ++++++++++++++++++++++ - 2 files changed, 22 insertions(+), 20 deletions(-) - -diff --git a/target/i386/csv.c b/target/i386/csv.c -index d166d3775..161cad39a 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -27,28 +27,8 @@ - - CsvGuestState csv_guest = { 0 }; - --#define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ --#define CPUID_VENDOR_HYGON_ECX 0x656e6975 /* "uine" */ --#define CPUID_VENDOR_HYGON_EDX 0x6e65476e /* "nGen" */ -- - #define GUEST_POLICY_CSV_BIT (1 << 6) - --static bool is_hygon_cpu(void) --{ -- uint32_t ebx = 0; -- uint32_t ecx = 0; -- uint32_t edx = 0; -- -- host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); -- -- if (ebx == CPUID_VENDOR_HYGON_EBX && -- ecx == CPUID_VENDOR_HYGON_ECX && -- edx == CPUID_VENDOR_HYGON_EDX) -- return true; -- else -- return false; --} -- - int - csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - { -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 7dc5c7536..4f5b2773c 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -16,6 +16,28 @@ - - #include "qapi/qapi-commands-misc-target.h" - -+#include "cpu.h" -+ -+#define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ -+#define CPUID_VENDOR_HYGON_ECX 0x656e6975 /* "uine" */ -+#define CPUID_VENDOR_HYGON_EDX 0x6e65476e /* "nGen" */ -+ -+static __attribute__((unused)) bool is_hygon_cpu(void) -+{ -+ uint32_t ebx = 0; -+ uint32_t ecx = 0; -+ uint32_t edx = 0; -+ -+ host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); -+ -+ if (ebx == CPUID_VENDOR_HYGON_EBX && -+ ecx == CPUID_VENDOR_HYGON_ECX && -+ edx == CPUID_VENDOR_HYGON_EDX) -+ return true; -+ else -+ return false; -+} -+ - #ifdef CONFIG_CSV - bool csv_enabled(void); - #else --- -2.31.1 - diff --git a/1056-anolis-target-i386-csv-Read-cert-chain-from-file-whe.patch b/1056-anolis-target-i386-csv-Read-cert-chain-from-file-whe.patch deleted file mode 100644 index 23a528c638742d4939f3a5dd07d63c2554f8709d..0000000000000000000000000000000000000000 --- a/1056-anolis-target-i386-csv-Read-cert-chain-from-file-whe.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 980dff011e266d60f8ce669a1dc14cc23b192c8b Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Mon, 13 Nov 2023 21:55:33 +0000 -Subject: [PATCH 19/29] anolis: target/i386: csv: Read cert chain from file - when prepared for CSV live migration - -The cert chain is too long when encoded with base64, use the filename -of cert chain instead of the encoded string when prepared for CSV live -migration. - -Signed-off-by: hanliyang ---- - qapi/migration.json | 24 +++++++++++++++--------- - target/i386/sev.c | 29 +++++++++++++++++++++++++---- - 2 files changed, 40 insertions(+), 13 deletions(-) - -diff --git a/qapi/migration.json b/qapi/migration.json -index bad53a2f8..8632abb20 100644 ---- a/qapi/migration.json -+++ b/qapi/migration.json -@@ -774,14 +774,16 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # --# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64, or -+# pdh filename for hygon - # (Since 4.2) - # --# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# @sev-plat-cert: The target host platform certificate chain encoded in base64, -+# or plat cert filename for hygon - # (Since 4.2) - # - # @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in --# base64 (Since 4.2) -+# base64, or vendor cert filename for hygon (Since 4.2) - # - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. -@@ -949,14 +951,16 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # --# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64, or -+# pdh filename for hygon - # (Since 4.2) - # --# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# @sev-plat-cert: The target host platform certificate chain encoded in base64, -+# or plat cert filename for hygon - # (Since 4.2) - # - # @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in --# base64 (Since 4.2) -+# base64, or vendor cert filename for hygon (Since 4.2) - # - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. -@@ -1161,14 +1165,16 @@ - # block device name if there is one, and to their node name - # otherwise. (Since 5.2) - # --# @sev-pdh: The target host platform diffie-hellman key encoded in base64 -+# @sev-pdh: The target host platform diffie-hellman key encoded in base64, or -+# pdh filename for hygon - # (Since 4.2) - # --# @sev-plat-cert: The target host platform certificate chain encoded in base64 -+# @sev-plat-cert: The target host platform certificate chain encoded in base64, -+# or plat cert filename for hygon - # (Since 4.2) - # - # @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in --# base64 (Since 4.2) -+# base64, or vendor cert filename for hygon (Since 4.2) - # - # Features: - # @unstable: Member @x-checkpoint-delay is experimental. -diff --git a/target/i386/sev.c b/target/i386/sev.c -index e3eab4119..ebe97799c 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -944,18 +944,39 @@ int sev_save_setup(const char *pdh, const char *plat_cert, - { - SevGuestState *s = sev_guest; - -- s->remote_pdh = g_base64_decode(pdh, &s->remote_pdh_len); -+ if (is_hygon_cpu()) { -+ if (sev_read_file_base64(pdh, &s->remote_pdh, -+ &s->remote_pdh_len) < 0) { -+ goto error; -+ } -+ } else { -+ s->remote_pdh = g_base64_decode(pdh, &s->remote_pdh_len); -+ } - if (!check_blob_length(s->remote_pdh_len)) { - goto error; - } - -- s->remote_plat_cert = g_base64_decode(plat_cert, -- &s->remote_plat_cert_len); -+ if (is_hygon_cpu()) { -+ if (sev_read_file_base64(plat_cert, &s->remote_plat_cert, -+ &s->remote_plat_cert_len) < 0) { -+ goto error; -+ } -+ } else { -+ s->remote_plat_cert = g_base64_decode(plat_cert, -+ &s->remote_plat_cert_len); -+ } - if (!check_blob_length(s->remote_plat_cert_len)) { - goto error; - } - -- s->amd_cert = g_base64_decode(amd_cert, &s->amd_cert_len); -+ if (is_hygon_cpu()) { -+ if (sev_read_file_base64(amd_cert, &s->amd_cert, -+ &s->amd_cert_len) < 0) { -+ goto error; -+ } -+ } else { -+ s->amd_cert = g_base64_decode(amd_cert, &s->amd_cert_len); -+ } - if (!check_blob_length(s->amd_cert_len)) { - goto error; - } --- -2.31.1 - diff --git a/1057-anolis-target-i386-csv-add-support-to-queue-the-outg.patch b/1057-anolis-target-i386-csv-add-support-to-queue-the-outg.patch deleted file mode 100644 index f6a3b3b0b771850989aeac27cc9d1e8647dfa2be..0000000000000000000000000000000000000000 --- a/1057-anolis-target-i386-csv-add-support-to-queue-the-outg.patch +++ /dev/null @@ -1,270 +0,0 @@ -From 19941d177378b596a52a7905925525d68d152dea Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 11:00:07 +0800 -Subject: [PATCH 20/29] anolis: target/i386: csv: add support to queue the - outgoing page into a list - -The csv_queue_outgoing_page() provide the implementation to queue the -guest private pages during transmission. The routines queues the outgoing -pages into a listi, and then issues the KVM_CSV_COMMAND_BATCH command to -encrypt the pages togather before writing them to the socket. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 3 + - linux-headers/linux/kvm.h | 6 + - target/i386/sev.c | 172 ++++++++++++++++++++++ - target/i386/sev.h | 2 + - 4 files changed, 183 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 343f686fc..1f32519d4 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -77,6 +77,9 @@ struct ConfidentialGuestMemoryEncryptionOps { - - /* Load the shared regions list */ - int (*load_incoming_shared_regions_list)(QEMUFile *f); -+ -+ /* Queue the encrypted page and metadata associated with it into a list */ -+ int (*queue_outgoing_page)(uint8_t *ptr, uint32_t size, uint64_t addr); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index b640e72c8..8dd8c5e6a 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1938,6 +1938,12 @@ struct kvm_csv_init_data { - __u64 nodemask; - }; - -+struct kvm_csv_batch_list_node { -+ __u64 cmd_data_addr; -+ __u64 addr; -+ __u64 next_cmd_addr; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) -diff --git a/target/i386/sev.c b/target/i386/sev.c -index ebe97799c..e7ff3f4dd 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -50,6 +50,15 @@ struct shared_region { - QTAILQ_ENTRY(shared_region) list; - }; - -+typedef struct CsvBatchCmdList CsvBatchCmdList; -+typedef void (*CsvDestroyCmdNodeFn) (void *data); -+ -+struct CsvBatchCmdList { -+ struct kvm_csv_batch_list_node *head; -+ struct kvm_csv_batch_list_node *tail; -+ CsvDestroyCmdNodeFn destroy_fn; -+}; -+ - extern struct sev_ops sev_ops; - - /** -@@ -96,6 +105,9 @@ struct SevGuestState { - bool reset_data_valid; - - QTAILQ_HEAD(, shared_region) shared_regions_list; -+ -+ /* link list used for HYGON CSV */ -+ CsvBatchCmdList *csv_batch_cmd_list; - }; - - #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ -@@ -188,6 +200,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .is_gfn_in_unshared_region = sev_is_gfn_in_unshared_region, - .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, -+ .queue_outgoing_page = csv_queue_outgoing_page, - }; - - static int -@@ -1829,6 +1842,165 @@ bool sev_is_gfn_in_unshared_region(unsigned long gfn) - return true; - } - -+#include "csv.h" -+ -+static CsvBatchCmdList * -+csv_batch_cmd_list_create(struct kvm_csv_batch_list_node *head, -+ CsvDestroyCmdNodeFn func) -+{ -+ CsvBatchCmdList *csv_batch_cmd_list = -+ g_malloc0(sizeof(*csv_batch_cmd_list)); -+ -+ if (!csv_batch_cmd_list) { -+ return NULL; -+ } -+ -+ csv_batch_cmd_list->head = head; -+ csv_batch_cmd_list->tail = head; -+ csv_batch_cmd_list->destroy_fn = func; -+ -+ return csv_batch_cmd_list; -+} -+ -+static int -+csv_batch_cmd_list_add_after(CsvBatchCmdList *list, -+ struct kvm_csv_batch_list_node *new_node) -+{ -+ list->tail->next_cmd_addr = (__u64)new_node; -+ list->tail = new_node; -+ -+ return 0; -+} -+ -+static struct kvm_csv_batch_list_node * -+csv_batch_cmd_list_node_create(uint64_t cmd_data_addr, uint64_t addr) -+{ -+ struct kvm_csv_batch_list_node *new_node = -+ g_malloc0(sizeof(struct kvm_csv_batch_list_node)); -+ -+ if (!new_node) { -+ return NULL; -+ } -+ -+ new_node->cmd_data_addr = cmd_data_addr; -+ new_node->addr = addr; -+ new_node->next_cmd_addr = 0; -+ -+ return new_node; -+} -+ -+static int csv_batch_cmd_list_destroy(CsvBatchCmdList *list) -+{ -+ struct kvm_csv_batch_list_node *node = list->head; -+ -+ while (node != NULL) { -+ if (list->destroy_fn != NULL) -+ list->destroy_fn((void *)node->cmd_data_addr); -+ -+ list->head = (struct kvm_csv_batch_list_node *)node->next_cmd_addr; -+ g_free(node); -+ node = list->head; -+ } -+ -+ g_free(list); -+ return 0; -+} -+ -+static void send_update_data_free(void *data) -+{ -+ struct kvm_sev_send_update_data *update = -+ (struct kvm_sev_send_update_data *)data; -+ g_free((guchar *)update->hdr_uaddr); -+ g_free((guchar *)update->trans_uaddr); -+ g_free(update); -+} -+ -+static int -+csv_send_queue_data(SevGuestState *s, uint8_t *ptr, -+ uint32_t size, uint64_t addr) -+{ -+ int ret = 0; -+ int fw_error; -+ guchar *trans; -+ guchar *packet_hdr; -+ struct kvm_sev_send_update_data *update; -+ struct kvm_csv_batch_list_node *new_node = NULL; -+ -+ /* If this is first call then query the packet header bytes and allocate -+ * the packet buffer. -+ */ -+ if (s->send_packet_hdr_len < 1) { -+ s->send_packet_hdr_len = sev_send_get_packet_len(&fw_error); -+ if (s->send_packet_hdr_len < 1) { -+ error_report("%s: SEND_UPDATE fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ } -+ -+ packet_hdr = g_new(guchar, s->send_packet_hdr_len); -+ memset(packet_hdr, 0, s->send_packet_hdr_len); -+ -+ update = g_new0(struct kvm_sev_send_update_data, 1); -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, size); -+ -+ update->hdr_uaddr = (unsigned long)packet_hdr; -+ update->hdr_len = s->send_packet_hdr_len; -+ update->guest_uaddr = (unsigned long)ptr; -+ update->guest_len = size; -+ update->trans_uaddr = (unsigned long)trans; -+ update->trans_len = size; -+ -+ new_node = csv_batch_cmd_list_node_create((uint64_t)update, addr); -+ if (!new_node) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ if (s->csv_batch_cmd_list == NULL) { -+ s->csv_batch_cmd_list = csv_batch_cmd_list_create(new_node, -+ send_update_data_free); -+ if (s->csv_batch_cmd_list == NULL) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ } else { -+ /* Add new_node's command address to the last_node */ -+ csv_batch_cmd_list_add_after(s->csv_batch_cmd_list, new_node); -+ } -+ -+ trace_kvm_sev_send_update_data(ptr, trans, size); -+ -+ return ret; -+ -+err: -+ g_free(trans); -+ g_free(update); -+ g_free(packet_hdr); -+ g_free(new_node); -+ if (s->csv_batch_cmd_list) { -+ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); -+ s->csv_batch_cmd_list = NULL; -+ } -+ return ret; -+} -+ -+int -+csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* Only support for HYGON CSV */ -+ if (!is_hygon_cpu()) { -+ error_report("Only support enqueue pages for HYGON CSV"); -+ return -EINVAL; -+ } -+ -+ return csv_send_queue_data(s, ptr, sz, addr); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 7e53f8461..1eba67bcf 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -74,6 +74,8 @@ void sev_del_migrate_blocker(void); - - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - -+int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); -+ - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); - const char *(*fw_error_to_str)(int code); --- -2.31.1 - diff --git a/1058-anolis-target-i386-csv-add-support-to-encrypt-the-ou.patch b/1058-anolis-target-i386-csv-add-support-to-encrypt-the-ou.patch deleted file mode 100644 index 393b47475269bf0c55f0be42250e6181669bffc1..0000000000000000000000000000000000000000 --- a/1058-anolis-target-i386-csv-add-support-to-encrypt-the-ou.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 500646168eb4dc297d01dbc35759e38d0206a3b6 Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 11:41:58 +0800 -Subject: [PATCH 21/29] anolis: target/i386: csv: add support to encrypt the - outgoing pages in the list queued before. - -The csv_save_queued_outgoing_pages() provide the implementation to encrypt -the guest private pages during transmission. The routines uses SEND_START -command to create the outgoing encryption context on the first call then -uses COMMAND_BATCH command to send the SEND_UPDATE_DATA commands queued -in the list to encrypt the data before writing it to the socket. While -encrypting the data SEND_UPDATE_DATA produces some metadata (e.g MAC, IV). -The metadata is also sent to the target machine. After migration is completed, -we issue the SEND_FINISH command to transition the SEV guest state from sending -to unrunnable state. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 4 + - linux-headers/linux/kvm.h | 8 ++ - target/i386/sev.c | 89 +++++++++++++++++++++++ - target/i386/sev.h | 4 + - 4 files changed, 105 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 1f32519d4..1ff4823b6 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -80,6 +80,10 @@ struct ConfidentialGuestMemoryEncryptionOps { - - /* Queue the encrypted page and metadata associated with it into a list */ - int (*queue_outgoing_page)(uint8_t *ptr, uint32_t size, uint64_t addr); -+ -+ /* Write the list queued with encrypted pages and metadata associated -+ * with them */ -+ int (*save_queued_outgoing_pages)(QEMUFile *f, uint64_t *bytes_sent); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 8dd8c5e6a..951afc8b2 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1823,6 +1823,9 @@ enum sev_cmd_id { - /* Guest Migration Extension */ - KVM_SEV_SEND_CANCEL, - -+ /* Hygon CSV batch command */ -+ KVM_CSV_COMMAND_BATCH = 0x18, -+ - KVM_SEV_NR_MAX, - }; - -@@ -1944,6 +1947,11 @@ struct kvm_csv_batch_list_node { - __u64 next_cmd_addr; - }; - -+struct kvm_csv_command_batch { -+ __u32 command_id; -+ __u64 csv_batch_list_uaddr; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) -diff --git a/target/i386/sev.c b/target/i386/sev.c -index e7ff3f4dd..6ff547a23 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -201,6 +201,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - .queue_outgoing_page = csv_queue_outgoing_page, -+ .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, - }; - - static int -@@ -1987,6 +1988,70 @@ err: - return ret; - } - -+static int -+csv_command_batch(uint32_t cmd_id, uint64_t head_uaddr, int *fw_err) -+{ -+ int ret; -+ struct kvm_csv_command_batch command_batch = { }; -+ -+ command_batch.command_id = cmd_id; -+ command_batch.csv_batch_list_uaddr = head_uaddr; -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_CSV_COMMAND_BATCH, -+ &command_batch, fw_err); -+ if (ret) { -+ error_report("%s: COMMAND_BATCH ret=%d fw_err=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ } -+ -+ return ret; -+} -+ -+static int -+csv_send_update_data_batch(SevGuestState *s, QEMUFile *f, uint64_t *bytes_sent) -+{ -+ int ret, fw_error = 0; -+ struct kvm_sev_send_update_data *update; -+ struct kvm_csv_batch_list_node *node; -+ -+ ret = csv_command_batch(KVM_SEV_SEND_UPDATE_DATA, -+ (uint64_t)s->csv_batch_cmd_list->head, &fw_error); -+ if (ret) { -+ error_report("%s: csv_command_batch ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ *bytes_sent = 0; -+ for (node = s->csv_batch_cmd_list->head; -+ node != NULL; -+ node = (struct kvm_csv_batch_list_node *)node->next_cmd_addr) { -+ if (node != s->csv_batch_cmd_list->head) { -+ /* head's page header is saved before send_update_data */ -+ qemu_put_be64(f, node->addr); -+ *bytes_sent += 8; -+ if (node->next_cmd_addr != 0) -+ qemu_put_be32(f, RAM_SAVE_ENCRYPTED_PAGE_BATCH); -+ else -+ qemu_put_be32(f, RAM_SAVE_ENCRYPTED_PAGE_BATCH_END); -+ *bytes_sent += 4; -+ } -+ update = (struct kvm_sev_send_update_data *)node->cmd_data_addr; -+ qemu_put_be32(f, update->hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update->hdr_uaddr, update->hdr_len); -+ *bytes_sent += (4 + update->hdr_len); -+ -+ qemu_put_be32(f, update->trans_len); -+ qemu_put_buffer(f, (uint8_t *)update->trans_uaddr, update->trans_len); -+ *bytes_sent += (4 + update->trans_len); -+ } -+ -+err: -+ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); -+ s->csv_batch_cmd_list = NULL; -+ return ret; -+} -+ - int - csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) - { -@@ -2001,6 +2066,30 @@ csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) - return csv_send_queue_data(s, ptr, sz, addr); - } - -+int -+csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* Only support for HYGON CSV */ -+ if (!is_hygon_cpu()) { -+ error_report("Only support transfer queued pages for HYGON CSV"); -+ return -EINVAL; -+ } -+ -+ /* -+ * If this is a first buffer then create outgoing encryption context -+ * and write our PDH, policy and session data. -+ */ -+ if (!sev_check_state(s, SEV_STATE_SEND_UPDATE) && -+ sev_send_start(s, f, bytes_sent)) { -+ error_report("Failed to create outgoing context"); -+ return 1; -+ } -+ -+ return csv_send_update_data_batch(s, f, bytes_sent); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 1eba67bcf..37ed17f32 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -41,6 +41,9 @@ typedef struct SevKernelLoaderContext { - #define RAM_SAVE_ENCRYPTED_PAGE 0x1 - #define RAM_SAVE_SHARED_REGIONS_LIST 0x2 - -+#define RAM_SAVE_ENCRYPTED_PAGE_BATCH 0x4 -+#define RAM_SAVE_ENCRYPTED_PAGE_BATCH_END 0x5 -+ - #ifdef CONFIG_SEV - bool sev_enabled(void); - bool sev_es_enabled(void); -@@ -75,6 +78,7 @@ void sev_del_migrate_blocker(void); - int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - - int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); -+int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); --- -2.31.1 - diff --git a/1059-anolis-target-i386-csv-add-support-to-queue-the-inco.patch b/1059-anolis-target-i386-csv-add-support-to-queue-the-inco.patch deleted file mode 100644 index cc70aac8f9f954197ad85df733242d11b66990cb..0000000000000000000000000000000000000000 --- a/1059-anolis-target-i386-csv-add-support-to-queue-the-inco.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 8af625f3b5f4d2eb768b1eee2dc2e7938800d47e Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 13:49:48 +0800 -Subject: [PATCH 22/29] anolis: target/i386: csv: add support to queue the - incoming page into a list - -The csv_queue_incoming_page() provide the implementation to queue the -guest private pages during transmission. The routines queues the incoming -socket which contains the guest private pages into a list then uses the -COMMAND_BATCH command to load the encrypted pages into the guest memory. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 3 + - target/i386/sev.c | 92 +++++++++++++++++++++++ - target/i386/sev.h | 1 + - 3 files changed, 96 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 1ff4823b6..530b5057b 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -84,6 +84,9 @@ struct ConfidentialGuestMemoryEncryptionOps { - /* Write the list queued with encrypted pages and metadata associated - * with them */ - int (*save_queued_outgoing_pages)(QEMUFile *f, uint64_t *bytes_sent); -+ -+ /* Queue the incoming encrypted page into a list */ -+ int (*queue_incoming_page)(QEMUFile *f, uint8_t *ptr); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 6ff547a23..e235fb207 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -202,6 +202,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - .queue_outgoing_page = csv_queue_outgoing_page, - .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, -+ .queue_incoming_page = csv_queue_incoming_page, - }; - - static int -@@ -1916,6 +1917,15 @@ static void send_update_data_free(void *data) - g_free(update); - } - -+static void receive_update_data_free(void *data) -+{ -+ struct kvm_sev_receive_update_data *update = -+ (struct kvm_sev_receive_update_data *)data; -+ g_free((guchar *)update->hdr_uaddr); -+ g_free((guchar *)update->trans_uaddr); -+ g_free(update); -+} -+ - static int - csv_send_queue_data(SevGuestState *s, uint8_t *ptr, - uint32_t size, uint64_t addr) -@@ -1988,6 +1998,66 @@ err: - return ret; - } - -+static int -+csv_receive_queue_data(SevGuestState *s, QEMUFile *f, uint8_t *ptr) -+{ -+ int ret = 0; -+ gchar *hdr = NULL, *trans = NULL; -+ struct kvm_sev_receive_update_data *update; -+ struct kvm_csv_batch_list_node *new_node = NULL; -+ -+ update = g_new0(struct kvm_sev_receive_update_data, 1); -+ /* get packet header */ -+ update->hdr_len = qemu_get_be32(f); -+ hdr = g_new(gchar, update->hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update->hdr_len); -+ update->hdr_uaddr = (unsigned long)hdr; -+ -+ /* get transport buffer */ -+ update->trans_len = qemu_get_be32(f); -+ trans = g_new(gchar, update->trans_len); -+ update->trans_uaddr = (unsigned long)trans; -+ qemu_get_buffer(f, (uint8_t *)update->trans_uaddr, update->trans_len); -+ -+ /* set guest address,guest len is page_size */ -+ update->guest_uaddr = (uint64_t)ptr; -+ update->guest_len = TARGET_PAGE_SIZE; -+ -+ new_node = csv_batch_cmd_list_node_create((uint64_t)update, 0); -+ if (!new_node) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ if (s->csv_batch_cmd_list == NULL) { -+ s->csv_batch_cmd_list = csv_batch_cmd_list_create(new_node, -+ receive_update_data_free); -+ if (s->csv_batch_cmd_list == NULL) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ } else { -+ /* Add new_node's command address to the last_node */ -+ csv_batch_cmd_list_add_after(s->csv_batch_cmd_list, new_node); -+ } -+ -+ trace_kvm_sev_receive_update_data(trans, (void *)ptr, update->guest_len, -+ (void *)hdr, update->hdr_len); -+ -+ return ret; -+ -+err: -+ g_free(trans); -+ g_free(update); -+ g_free(hdr); -+ g_free(new_node); -+ if (s->csv_batch_cmd_list) { -+ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); -+ s->csv_batch_cmd_list = NULL; -+ } -+ return ret; -+} -+ - static int - csv_command_batch(uint32_t cmd_id, uint64_t head_uaddr, int *fw_err) - { -@@ -2066,6 +2136,28 @@ csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) - return csv_send_queue_data(s, ptr, sz, addr); - } - -+int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* Only support for HYGON CSV */ -+ if (!is_hygon_cpu()) { -+ error_report("Only support enqueue received pages for HYGON CSV"); -+ return -EINVAL; -+ } -+ -+ /* -+ * If this is first buffer and SEV is not in recieiving state then -+ * use RECEIVE_START command to create a encryption context. -+ */ -+ if (!sev_check_state(s, SEV_STATE_RECEIVE_UPDATE) && -+ sev_receive_start(s, f)) { -+ return 1; -+ } -+ -+ return csv_receive_queue_data(s, f, ptr); -+} -+ - int - csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) - { -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 37ed17f32..6166be420 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -79,6 +79,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - - int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); -+int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr); - - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); --- -2.31.1 - diff --git a/1060-anolis-target-i386-csv-add-support-to-load-incoming-.patch b/1060-anolis-target-i386-csv-add-support-to-load-incoming-.patch deleted file mode 100644 index f54f872658b2f2cbd9eca3c4ebd22e4cf9e13c71..0000000000000000000000000000000000000000 --- a/1060-anolis-target-i386-csv-add-support-to-load-incoming-.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 8949b2ac9cc6d9a59a482ca76f81a417c9c38e6d Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 14:11:43 +0800 -Subject: [PATCH 23/29] anolis: target/i386: csv: add support to load incoming - encrypted pages queued in the CMD list - -The csv_load_queued_incoming_pages() provide the implementation to read the -incoming guest private pages from the socket queued in the CMD list and load -them into the guest memory. The routines uses the RECEIVE_START command to -create the incoming encryption context on the first call then uses the -COMMAND_BATCH carried with RECEIEVE_UPDATE_DATA commands to load the encrypted -pages into the guest memory. After migration is completed, we issue the -RECEIVE_FINISH command to transition the SEV guest to the runnable state -so that it can be executed. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 3 +++ - target/i386/sev.c | 32 +++++++++++++++++++++++ - target/i386/sev.h | 1 + - 3 files changed, 36 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index 530b5057b..f6a30fab3 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -87,6 +87,9 @@ struct ConfidentialGuestMemoryEncryptionOps { - - /* Queue the incoming encrypted page into a list */ - int (*queue_incoming_page)(QEMUFile *f, uint8_t *ptr); -+ -+ /* Load the incoming encrypted pages queued in list into guest memory */ -+ int (*load_queued_incoming_pages)(QEMUFile *f); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/target/i386/sev.c b/target/i386/sev.c -index e235fb207..2f7d98be6 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -203,6 +203,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .queue_outgoing_page = csv_queue_outgoing_page, - .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, - .queue_incoming_page = csv_queue_incoming_page, -+ .load_queued_incoming_pages = csv_load_queued_incoming_pages, - }; - - static int -@@ -2122,6 +2123,24 @@ err: - return ret; - } - -+static int -+csv_receive_update_data_batch(SevGuestState *s) -+{ -+ int ret; -+ int fw_error; -+ -+ ret = csv_command_batch(KVM_SEV_RECEIVE_UPDATE_DATA, -+ (uint64_t)s->csv_batch_cmd_list->head, &fw_error); -+ if (ret) { -+ error_report("%s: csv_command_batch ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ } -+ -+ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); -+ s->csv_batch_cmd_list = NULL; -+ return ret; -+} -+ - int - csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) - { -@@ -2182,6 +2201,19 @@ csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) - return csv_send_update_data_batch(s, f, bytes_sent); - } - -+int csv_load_queued_incoming_pages(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ -+ /* Only support for HYGON CSV */ -+ if (!is_hygon_cpu()) { -+ error_report("Only support load queued pages for HYGON CSV"); -+ return -EINVAL; -+ } -+ -+ return csv_receive_update_data_batch(s); -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 6166be420..c53f96b04 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -80,6 +80,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); - int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr); -+int csv_load_queued_incoming_pages(QEMUFile *f); - - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); --- -2.31.1 - diff --git a/1061-anolis-migration-ram-Accelerate-the-transmission-of-.patch b/1061-anolis-migration-ram-Accelerate-the-transmission-of-.patch deleted file mode 100644 index a065a0e4ef9ea439eff3cf5e50053daaf6dc06be..0000000000000000000000000000000000000000 --- a/1061-anolis-migration-ram-Accelerate-the-transmission-of-.patch +++ /dev/null @@ -1,229 +0,0 @@ -From 379463820571f9ca239e68f2f5f588634b96bbff Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 14:35:51 +0800 -Subject: [PATCH 24/29] anolis: migration/ram: Accelerate the transmission of - CSV guest's encrypted pages - -When memory encryption is enabled, the guest memory will be encrypted with -the guest specific key. The patch introduces an accelerate solution which -queued the pages into list and send them togather by COMMAND_BATCH. - -Signed-off-by: hanliyang ---- - configs/devices/i386-softmmu/default.mak | 1 + - hw/i386/Kconfig | 5 ++ - migration/ram.c | 106 +++++++++++++++++++++++ - target/i386/csv.h | 11 +++ - target/i386/sev.h | 1 + - 5 files changed, 124 insertions(+) - -diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak -index db83ffcab..e948e54e4 100644 ---- a/configs/devices/i386-softmmu/default.mak -+++ b/configs/devices/i386-softmmu/default.mak -@@ -24,6 +24,7 @@ - #CONFIG_VTD=n - #CONFIG_SGX=n - #CONFIG_CSV=n -+#CONFIG_HYGON_CSV_MIG_ACCEL=n - - # Boards: - # -diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig -index ed35d762b..8876b360b 100644 ---- a/hw/i386/Kconfig -+++ b/hw/i386/Kconfig -@@ -4,6 +4,7 @@ config X86_FW_OVMF - config SEV - bool - select X86_FW_OVMF -+ select HYGON_CSV_MIG_ACCEL - depends on KVM - - config SGX -@@ -14,6 +15,10 @@ config CSV - bool - depends on SEV - -+config HYGON_CSV_MIG_ACCEL -+ bool -+ depends on SEV -+ - config PC - bool - imply APPLESMC -diff --git a/migration/ram.c b/migration/ram.c -index 33e2c9d5f..7e2d4e7df 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -59,6 +59,7 @@ - - /* Defines RAM_SAVE_ENCRYPTED_PAGE and RAM_SAVE_SHARED_REGION_LIST */ - #include "target/i386/sev.h" -+#include "target/i386/csv.h" - #include "sysemu/kvm.h" - - #include "hw/boards.h" /* for machine_dump_guest_core() */ -@@ -2348,6 +2349,99 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, - return ram_save_page(rs, pss, last_stage); - } - -+#ifdef CONFIG_HYGON_CSV_MIG_ACCEL -+/** -+ * ram_save_encrypted_pages_in_batch - send the given encrypted pages to -+ * the stream. -+ */ -+static int -+ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss, bool last_stage) -+{ -+ int ret; -+ int tmppages = 0, pages = 0; -+ RAMBlock *block = pss->block; -+ ram_addr_t offset = pss->page << TARGET_PAGE_BITS; -+ ram_addr_t start_offset = 0; -+ uint32_t host_len = 0; -+ uint8_t *p; -+ uint64_t bytes_xmit; -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *)object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ do { -+ /* Check the pages is dirty and if it is send it */ -+ if (!migration_bitmap_clear_dirty(rs, block, pss->page)) { -+ pss->page++; -+ continue; -+ } -+ -+ /* Process the unencrypted page */ -+ if (!encrypted_test_list(rs, block, pss->page)) { -+ tmppages = ram_save_target_page(rs, pss, last_stage); -+ } else { -+ /* Caculate the offset and host virtual address of the page */ -+ offset = pss->page << TARGET_PAGE_BITS; -+ p = block->host + offset; -+ -+ /* Record the offset and host virtual address of the first -+ * page in this loop which will be used below. -+ */ -+ if (host_len == 0) { -+ start_offset = offset | RAM_SAVE_FLAG_ENCRYPTED_DATA; -+ } else { -+ offset |= (RAM_SAVE_FLAG_ENCRYPTED_DATA | RAM_SAVE_FLAG_CONTINUE); -+ } -+ -+ /* Queue the outgoing page if the page is not zero page. -+ * If the queued pages are up to the outgoing page window size, -+ * process them below. -+ */ -+ if (ops->queue_outgoing_page(p, TARGET_PAGE_SIZE, offset)) -+ return -1; -+ -+ tmppages = 1; -+ host_len += TARGET_PAGE_SIZE; -+ ram_counters.normal++; -+ } -+ -+ if (tmppages < 0) { -+ return tmppages; -+ } -+ -+ pages += tmppages; -+ -+ pss->page++; -+ } while (offset_in_ramblock(block, pss->page << TARGET_PAGE_BITS) && -+ host_len < CSV_OUTGOING_PAGE_WINDOW_SIZE); -+ -+ /* Check if there are any queued pages */ -+ if (host_len != 0) { -+ ram_counters.transferred += -+ save_page_header(rs, rs->f, block, start_offset); -+ /* if only one page queued, flag is BATCH_END, else flag is BATCH */ -+ if (host_len > TARGET_PAGE_SIZE) -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_PAGE_BATCH); -+ else -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_PAGE_BATCH_END); -+ ram_counters.transferred += 4; -+ /* Process the queued pages in batch */ -+ ret = ops->save_queued_outgoing_pages(rs->f, &bytes_xmit); -+ if (ret) { -+ return -1; -+ } -+ ram_counters.transferred += bytes_xmit; -+ } -+ -+ /* The offset we leave with is the last one we looked at */ -+ pss->page--; -+ -+ return pages; -+} -+#endif -+ - /** - * ram_save_host_page: save a whole host page - * -@@ -2382,6 +2476,18 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, - return 0; - } - -+#ifdef CONFIG_HYGON_CSV_MIG_ACCEL -+ /* -+ * If command_batch function is enabled and memory encryption is enabled -+ * then use command batch APIs to accelerate the sending process -+ * to write the outgoing buffer to the wire. The encryption APIs -+ * will re-encrypt the data with transport key so that data is prototect -+ * on the wire. -+ */ -+ if (memcrypt_enabled() && is_hygon_cpu() && !migration_in_postcopy()) -+ return ram_save_encrypted_pages_in_batch(rs, pss, last_stage); -+#endif -+ - do { - /* Check the pages is dirty and if it is send it */ - if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 4f5b2773c..e51cc8302 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -16,6 +16,8 @@ - - #include "qapi/qapi-commands-misc-target.h" - -+#ifdef CONFIG_SEV -+ - #include "cpu.h" - - #define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ -@@ -38,6 +40,15 @@ static __attribute__((unused)) bool is_hygon_cpu(void) - return false; - } - -+#else -+ -+static __attribute__((unused)) bool is_hygon_cpu(void) -+{ -+ return false; -+} -+ -+#endif -+ - #ifdef CONFIG_CSV - bool csv_enabled(void); - #else -diff --git a/target/i386/sev.h b/target/i386/sev.h -index c53f96b04..345dffac5 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -43,6 +43,7 @@ typedef struct SevKernelLoaderContext { - - #define RAM_SAVE_ENCRYPTED_PAGE_BATCH 0x4 - #define RAM_SAVE_ENCRYPTED_PAGE_BATCH_END 0x5 -+#define CSV_OUTGOING_PAGE_WINDOW_SIZE (4094 * TARGET_PAGE_SIZE) - - #ifdef CONFIG_SEV - bool sev_enabled(void); --- -2.31.1 - diff --git a/1062-anolis-migration-ram-Accelerate-the-loading-of-CSV-g.patch b/1062-anolis-migration-ram-Accelerate-the-loading-of-CSV-g.patch deleted file mode 100644 index 56c11eb31074d00363896ad069af86f42ff2735d..0000000000000000000000000000000000000000 --- a/1062-anolis-migration-ram-Accelerate-the-loading-of-CSV-g.patch +++ /dev/null @@ -1,37 +0,0 @@ -From e9b70bcaf165cb163304ba68a1b1db078489d9e0 Mon Sep 17 00:00:00 2001 -From: fangbaoshun -Date: Mon, 2 Aug 2021 14:49:45 +0800 -Subject: [PATCH 25/29] anolis: migration/ram: Accelerate the loading of CSV - guest's encrypted pages - -When memory encryption is enabled, the guest memory will be encrypted with -the guest specific key. The patch introduces an accelerate solution which -queued the pages into list and load them togather by COMMAND_BATCH. - -Signed-off-by: hanliyang ---- - migration/ram.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/migration/ram.c b/migration/ram.c -index 7e2d4e7df..90f1bda83 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1387,6 +1387,14 @@ static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) - return ops->load_incoming_page(f, ptr); - } else if (flag == RAM_SAVE_SHARED_REGIONS_LIST) { - return ops->load_incoming_shared_regions_list(f); -+ } else if (flag == RAM_SAVE_ENCRYPTED_PAGE_BATCH) { -+ return ops->queue_incoming_page(f, ptr); -+ } else if (flag == RAM_SAVE_ENCRYPTED_PAGE_BATCH_END) { -+ if (ops->queue_incoming_page(f, ptr)) { -+ error_report("Failed to queue incoming data"); -+ return -EINVAL; -+ } -+ return ops->load_queued_incoming_pages(f); - } else { - error_report("unknown encrypted flag %x", flag); - return 1; --- -2.31.1 - diff --git a/1063-anolis-target-i386-csv-Add-support-for-migrate-VMSA-.patch b/1063-anolis-target-i386-csv-Add-support-for-migrate-VMSA-.patch deleted file mode 100644 index 166fb5835da60f6f4135cd382716dc6425d6f569..0000000000000000000000000000000000000000 --- a/1063-anolis-target-i386-csv-Add-support-for-migrate-VMSA-.patch +++ /dev/null @@ -1,416 +0,0 @@ -From 133fe2e6a250623ccc9305fdacc1e8d990878fb4 Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Tue, 7 Jun 2022 15:19:32 +0800 -Subject: [PATCH 26/29] anolis: target/i386/csv: Add support for migrate VMSA - for CSV2 guest - -CSV2 can protect guest's cpu state through memory encryption. Each -vcpu has its corresponding memory, which is also called VMSA, and -is encrypted by guest's specific encrytion key. - -When CSV2 guest exit to host, the vcpu's state will be encrypted -and saved to VMSA, and the VMSA will be decrypted and loaded to cpu -when the guest's vcpu running at next time. - -If user wants to migrate one CSV2 guest to target machine, the VMSA -of the vcpus also should be migrated to target. CSV firmware provides -SEND_UPDATE_VMSA/RECEIVE_UPDATE_VMSA API through which VMSA can be -converted into secure data and transmitted to the remote end (for -example, network transmission). - -The migration of cpu state is identified by CPUState.cpu_index which -may not equals to vcpu id from KVM's perspective. - -When migrate the VMSA, the source QEMU will invoke SEND_UPDATE_VMSA to -generate data correspond to VMSA, after target QEMU received the data, -it will calc target vcpu id in the KVM by CPUState.cpu_index, and then -invoke RECEIVE_UPDATE_VMSA to restore VMSA correspond to vcpu. - -Signed-off-by: hanliyang ---- - include/exec/confidential-guest-support.h | 6 + - linux-headers/linux/kvm.h | 16 ++ - migration/ram.c | 30 ++++ - target/i386/sev.c | 196 ++++++++++++++++++++++ - target/i386/sev.h | 3 + - target/i386/trace-events | 2 + - 6 files changed, 253 insertions(+) - -diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h -index f6a30fab3..a069bad9d 100644 ---- a/include/exec/confidential-guest-support.h -+++ b/include/exec/confidential-guest-support.h -@@ -90,6 +90,12 @@ struct ConfidentialGuestMemoryEncryptionOps { - - /* Load the incoming encrypted pages queued in list into guest memory */ - int (*load_queued_incoming_pages)(QEMUFile *f); -+ -+ /* Write the encrypted cpu state */ -+ int (*save_outgoing_cpu_state)(QEMUFile *f); -+ -+ /* Load the encrypted cpu state */ -+ int (*load_incoming_cpu_state)(QEMUFile *f); - }; - - typedef struct ConfidentialGuestSupportClass { -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 951afc8b2..e5d282c75 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1904,6 +1904,14 @@ struct kvm_sev_send_update_data { - __u32 trans_len; - }; - -+struct kvm_sev_send_update_vmsa { -+ __u32 vcpu_id; -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ - struct kvm_sev_receive_start { - __u32 handle; - __u32 policy; -@@ -1922,6 +1930,14 @@ struct kvm_sev_receive_update_data { - __u32 trans_len; - }; - -+struct kvm_sev_receive_update_vmsa { -+ __u32 vcpu_id; -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ - /* CSV command */ - enum csv_cmd_id { - KVM_CSV_NR_MIN = 0xc0, -diff --git a/migration/ram.c b/migration/ram.c -index 90f1bda83..8c61eecb9 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -1371,6 +1371,23 @@ static int ram_save_shared_region_list(RAMState *rs, QEMUFile *f) - return ops->save_outgoing_shared_regions_list(rs->f); - } - -+/** -+ * ram_save_encrypted_cpu_state: send the encrypted cpu state -+ */ -+static int ram_save_encrypted_cpu_state(RAMState *rs, QEMUFile *f) -+{ -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ save_page_header(rs, rs->f, rs->last_seen_block, -+ RAM_SAVE_FLAG_ENCRYPTED_DATA); -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_CPU_STATE); -+ return ops->save_outgoing_cpu_state(rs->f); -+} -+ - static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) - { - MachineState *ms = MACHINE(qdev_get_machine()); -@@ -1395,6 +1412,8 @@ static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) - return -EINVAL; - } - return ops->load_queued_incoming_pages(f); -+ } else if (flag == RAM_SAVE_ENCRYPTED_CPU_STATE) { -+ return ops->load_incoming_cpu_state(f); - } else { - error_report("unknown encrypted flag %x", flag); - return 1; -@@ -3507,6 +3526,17 @@ static int ram_save_complete(QEMUFile *f, void *opaque) - if (memcrypt_enabled()) { - ret = ram_save_shared_region_list(rs, f); - } -+ -+ /* -+ * send the encrypted cpu state, for example, CSV2 guest's -+ * vmsa for each vcpu. -+ */ -+ if (!ret && memcrypt_enabled() && is_hygon_cpu()) { -+ ret = ram_save_encrypted_cpu_state(rs, f); -+ if (ret) { -+ error_report("Failed to save encrypted cpu state"); -+ } -+ } - } - - if (ret < 0) { -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 2f7d98be6..9cdf3e6bf 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -100,6 +100,10 @@ struct SevGuestState { - gchar *send_packet_hdr; - size_t send_packet_hdr_len; - -+ /* needed by live migration of HYGON CSV2 guest */ -+ gchar *send_vmsa_packet_hdr; -+ size_t send_vmsa_packet_hdr_len; -+ - uint32_t reset_cs; - uint32_t reset_ip; - bool reset_data_valid; -@@ -193,6 +197,9 @@ static const char *const sev_fw_errlist[] = { - #define SHARED_REGION_LIST_CONT 0x1 - #define SHARED_REGION_LIST_END 0x2 - -+#define ENCRYPTED_CPU_STATE_CONT 0x1 -+#define ENCRYPTED_CPU_STATE_END 0x2 -+ - static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = sev_save_outgoing_page, -@@ -204,6 +211,8 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, - .queue_incoming_page = csv_queue_incoming_page, - .load_queued_incoming_pages = csv_load_queued_incoming_pages, -+ .save_outgoing_cpu_state = csv_save_outgoing_cpu_state, -+ .load_incoming_cpu_state = csv_load_incoming_cpu_state, - }; - - static int -@@ -1020,6 +1029,9 @@ sev_send_finish(void) - } - - g_free(sev_guest->send_packet_hdr); -+ if (sev_es_enabled() && is_hygon_cpu()) { -+ g_free(sev_guest->send_vmsa_packet_hdr); -+ } - sev_set_guest_state(sev_guest, SEV_STATE_RUNNING); - } - -@@ -2214,6 +2226,190 @@ int csv_load_queued_incoming_pages(QEMUFile *f) - return csv_receive_update_data_batch(s); - } - -+static int -+sev_send_vmsa_get_packet_len(int *fw_err) -+{ -+ int ret; -+ struct kvm_sev_send_update_vmsa update = { 0, }; -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_UPDATE_VMSA, -+ &update, fw_err); -+ if (*fw_err != SEV_RET_INVALID_LEN) { -+ ret = -1; -+ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ goto err; -+ } -+ -+ ret = update.hdr_len; -+ -+err: -+ return ret; -+} -+ -+static int -+sev_send_update_vmsa(SevGuestState *s, QEMUFile *f, uint32_t cpu_id, -+ uint32_t cpu_index, uint32_t size) -+{ -+ int ret, fw_error; -+ guchar *trans = NULL; -+ struct kvm_sev_send_update_vmsa update = {}; -+ -+ /* -+ * If this is first call then query the packet header bytes and allocate -+ * the packet buffer. -+ */ -+ if (!s->send_vmsa_packet_hdr) { -+ s->send_vmsa_packet_hdr_len = sev_send_vmsa_get_packet_len(&fw_error); -+ if (s->send_vmsa_packet_hdr_len < 1) { -+ error_report("%s: SEND_UPDATE_VMSA fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ -+ s->send_vmsa_packet_hdr = g_new(gchar, s->send_vmsa_packet_hdr_len); -+ } -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, size); -+ -+ update.vcpu_id = cpu_id; -+ update.hdr_uaddr = (uintptr_t)s->send_vmsa_packet_hdr; -+ update.hdr_len = s->send_vmsa_packet_hdr_len; -+ update.trans_uaddr = (uintptr_t)trans; -+ update.trans_len = size; -+ -+ trace_kvm_sev_send_update_vmsa(cpu_id, cpu_index, trans, size); -+ -+ ret = sev_ioctl(s->sev_fd, KVM_SEV_SEND_UPDATE_VMSA, &update, &fw_error); -+ if (ret) { -+ error_report("%s: SEND_UPDATE_VMSA ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ /* -+ * Migration of vCPU's VMState according to the instance_id -+ * (i.e. CPUState.cpu_index) -+ */ -+ qemu_put_be32(f, sizeof(uint32_t)); -+ qemu_put_buffer(f, (uint8_t *)&cpu_index, sizeof(uint32_t)); -+ -+ qemu_put_be32(f, update.hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); -+ -+ qemu_put_be32(f, update.trans_len); -+ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+err: -+ g_free(trans); -+ return ret; -+} -+ -+int csv_save_outgoing_cpu_state(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ CPUState *cpu; -+ int ret = 0; -+ -+ /* Only support migrate VMSAs for HYGON CSV2 guest */ -+ if (!sev_es_enabled() || !is_hygon_cpu()) { -+ return 0; -+ } -+ -+ CPU_FOREACH(cpu) { -+ qemu_put_be32(f, ENCRYPTED_CPU_STATE_CONT); -+ ret = sev_send_update_vmsa(s, f, kvm_arch_vcpu_id(cpu), -+ cpu->cpu_index, TARGET_PAGE_SIZE); -+ if (ret) { -+ goto err; -+ } -+ } -+ -+ qemu_put_be32(f, ENCRYPTED_CPU_STATE_END); -+ -+err: -+ return ret; -+} -+ -+static int sev_receive_update_vmsa(QEMUFile *f) -+{ -+ int ret = 1, fw_error = 0; -+ CPUState *cpu; -+ uint32_t cpu_index, cpu_id = 0; -+ gchar *hdr = NULL, *trans = NULL; -+ struct kvm_sev_receive_update_vmsa update = {}; -+ -+ /* get cpu index buffer */ -+ assert(qemu_get_be32(f) == sizeof(uint32_t)); -+ qemu_get_buffer(f, (uint8_t *)&cpu_index, sizeof(uint32_t)); -+ -+ CPU_FOREACH(cpu) { -+ if (cpu->cpu_index == cpu_index) { -+ cpu_id = kvm_arch_vcpu_id(cpu); -+ break; -+ } -+ } -+ update.vcpu_id = cpu_id; -+ -+ /* get packet header */ -+ update.hdr_len = qemu_get_be32(f); -+ if (!check_blob_length(update.hdr_len)) { -+ return 1; -+ } -+ -+ hdr = g_new(gchar, update.hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); -+ update.hdr_uaddr = (uintptr_t)hdr; -+ -+ /* get transport buffer */ -+ update.trans_len = qemu_get_be32(f); -+ if (!check_blob_length(update.trans_len)) { -+ goto err; -+ } -+ -+ trans = g_new(gchar, update.trans_len); -+ update.trans_uaddr = (uintptr_t)trans; -+ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+ trace_kvm_sev_receive_update_vmsa(cpu_id, cpu_index, -+ trans, update.trans_len, hdr, update.hdr_len); -+ -+ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_RECEIVE_UPDATE_VMSA, -+ &update, &fw_error); -+ if (ret) { -+ error_report("Error RECEIVE_UPDATE_VMSA ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ } -+ -+err: -+ g_free(trans); -+ g_free(hdr); -+ return ret; -+} -+ -+int csv_load_incoming_cpu_state(QEMUFile *f) -+{ -+ int status, ret = 0; -+ -+ /* Only support migrate VMSAs for HYGON CSV2 guest */ -+ if (!sev_es_enabled() || !is_hygon_cpu()) { -+ return 0; -+ } -+ -+ status = qemu_get_be32(f); -+ while (status == ENCRYPTED_CPU_STATE_CONT) { -+ ret = sev_receive_update_vmsa(f); -+ if (ret) { -+ break; -+ } -+ -+ status = qemu_get_be32(f); -+ } -+ -+ return ret; -+} -+ - static const QemuUUID sev_hash_table_header_guid = { - .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, - 0xd4, 0x11, 0xfd, 0x21) -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 345dffac5..8b38567c3 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -44,6 +44,7 @@ typedef struct SevKernelLoaderContext { - #define RAM_SAVE_ENCRYPTED_PAGE_BATCH 0x4 - #define RAM_SAVE_ENCRYPTED_PAGE_BATCH_END 0x5 - #define CSV_OUTGOING_PAGE_WINDOW_SIZE (4094 * TARGET_PAGE_SIZE) -+#define RAM_SAVE_ENCRYPTED_CPU_STATE 0x6 - - #ifdef CONFIG_SEV - bool sev_enabled(void); -@@ -82,6 +83,8 @@ int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr); - int csv_load_queued_incoming_pages(QEMUFile *f); -+int csv_save_outgoing_cpu_state(QEMUFile *f); -+int csv_load_incoming_cpu_state(QEMUFile *f); - - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); -diff --git a/target/i386/trace-events b/target/i386/trace-events -index e32b0319b..60a4609c0 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -17,6 +17,8 @@ kvm_sev_send_finish(void) "" - kvm_sev_receive_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p" - kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_len) "guest %p trans %p len %d hdr %p hdr_len %d" - kvm_sev_receive_finish(void) "" -+kvm_sev_send_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *dst, int len) "cpu_id %d cpu_index %d trans %p len %d" -+kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int len, void *hdr, int hdr_len) "cpu_id %d cpu_index %d trans %p len %d hdr %p hdr_len %d" - - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 --- -2.31.1 - diff --git a/1064-anolis-target-i386-get-set-migrate-GHCB-state.patch b/1064-anolis-target-i386-get-set-migrate-GHCB-state.patch deleted file mode 100644 index a58e394630041ecb581b24c3fce00bcb4a203bc2..0000000000000000000000000000000000000000 --- a/1064-anolis-target-i386-get-set-migrate-GHCB-state.patch +++ /dev/null @@ -1,175 +0,0 @@ -From a95faafa015e094f7252ef35afb74933d07a9334 Mon Sep 17 00:00:00 2001 -From: panpingsheng -Date: Sat, 12 Jun 2021 15:15:29 +0800 -Subject: [PATCH 27/29] anolis: target/i386: get/set/migrate GHCB state - -GHCB state is necessary to CSV2 guest when migrating to target. - -Add GHCB related definition, it also adds corresponding part -to kvm_get/put, and vmstate. - -Signed-off-by: hanliyang ---- - include/sysemu/kvm.h | 1 + - linux-headers/linux/kvm.h | 1 + - target/i386/cpu.h | 4 ++++ - target/i386/kvm/kvm.c | 11 +++++++++++ - target/i386/machine.c | 24 ++++++++++++++++++++++++ - target/i386/sev.c | 10 ++++++++++ - 6 files changed, 51 insertions(+) - -diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h -index 7b22aeb6a..9f8099f48 100644 ---- a/include/sysemu/kvm.h -+++ b/include/sysemu/kvm.h -@@ -46,6 +46,7 @@ extern bool kvm_readonly_mem_allowed; - extern bool kvm_direct_msi_allowed; - extern bool kvm_ioeventfd_any_length_allowed; - extern bool kvm_msi_use_devid; -+extern bool kvm_has_msr_ghcb; - - #define kvm_enabled() (kvm_allowed) - /** -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index e5d282c75..4a177f81d 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1154,6 +1154,7 @@ struct kvm_ppc_resize_hpt { - #define KVM_CAP_S390_PROTECTED_DUMP 217 - #define KVM_CAP_S390_ZPCI_OP 221 - #define KVM_CAP_S390_CPU_TOPOLOGY 222 -+#define KVM_CAP_SEV_ES_GHCB 500 - - #define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) - -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 5d2ddd81b..5c476a029 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -505,6 +505,8 @@ typedef enum X86Seg { - - #define MSR_VM_HSAVE_PA 0xc0010117 - -+#define MSR_AMD64_SEV_ES_GHCB 0xc0010130 -+ - #define MSR_IA32_XFD 0x000001c4 - #define MSR_IA32_XFD_ERR 0x000001c5 - -@@ -1732,6 +1734,8 @@ typedef struct CPUX86State { - TPRAccess tpr_access_type; - - unsigned nr_dies; -+ -+ uint64_t ghcb_gpa; - } CPUX86State; - - struct kvm_msrs; -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index f0b61ec3c..fb85cc698 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -3346,6 +3346,10 @@ static int kvm_put_msrs(X86CPU *cpu, int level) - } - } - -+ if (kvm_has_msr_ghcb) { -+ kvm_msr_entry_add(cpu, MSR_AMD64_SEV_ES_GHCB, env->ghcb_gpa); -+ } -+ - return kvm_buf_set_msrs(cpu); - } - -@@ -3686,6 +3690,10 @@ static int kvm_get_msrs(X86CPU *cpu) - kvm_msr_entry_add(cpu, MSR_IA32_XFD_ERR, 0); - } - -+ if (kvm_has_msr_ghcb) { -+ kvm_msr_entry_add(cpu, MSR_AMD64_SEV_ES_GHCB, 0); -+ } -+ - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf); - if (ret < 0) { - return ret; -@@ -3991,6 +3999,9 @@ static int kvm_get_msrs(X86CPU *cpu) - case MSR_IA32_XFD_ERR: - env->msr_xfd_err = msrs[i].data; - break; -+ case MSR_AMD64_SEV_ES_GHCB: -+ env->ghcb_gpa = msrs[i].data; -+ break; - } - } - -diff --git a/target/i386/machine.c b/target/i386/machine.c -index 3977e9d8f..8aa54432d 100644 ---- a/target/i386/machine.c -+++ b/target/i386/machine.c -@@ -1497,6 +1497,27 @@ static const VMStateDescription vmstate_amx_xtile = { - }; - #endif - -+#if defined(CONFIG_KVM) && defined(TARGET_X86_64) -+static bool msr_ghcb_gpa_needed(void *opaque) -+{ -+ X86CPU *cpu = opaque; -+ CPUX86State *env = &cpu->env; -+ -+ return env->ghcb_gpa != 0; -+} -+ -+static const VMStateDescription vmstate_msr_ghcb_gpa = { -+ .name = "cpu/svm_msr_ghcb_gpa", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .needed = msr_ghcb_gpa_needed, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT64(env.ghcb_gpa, X86CPU), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+#endif -+ - const VMStateDescription vmstate_x86_cpu = { - .name = "cpu", - .version_id = 12, -@@ -1638,6 +1659,9 @@ const VMStateDescription vmstate_x86_cpu = { - &vmstate_msr_xfd, - #ifdef TARGET_X86_64 - &vmstate_amx_xtile, -+#endif -+#if defined(CONFIG_KVM) && defined(TARGET_X86_64) -+ &vmstate_msr_ghcb_gpa, - #endif - NULL - } -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 9cdf3e6bf..26b6e84d3 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -215,6 +215,8 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { - .load_incoming_cpu_state = csv_load_incoming_cpu_state, - }; - -+bool kvm_has_msr_ghcb; -+ - static int - sev_ioctl(int fd, int cmd, void *data, int *error) - { -@@ -1174,6 +1176,14 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; - QTAILQ_INIT(&sev->shared_regions_list); - -+ /* Determine whether support MSR_AMD64_SEV_ES_GHCB */ -+ if (sev_es_enabled()) { -+ kvm_has_msr_ghcb = -+ kvm_vm_check_extension(kvm_state, KVM_CAP_SEV_ES_GHCB); -+ } else { -+ kvm_has_msr_ghcb = false; -+ } -+ - cgs->ready = true; - - return 0; --- -2.31.1 - diff --git a/1065-anolis-target-i386-kvm-Return-resettable-when-emulat.patch b/1065-anolis-target-i386-kvm-Return-resettable-when-emulat.patch deleted file mode 100644 index 966d6ffef29179b3d6fde37cd7b0a74812ace5c0..0000000000000000000000000000000000000000 --- a/1065-anolis-target-i386-kvm-Return-resettable-when-emulat.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 84ea1a98ae7cb888eba8f9be9f51955a4402355c Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Sun, 19 Jun 2022 16:49:45 +0800 -Subject: [PATCH 28/29] anolis: target/i386/kvm: Return resettable when emulate - HYGON CSV2 guest - -SEV-ES guest will be terminated by QEMU when receive reboot request. -In order to support reboot for CSV2 guest, report resettable in -kvm_arch_cpu_check_are_resettable(). - -Signed-off-by: hanliyang ---- - target/i386/kvm/kvm.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index fb85cc698..19c622bb0 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -30,6 +30,7 @@ - #include "sysemu/runstate.h" - #include "kvm_i386.h" - #include "sev.h" -+#include "csv.h" - #include "hyperv.h" - #include "hyperv-proto.h" - -@@ -5363,7 +5364,7 @@ bool kvm_has_waitpkg(void) - - bool kvm_arch_cpu_check_are_resettable(void) - { -- return !sev_es_enabled(); -+ return !(sev_es_enabled() && !is_hygon_cpu()) && !csv_enabled(); - } - - #define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 --- -2.31.1 - diff --git a/1066-anolis-kvm-Add-support-for-CSV2-reboot.patch b/1066-anolis-kvm-Add-support-for-CSV2-reboot.patch deleted file mode 100644 index 3c246b0133aabdd15cb4e3d4af358e4e56fef877..0000000000000000000000000000000000000000 --- a/1066-anolis-kvm-Add-support-for-CSV2-reboot.patch +++ /dev/null @@ -1,170 +0,0 @@ -From a165dedbb9121f948738e5265198410487aa7acf Mon Sep 17 00:00:00 2001 -From: hanliyang -Date: Thu, 15 Apr 2021 08:32:24 -0400 -Subject: [PATCH 29/29] anolis: kvm: Add support for CSV2 reboot - -Linux will set vcpu.arch.guest_state_protected to true after execute -LAUNCH_UPDATE_VMSA successfully, and then KVM will prevent any changes -to VMCB State Save Area. - -In order to support CSV2 guest reboot, calls cpus_control_pre_system_reset() -to set vcpu.arch.guest_state_protected to false, and calls -cpus_control_post_system_reset() to restore VMSA of guest's vcpu with -data generated by LAUNCH_UPDATE_VMSA. - -In addition, for memory encrypted guest, additional works may be -required during system reset, such as flushing the cache. The function -cpus_control_post_system_reset() hints linux to flush caches of guest -memory. - -Signed-off-by: hanliyang ---- - accel/kvm/kvm-accel-ops.c | 3 +++ - accel/kvm/kvm-all.c | 10 ++++++++++ - accel/kvm/kvm-cpus.h | 3 +++ - include/sysemu/accel-ops.h | 3 +++ - include/sysemu/cpus.h | 2 ++ - linux-headers/linux/kvm.h | 4 ++++ - softmmu/cpus.c | 14 ++++++++++++++ - softmmu/runstate.c | 4 ++++ - 8 files changed, 43 insertions(+) - -diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c -index 7516c67a3..9602f9609 100644 ---- a/accel/kvm/kvm-accel-ops.c -+++ b/accel/kvm/kvm-accel-ops.c -@@ -83,6 +83,9 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, void *data) - ops->synchronize_post_init = kvm_cpu_synchronize_post_init; - ops->synchronize_state = kvm_cpu_synchronize_state; - ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm; -+ -+ ops->control_pre_system_reset = kvm_cpus_control_pre_system_reset; -+ ops->control_post_system_reset = kvm_cpus_control_post_system_reset; - } - - static const TypeInfo kvm_accel_ops_type = { -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 6d63f0ab0..10af4170d 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -2848,6 +2848,16 @@ void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu) - run_on_cpu(cpu, do_kvm_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL); - } - -+void kvm_cpus_control_pre_system_reset(void) -+{ -+ kvm_vm_ioctl(kvm_state, KVM_CONTROL_VCPU_PRE_SYSTEM_RESET, NULL); -+} -+ -+void kvm_cpus_control_post_system_reset(void) -+{ -+ kvm_vm_ioctl(kvm_state, KVM_CONTROL_VCPU_POST_SYSTEM_RESET, NULL); -+} -+ - #ifdef KVM_HAVE_MCE_INJECTION - static __thread void *pending_sigbus_addr; - static __thread int pending_sigbus_code; -diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h -index bf0bd1bee..8ba363e0b 100644 ---- a/accel/kvm/kvm-cpus.h -+++ b/accel/kvm/kvm-cpus.h -@@ -19,4 +19,7 @@ void kvm_cpu_synchronize_post_reset(CPUState *cpu); - void kvm_cpu_synchronize_post_init(CPUState *cpu); - void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu); - -+void kvm_cpus_control_pre_system_reset(void); -+void kvm_cpus_control_post_system_reset(void); -+ - #endif /* KVM_CPUS_H */ -diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h -index 032f6979d..43893c1a4 100644 ---- a/include/sysemu/accel-ops.h -+++ b/include/sysemu/accel-ops.h -@@ -40,6 +40,9 @@ struct AccelOpsClass { - - int64_t (*get_virtual_clock)(void); - int64_t (*get_elapsed_ticks)(void); -+ -+ void (*control_pre_system_reset)(void); -+ void (*control_post_system_reset)(void); - }; - - #endif /* ACCEL_OPS_H */ -diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h -index 868f1192d..70d6e8ad3 100644 ---- a/include/sysemu/cpus.h -+++ b/include/sysemu/cpus.h -@@ -42,6 +42,8 @@ extern int icount_align_option; - void qemu_cpu_kick_self(void); - - bool cpus_are_resettable(void); -+void cpus_control_pre_system_reset(void); -+void cpus_control_post_system_reset(void); - - void cpu_synchronize_all_states(void); - void cpu_synchronize_all_post_reset(void); -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 4a177f81d..d5278df1c 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1528,6 +1528,10 @@ struct kvm_s390_ucas_mapping { - #define KVM_GET_DEVICE_ATTR _IOW(KVMIO, 0xe2, struct kvm_device_attr) - #define KVM_HAS_DEVICE_ATTR _IOW(KVMIO, 0xe3, struct kvm_device_attr) - -+/* ioctls for control vcpu setup during system reset */ -+#define KVM_CONTROL_VCPU_PRE_SYSTEM_RESET _IO(KVMIO, 0xe8) -+#define KVM_CONTROL_VCPU_POST_SYSTEM_RESET _IO(KVMIO, 0xe9) -+ - /* - * ioctls for vcpu fds - */ -diff --git a/softmmu/cpus.c b/softmmu/cpus.c -index 071085f84..319a72d92 100644 ---- a/softmmu/cpus.c -+++ b/softmmu/cpus.c -@@ -200,6 +200,20 @@ bool cpus_are_resettable(void) - return cpu_check_are_resettable(); - } - -+void cpus_control_pre_system_reset(void) -+{ -+ if (cpus_accel->control_pre_system_reset) { -+ cpus_accel->control_pre_system_reset(); -+ } -+} -+ -+void cpus_control_post_system_reset(void) -+{ -+ if (cpus_accel->control_post_system_reset) { -+ cpus_accel->control_post_system_reset(); -+ } -+} -+ - int64_t cpus_get_virtual_clock(void) - { - /* -diff --git a/softmmu/runstate.c b/softmmu/runstate.c -index 10d9b7365..4b9c9f9e0 100644 ---- a/softmmu/runstate.c -+++ b/softmmu/runstate.c -@@ -437,6 +437,8 @@ void qemu_system_reset(ShutdownCause reason) - - mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; - -+ cpus_control_pre_system_reset(); -+ - cpu_synchronize_all_states(); - - if (mc && mc->reset) { -@@ -448,6 +450,8 @@ void qemu_system_reset(ShutdownCause reason) - qapi_event_send_reset(shutdown_caused_by_guest(reason), reason); - } - cpu_synchronize_all_post_reset(); -+ -+ cpus_control_post_system_reset(); - } - - /* --- -2.31.1 - diff --git a/1067-anolis-vfio-only-map-shared-region-for-CSV-virtual-m.patch b/1067-anolis-vfio-only-map-shared-region-for-CSV-virtual-m.patch deleted file mode 100644 index 6e1d41881e9d91ea5a190a7e4fa8374c0ce828ef..0000000000000000000000000000000000000000 --- a/1067-anolis-vfio-only-map-shared-region-for-CSV-virtual-m.patch +++ /dev/null @@ -1,384 +0,0 @@ -From 3b532188e4eac7fd291cf66970126a18af024364 Mon Sep 17 00:00:00 2001 -From: liuyafei -Date: Mon, 22 May 2023 20:37:40 +0800 -Subject: [PATCH 1067/1072] anolis: vfio: only map shared region for CSV - virtual machine - -qemu vfio listener map/unmap all of the virtual machine's memory. -It does not work for CSV virtual machine, as only shared memory -should be accessed by device. - -Change-Id: I3f281c28166a36f2bed8ea193523715af9ff3271 ---- - hw/vfio/common.c | 40 +++++++++- - include/exec/memory.h | 11 +++ - softmmu/memory.c | 18 +++++ - target/i386/csv-sysemu-stub.c | 10 +++ - target/i386/csv.c | 134 ++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 12 +++ - target/i386/kvm/kvm.c | 2 + - 7 files changed, 225 insertions(+), 2 deletions(-) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 080046e3f5..7cc03a7ef9 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -41,6 +41,9 @@ - #include "qapi/error.h" - #include "migration/migration.h" - -+#include "target/i386/sev.h" -+#include "target/i386/csv.h" -+ - VFIOGroupList vfio_group_list = - QLIST_HEAD_INITIALIZER(vfio_group_list); - static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = -@@ -1251,6 +1254,30 @@ static void vfio_listener_log_global_stop(MemoryListener *listener) - vfio_set_dirty_page_tracking(container, false); - } - -+static SharedRegionListener *g_shl; -+static void shared_memory_listener_register(MemoryListener *listener, AddressSpace *as) -+{ -+ SharedRegionListener *shl; -+ -+ shl = g_new0(SharedRegionListener, 1); -+ -+ shl->listener = listener; -+ shl->as = as; -+ -+ shared_region_register_listener(shl); -+ g_shl = shl; -+} -+ -+static void shared_memory_listener_unregister(void) -+{ -+ SharedRegionListener *shl = g_shl; -+ -+ shared_region_unregister_listener(shl); -+ -+ g_free(shl); -+ g_shl = NULL; -+} -+ - static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, - uint64_t size, ram_addr_t ram_addr) - { -@@ -1453,7 +1480,12 @@ static const MemoryListener vfio_memory_listener = { - - static void vfio_listener_release(VFIOContainer *container) - { -- memory_listener_unregister(&container->listener); -+ if (csv_enabled()) { -+ shared_memory_listener_unregister(); -+ } else { -+ memory_listener_unregister(&container->listener); -+ } -+ - if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - memory_listener_unregister(&container->prereg_listener); - } -@@ -2183,7 +2215,11 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - - container->listener = vfio_memory_listener; - -- memory_listener_register(&container->listener, container->space->as); -+ if (csv_enabled()) { -+ shared_memory_listener_register(&container->listener, container->space->as); -+ } else { -+ memory_listener_register(&container->listener, container->space->as); -+ } - - if (container->error) { - ret = -1; -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 20f1b27377..d4bd90dfcc 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -710,6 +710,17 @@ void ram_discard_manager_register_listener(RamDiscardManager *rdm, - void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, - RamDiscardListener *rdl); - -+typedef struct SharedRegionListener SharedRegionListener; -+struct SharedRegionListener { -+ MemoryListener *listener; -+ AddressSpace *as; -+ QTAILQ_ENTRY(SharedRegionListener) next; -+}; -+ -+void shared_region_register_listener(SharedRegionListener *shl); -+void shared_region_unregister_listener(SharedRegionListener *shl); -+void *shared_region_listeners_get(void); -+ - typedef struct CoalescedMemoryRange CoalescedMemoryRange; - typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd; - -diff --git a/softmmu/memory.c b/softmmu/memory.c -index 7340e19ff5..b435bb4aa3 100644 ---- a/softmmu/memory.c -+++ b/softmmu/memory.c -@@ -47,6 +47,9 @@ static QTAILQ_HEAD(, MemoryListener) memory_listeners - static QTAILQ_HEAD(, AddressSpace) address_spaces - = QTAILQ_HEAD_INITIALIZER(address_spaces); - -+static QTAILQ_HEAD(, SharedRegionListener) shared_region_listeners -+ = QTAILQ_HEAD_INITIALIZER(shared_region_listeners); -+ - static GHashTable *flat_views; - - typedef struct AddrRange AddrRange; -@@ -2111,6 +2114,21 @@ void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, - rdmc->unregister_listener(rdm, rdl); - } - -+void shared_region_register_listener(SharedRegionListener *shl) -+{ -+ QTAILQ_INSERT_TAIL(&shared_region_listeners, shl, next); -+} -+ -+void shared_region_unregister_listener(SharedRegionListener *shl) -+{ -+ QTAILQ_REMOVE(&shared_region_listeners, shl, next); -+} -+ -+void *shared_region_listeners_get(void) -+{ -+ return &shared_region_listeners; -+} -+ - void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) - { - uint8_t mask = 1 << client; -diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c -index a5ce986e3c..96ca055270 100644 ---- a/target/i386/csv-sysemu-stub.c -+++ b/target/i386/csv-sysemu-stub.c -@@ -29,3 +29,13 @@ int csv_launch_encrypt_vmcb(void) - { - g_assert_not_reached(); - } -+ -+int csv_shared_region_dma_map(uint64_t start, uint64_t end) -+{ -+ return 0; -+} -+ -+void csv_shared_region_dma_unmap(uint64_t start, uint64_t end) -+{ -+ -+} -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 161cad39ae..6d05382fb2 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -24,6 +24,7 @@ - #include "cpu.h" - #include "sev.h" - #include "csv.h" -+#include "exec/address-spaces.h" - - CsvGuestState csv_guest = { 0 }; - -@@ -63,6 +64,8 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - csv_guest.state = state; - csv_guest.sev_ioctl = ops->sev_ioctl; - csv_guest.fw_error_to_str = ops->fw_error_to_str; -+ QTAILQ_INIT(&csv_guest.dma_map_regions_list); -+ qemu_mutex_init(&csv_guest.dma_map_regions_list_mutex); - } - return 0; - } -@@ -163,3 +166,134 @@ csv_launch_encrypt_vmcb(void) - err: - return ret; - } -+ -+int csv_shared_region_dma_map(uint64_t start, uint64_t end) -+{ -+ MemoryRegionSection section; -+ AddressSpace *as; -+ QTAILQ_HEAD(, SharedRegionListener) *shared_region_listeners; -+ SharedRegionListener *shl; -+ MemoryListener *listener; -+ uint64_t size; -+ CsvGuestState *s = &csv_guest; -+ struct dma_map_region *region, *pos; -+ int ret = 0; -+ -+ if (!csv_enabled()) -+ return 0; -+ -+ if (end <= start) -+ return 0; -+ -+ shared_region_listeners = shared_region_listeners_get(); -+ if (QTAILQ_EMPTY(shared_region_listeners)) -+ return 0; -+ -+ size = end - start; -+ -+ qemu_mutex_lock(&s->dma_map_regions_list_mutex); -+ QTAILQ_FOREACH(pos, &s->dma_map_regions_list, list) { -+ if (start >= (pos->start + pos->size)) { -+ continue; -+ } else if ((start + size) <= pos->start) { -+ break; -+ } else { -+ goto end; -+ } -+ } -+ QTAILQ_FOREACH(shl, shared_region_listeners, next) { -+ listener = shl->listener; -+ as = shl->as; -+ section = memory_region_find(as->root, start, size); -+ if (!section.mr) { -+ goto end; -+ } -+ -+ if (!memory_region_is_ram(section.mr)) { -+ memory_region_unref(section.mr); -+ goto end; -+ } -+ -+ if (listener->region_add) { -+ listener->region_add(listener, §ion); -+ } -+ memory_region_unref(section.mr); -+ } -+ -+ region = g_malloc0(sizeof(*region)); -+ if (!region) { -+ ret = -1; -+ goto end; -+ } -+ region->start = start; -+ region->size = size; -+ -+ if (pos) { -+ QTAILQ_INSERT_BEFORE(pos, region, list); -+ } else { -+ QTAILQ_INSERT_TAIL(&s->dma_map_regions_list, region, list); -+ } -+ -+end: -+ qemu_mutex_unlock(&s->dma_map_regions_list_mutex); -+ return ret; -+} -+ -+void csv_shared_region_dma_unmap(uint64_t start, uint64_t end) -+{ -+ MemoryRegionSection section; -+ AddressSpace *as; -+ QTAILQ_HEAD(, SharedRegionListener) *shared_region_listeners; -+ SharedRegionListener *shl; -+ MemoryListener *listener; -+ uint64_t size; -+ CsvGuestState *s = &csv_guest; -+ struct dma_map_region *pos, *next_pos; -+ -+ if (!csv_enabled()) -+ return; -+ -+ if (end <= start) -+ return; -+ -+ shared_region_listeners = shared_region_listeners_get(); -+ if (QTAILQ_EMPTY(shared_region_listeners)) -+ return; -+ -+ size = end - start; -+ -+ qemu_mutex_lock(&s->dma_map_regions_list_mutex); -+ QTAILQ_FOREACH_SAFE(pos, &s->dma_map_regions_list, list, next_pos) { -+ uint64_t l, r; -+ uint64_t curr_end = pos->start + pos->size; -+ -+ l = MAX(start, pos->start); -+ r = MIN(start + size, pos->start + pos->size); -+ if (l < r) { -+ if ((start <= pos->start) && (start + size >= pos->start + pos->size)) { -+ QTAILQ_FOREACH(shl, shared_region_listeners, next) { -+ listener = shl->listener; -+ as = shl->as; -+ section = memory_region_find(as->root, pos->start, pos->size); -+ if (!section.mr) { -+ goto end; -+ } -+ if (listener->region_del) { -+ listener->region_del(listener, §ion); -+ } -+ memory_region_unref(section.mr); -+ } -+ -+ QTAILQ_REMOVE(&s->dma_map_regions_list, pos, list); -+ g_free(pos); -+ } -+ break; -+ } -+ if ((start + size) <= curr_end) { -+ break; -+ } -+ } -+end: -+ qemu_mutex_unlock(&s->dma_map_regions_list_mutex); -+ return; -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index e51cc83022..6412c0c70b 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -15,6 +15,8 @@ - #define QEMU_CSV_H - - #include "qapi/qapi-commands-misc-target.h" -+#include "qemu/thread.h" -+#include "qemu/queue.h" - - #ifdef CONFIG_SEV - -@@ -55,12 +57,19 @@ bool csv_enabled(void); - #define csv_enabled() 0 - #endif - -+struct dma_map_region { -+ uint64_t start, size; -+ QTAILQ_ENTRY(dma_map_region) list; -+}; -+ - struct CsvGuestState { - uint32_t policy; - int sev_fd; - void *state; - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); - const char *(*fw_error_to_str)(int code); -+ QTAILQ_HEAD(, dma_map_region) dma_map_regions_list; -+ QemuMutex dma_map_regions_list_mutex; - }; - - typedef struct CsvGuestState CsvGuestState; -@@ -71,4 +80,7 @@ extern int csv_launch_encrypt_vmcb(void); - - int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - -+int csv_shared_region_dma_map(uint64_t start, uint64_t end); -+void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); -+ - #endif -diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c -index 6192bcd36e..090800257f 100644 ---- a/target/i386/kvm/kvm.c -+++ b/target/i386/kvm/kvm.c -@@ -4626,8 +4626,10 @@ static int kvm_handle_exit_hypercall(X86CPU *cpu, struct kvm_run *run) - - if (enc) { - sev_remove_shared_regions_list(gfn_start, gfn_end); -+ csv_shared_region_dma_unmap(gpa, gfn_end << TARGET_PAGE_BITS); - } else { - sev_add_shared_regions_list(gfn_start, gfn_end); -+ csv_shared_region_dma_map(gpa, gfn_end << TARGET_PAGE_BITS); - } - } - return 0; --- -2.17.1 - diff --git a/1068-anolis-linux-headers-update-kernel-headers-to-includ.patch b/1068-anolis-linux-headers-update-kernel-headers-to-includ.patch deleted file mode 100644 index 209ebd951fd0343f42ac11f296ee754417a17ea6..0000000000000000000000000000000000000000 --- a/1068-anolis-linux-headers-update-kernel-headers-to-includ.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 69976084e81798c275286b5bd3641d4b58896b72 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 09:25:19 +0800 -Subject: [PATCH 1068/1072] anolis: linux-headers: update kernel headers to - include CSV migration cmds - -Four new migration commands are added to support CSV migration. - -KVM_CSV_SEND_ENCRYPT_DATA/KVM_CSV_RECEIVE_ENCRYPT_DATA cmds are -used to migrate guest's pages. - -KVM_CSV_SEND_ENCRYPT_CONTEXT/KVM_CSV_RECEIVE_ENCRYPT_CONTEXT cmds -are used to migration guest's runtime context. - -Change-Id: Ib3b733c7b5713aa6a6648c65e03cf8c9618ff1af -Signed-off-by: Xin Jiang ---- - linux-headers/linux/kvm.h | 38 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 38 insertions(+) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 1a2c3ea87d..cbf4fe4ecb 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -1842,6 +1842,12 @@ enum csv_cmd_id { - KVM_CSV_INIT = KVM_CSV_NR_MIN, - KVM_CSV_LAUNCH_ENCRYPT_DATA, - KVM_CSV_LAUNCH_ENCRYPT_VMCB, -+ KVM_CSV_SEND_ENCRYPT_DATA, -+ KVM_CSV_SEND_ENCRYPT_CONTEXT, -+ KVM_CSV_RECEIVE_ENCRYPT_DATA, -+ KVM_CSV_RECEIVE_ENCRYPT_CONTEXT, -+ -+ KVM_CSV_NR_MAX, - }; - - struct kvm_csv_launch_encrypt_data { -@@ -1865,6 +1871,38 @@ struct kvm_csv_command_batch { - __u64 csv_batch_list_uaddr; - }; - -+struct kvm_csv_send_encrypt_data { -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 guest_addr_data; -+ __u32 guest_addr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ -+struct kvm_csv_send_encrypt_context { -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ -+struct kvm_csv_receive_encrypt_data { -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 guest_addr_data; -+ __u32 guest_addr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ -+struct kvm_csv_receive_encrypt_context { -+ __u64 hdr_uaddr; -+ __u32 hdr_len; -+ __u64 trans_uaddr; -+ __u32 trans_len; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) --- -2.17.1 - diff --git a/1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch b/1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch deleted file mode 100644 index 1d941ca68fbf3d56ee0667d267fe98f60c02265a..0000000000000000000000000000000000000000 --- a/1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch +++ /dev/null @@ -1,453 +0,0 @@ -From 967c7ad199c55223cc03d0217c6f256d3d418be2 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 09:37:56 +0800 -Subject: [PATCH 1069/1072] anolis: csv/i386: add support to migrate the - outgoing page - -The csv_send_encrypt_data() provides the method to encrypt the -guest's private pages during migration. The routine is similar to -CSV2's. Usually, it starts with a SEND_START command to create the -migration context. Then SEND_ENCRYPT_DATA command is performed to -encrypt guest pages. After migration is completed, a SEND_FINISH -command is performed to the firmware. - -Change-Id: I6781119890036636d8f5c0a19c6647fa8a33a37d ---- - migration/ram.c | 83 ++++++++++++++++++ - target/i386/csv.c | 185 +++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 22 +++++ - target/i386/sev.c | 13 ++- - target/i386/sev.h | 1 + - target/i386/trace-events | 1 + - 6 files changed, 304 insertions(+), 1 deletion(-) - -diff --git a/migration/ram.c b/migration/ram.c -index 1dcd5c8553..c962496684 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -2452,6 +2452,86 @@ ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss, bool last - } - #endif - -+/** -+ * ram_save_csv_pages - send the given csv VM pages to the stream -+ */ -+static int ram_save_csv_pages(RAMState *rs, PageSearchStatus *pss, -+ bool last_stage) -+{ -+ int ret; -+ int tmppages = 0, pages = 0; -+ RAMBlock *block = pss->block; -+ ram_addr_t offset = 0; -+ hwaddr paddr = RAM_ADDR_INVALID; -+ uint32_t host_len = 0; -+ uint8_t *p; -+ uint64_t bytes_xmit; -+ MachineState *ms = MACHINE(qdev_get_machine()); -+ ConfidentialGuestSupportClass *cgs_class = -+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); -+ struct ConfidentialGuestMemoryEncryptionOps *ops = -+ cgs_class->memory_encryption_ops; -+ -+ if (!csv_enabled()) -+ return 0; -+ -+ do { -+ /* Check the pages is dirty and if it is send it */ -+ if (!migration_bitmap_clear_dirty(rs, block, pss->page)) { -+ pss->page++; -+ continue; -+ } -+ -+ ret = kvm_physical_memory_addr_from_host(kvm_state, -+ block->host + (pss->page << TARGET_PAGE_BITS), &paddr); -+ /* Process ROM or MMIO */ -+ if (paddr == RAM_ADDR_INVALID || memory_region_is_rom(block->mr)) -+ tmppages = ram_save_target_page(rs, pss, last_stage); -+ else { -+ /* Caculate the offset and host virtual address of the page */ -+ offset = pss->page << TARGET_PAGE_BITS; -+ p = block->host + offset; -+ -+ if (ops->queue_outgoing_page(p, TARGET_PAGE_SIZE, offset)) -+ return -1; -+ -+ tmppages = 1; -+ host_len += TARGET_PAGE_SIZE; -+ ram_counters.normal++; -+ } -+ -+ if (tmppages < 0) { -+ return tmppages; -+ } -+ -+ pages += tmppages; -+ -+ pss->page++; -+ } while (offset_in_ramblock(block, pss->page << TARGET_PAGE_BITS) && -+ host_len < CSV3_OUTGOING_PAGE_WINDOW_SIZE); -+ -+ /* Check if there are any queued pages */ -+ if (host_len != 0) { -+ /* Always set offset as 0 for csv. */ -+ ram_counters.transferred += -+ save_page_header(rs, rs->f, block, 0 | RAM_SAVE_FLAG_ENCRYPTED_DATA); -+ -+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_PAGE); -+ ram_counters.transferred += 4; -+ /* Process the queued pages in batch */ -+ ret = ops->save_queued_outgoing_pages(rs->f, &bytes_xmit); -+ if (ret) { -+ return -1; -+ } -+ ram_counters.transferred += bytes_xmit; -+ } -+ -+ /* The offset we leave with is the last one we looked at */ -+ pss->page--; -+ -+ return pages; -+} -+ - /** - * ram_save_host_page: save a whole host page - * -@@ -2486,6 +2566,9 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, - return 0; - } - -+ if (csv_enabled()) -+ return ram_save_csv_pages(rs, pss, last_stage); -+ - #ifdef CONFIG_HYGON_CSV_MIG_ACCEL - /* - * If command_batch function is enabled and memory encryption is enabled -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 6d05382fb2..c5a2bc9924 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -13,6 +13,7 @@ - - #include "qemu/osdep.h" - -+#include - #include - #include "qapi/error.h" - -@@ -20,12 +21,30 @@ - #include - #endif - -+#include "migration/blocker.h" -+#include "migration/qemu-file.h" -+#include "migration/misc.h" -+#include "monitor/monitor.h" -+#include "sysemu/kvm.h" -+ - #include "trace.h" - #include "cpu.h" - #include "sev.h" - #include "csv.h" - #include "exec/address-spaces.h" - -+struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = { -+ .save_setup = sev_save_setup, -+ .save_outgoing_page = NULL, -+ .is_gfn_in_unshared_region = NULL, -+ .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, -+ .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, -+ .queue_outgoing_page = csv3_queue_outgoing_page, -+ .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, -+}; -+ -+#define CSV_OUTGOING_PAGE_NUM (CSV3_OUTGOING_PAGE_WINDOW_SIZE/TARGET_PAGE_SIZE) -+ - CsvGuestState csv_guest = { 0 }; - - #define GUEST_POLICY_CSV_BIT (1 << 6) -@@ -66,6 +85,7 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - csv_guest.fw_error_to_str = ops->fw_error_to_str; - QTAILQ_INIT(&csv_guest.dma_map_regions_list); - qemu_mutex_init(&csv_guest.dma_map_regions_list_mutex); -+ csv_guest.sev_send_start = ops->sev_send_start; - } - return 0; - } -@@ -297,3 +317,168 @@ end: - qemu_mutex_unlock(&s->dma_map_regions_list_mutex); - return; - } -+ -+static inline hwaddr csv_hva_to_gfn(uint8_t *ptr) -+{ -+ ram_addr_t offset = RAM_ADDR_INVALID; -+ -+ kvm_physical_memory_addr_from_host(kvm_state, ptr, &offset); -+ -+ return offset >> TARGET_PAGE_BITS; -+} -+ -+static int -+csv_send_start(QEMUFile *f, uint64_t *bytes_sent) -+{ -+ if (csv_guest.sev_send_start) -+ return csv_guest.sev_send_start(f, bytes_sent); -+ else -+ return -1; -+} -+ -+static int -+csv_send_get_packet_len(int *fw_err) -+{ -+ int ret; -+ struct kvm_csv_send_encrypt_data update = {0}; -+ -+ update.hdr_len = 0; -+ update.trans_len = 0; -+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_DATA, &update, fw_err); -+ if (*fw_err != SEV_RET_INVALID_LEN) { -+ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ ret = 0; -+ goto err; -+ } -+ -+ if (update.hdr_len <= INT_MAX) -+ ret = update.hdr_len; -+ else -+ ret = 0; -+ -+err: -+ return ret; -+} -+ -+static int -+csv_send_encrypt_data(CsvGuestState *s, QEMUFile *f, uint8_t *ptr, uint32_t size, -+ uint64_t *bytes_sent) -+{ -+ int ret, fw_error = 0; -+ guchar *trans; -+ uint32_t guest_addr_entry_num; -+ uint32_t i; -+ struct kvm_csv_send_encrypt_data update = { }; -+ -+ /* -+ * If this is first call then query the packet header bytes and allocate -+ * the packet buffer. -+ */ -+ if (!s->send_packet_hdr) { -+ s->send_packet_hdr_len = csv_send_get_packet_len(&fw_error); -+ if (s->send_packet_hdr_len < 1) { -+ error_report("%s: SEND_UPDATE fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ -+ s->send_packet_hdr = g_new(gchar, s->send_packet_hdr_len); -+ } -+ -+ if (!s->guest_addr_len || !s->guest_addr_data) { -+ error_report("%s: invalid host address or size", __func__); -+ return 1; -+ } else { -+ guest_addr_entry_num = s->guest_addr_len / sizeof(struct guest_addr_entry); -+ } -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, guest_addr_entry_num * TARGET_PAGE_SIZE); -+ -+ update.hdr_uaddr = (uintptr_t)s->send_packet_hdr; -+ update.hdr_len = s->send_packet_hdr_len; -+ update.guest_addr_data = (uintptr_t)s->guest_addr_data; -+ update.guest_addr_len = s->guest_addr_len; -+ update.trans_uaddr = (uintptr_t)trans; -+ update.trans_len = guest_addr_entry_num * TARGET_PAGE_SIZE; -+ -+ trace_kvm_csv_send_encrypt_data(trans, update.trans_len); -+ -+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_DATA, &update, &fw_error); -+ if (ret) { -+ error_report("%s: SEND_ENCRYPT_DATA ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ for (i = 0; i < guest_addr_entry_num; i++) { -+ if (s->guest_addr_data[i].share) -+ memcpy(trans + i * TARGET_PAGE_SIZE, (guchar *)s->guest_hva_data[i].hva, -+ TARGET_PAGE_SIZE); -+ } -+ -+ qemu_put_be32(f, update.hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); -+ *bytes_sent = 4 + update.hdr_len; -+ -+ qemu_put_be32(f, update.guest_addr_len); -+ qemu_put_buffer(f, (uint8_t *)update.guest_addr_data, update.guest_addr_len); -+ *bytes_sent = 4 + update.guest_addr_len; -+ -+ qemu_put_be32(f, update.trans_len); -+ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ *bytes_sent += (4 + update.trans_len); -+ -+err: -+ s->guest_addr_len = 0; -+ g_free(trans); -+ return ret; -+} -+ -+int -+csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) -+{ -+ CsvGuestState *s = &csv_guest; -+ uint32_t i = 0; -+ -+ (void) addr; -+ -+ if (!s->guest_addr_data) { -+ s->guest_hva_data = g_new0(struct guest_hva_entry, CSV_OUTGOING_PAGE_NUM); -+ s->guest_addr_data = g_new0(struct guest_addr_entry, CSV_OUTGOING_PAGE_NUM); -+ s->guest_addr_len = 0; -+ } -+ -+ if (s->guest_addr_len >= sizeof(struct guest_addr_entry) * CSV_OUTGOING_PAGE_NUM) { -+ error_report("Failed to queue outgoing page"); -+ return 1; -+ } -+ -+ i = s->guest_addr_len / sizeof(struct guest_addr_entry); -+ s->guest_hva_data[i].hva = (uintptr_t)ptr; -+ s->guest_addr_data[i].share = 0; -+ s->guest_addr_data[i].reserved = 0; -+ s->guest_addr_data[i].gfn = csv_hva_to_gfn(ptr); -+ s->guest_addr_len += sizeof(struct guest_addr_entry); -+ -+ return 0; -+} -+ -+int -+csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) -+{ -+ CsvGuestState *s = &csv_guest; -+ -+ /* -+ * If this is a first buffer then create outgoing encryption context -+ * and write our PDH, policy and session data. -+ */ -+ if (!csv_check_state(SEV_STATE_SEND_UPDATE) && -+ csv_send_start(f, bytes_sent)) { -+ error_report("Failed to create outgoing context"); -+ return 1; -+ } -+ -+ return csv_send_encrypt_data(s, f, NULL, 0, bytes_sent); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 6412c0c70b..273d69d12c 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -62,6 +62,18 @@ struct dma_map_region { - QTAILQ_ENTRY(dma_map_region) list; - }; - -+#define CSV3_OUTGOING_PAGE_WINDOW_SIZE (512 * TARGET_PAGE_SIZE) -+ -+struct guest_addr_entry { -+ uint64_t share: 1; -+ uint64_t reserved: 11; -+ uint64_t gfn: 52; -+}; -+ -+struct guest_hva_entry { -+ uint64_t hva; -+}; -+ - struct CsvGuestState { - uint32_t policy; - int sev_fd; -@@ -70,6 +82,13 @@ struct CsvGuestState { - const char *(*fw_error_to_str)(int code); - QTAILQ_HEAD(, dma_map_region) dma_map_regions_list; - QemuMutex dma_map_regions_list_mutex; -+ gchar *send_packet_hdr; -+ size_t send_packet_hdr_len; -+ struct guest_hva_entry *guest_hva_data; -+ struct guest_addr_entry *guest_addr_data; -+ size_t guest_addr_len; -+ -+ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); - }; - - typedef struct CsvGuestState CsvGuestState; -@@ -77,10 +96,13 @@ typedef struct CsvGuestState CsvGuestState; - extern struct CsvGuestState csv_guest; - extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); - extern int csv_launch_encrypt_vmcb(void); -+extern struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops; - - int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - - int csv_shared_region_dma_map(uint64_t start, uint64_t end); - void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); -+int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); -+int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - - #endif -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 26b6e84d3f..31af1ecdf3 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -1173,7 +1173,10 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - qemu_add_vm_change_state_handler(sev_vm_state_change, sev); - add_migration_state_change_notifier(&sev_migration_state_notify); - -- cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; -+ if (csv_enabled()) -+ cgs_class->memory_encryption_ops = &csv_memory_encryption_ops; -+ else -+ cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; - QTAILQ_INIT(&sev->shared_regions_list); - - /* Determine whether support MSR_AMD64_SEV_ES_GHCB */ -@@ -2552,9 +2555,17 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) - return ret; - } - -+static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) -+{ -+ SevGuestState *s = sev_guest; -+ -+ return sev_send_start(s, f, bytes_sent); -+} -+ - struct sev_ops sev_ops = { - .sev_ioctl = sev_ioctl, - .fw_error_to_str = fw_error_to_str, -+ .sev_send_start = _sev_send_start, - }; - - static void -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 8b38567c3d..6d1a918413 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -89,6 +89,7 @@ int csv_load_incoming_cpu_state(QEMUFile *f); - struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); - const char *(*fw_error_to_str)(int code); -+ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); - }; - - #endif -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 60a4609c0f..8db3e36385 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -22,3 +22,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int - - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 -+kvm_csv_send_encrypt_data(void *dst, int len) "trans %p len %d" --- -2.17.1 - diff --git a/1070-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch b/1070-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch deleted file mode 100644 index 39a15d4338514cf7c3fef9315213e286a321c5f4..0000000000000000000000000000000000000000 --- a/1070-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch +++ /dev/null @@ -1,204 +0,0 @@ -From e6b96ff4918864bfb3ace811d46cdee74b7a7d91 Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 09:45:45 +0800 -Subject: [PATCH 1070/1072] anolis: csv/i386: add support to migrate the - incoming page - -The csv_receive_encrypt_data() provides the method to read incoming -guest private pages from socket and load them into guest memory. -The routine is similar to CSV2's. Usually, it starts with a RECEIVE -START command to create the migration context. Then RECEIVE ENCRYPT -DATA command is performed to let the firmware load incoming pages -into guest memory. After migration is completed, a RECEIVE FINISH -command is performed to the firmware. - -Change-Id: I53bc350e379fa747c7b3c3b3be9f2fef0bf1af9f ---- - target/i386/csv.c | 87 ++++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 2 + - target/i386/sev.c | 8 ++++ - target/i386/sev.h | 1 + - target/i386/trace-events | 1 + - 5 files changed, 99 insertions(+) - -diff --git a/target/i386/csv.c b/target/i386/csv.c -index c5a2bc9924..00ff7d20a5 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -36,11 +36,14 @@ - struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = { - .save_setup = sev_save_setup, - .save_outgoing_page = NULL, -+ .load_incoming_page = csv3_load_incoming_page, - .is_gfn_in_unshared_region = NULL, - .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, - .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, - .queue_outgoing_page = csv3_queue_outgoing_page, - .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, -+ .queue_incoming_page = NULL, -+ .load_queued_incoming_pages = NULL, - }; - - #define CSV_OUTGOING_PAGE_NUM (CSV3_OUTGOING_PAGE_WINDOW_SIZE/TARGET_PAGE_SIZE) -@@ -86,6 +89,7 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) - QTAILQ_INIT(&csv_guest.dma_map_regions_list); - qemu_mutex_init(&csv_guest.dma_map_regions_list_mutex); - csv_guest.sev_send_start = ops->sev_send_start; -+ csv_guest.sev_receive_start = ops->sev_receive_start; - } - return 0; - } -@@ -482,3 +486,86 @@ csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) - - return csv_send_encrypt_data(s, f, NULL, 0, bytes_sent); - } -+ -+static int -+csv_receive_start(QEMUFile *f) -+{ -+ if (csv_guest.sev_receive_start) -+ return csv_guest.sev_receive_start(f); -+ else -+ return -1; -+} -+ -+static int csv_receive_encrypt_data(QEMUFile *f, uint8_t *ptr) -+{ -+ int ret = 1, fw_error = 0; -+ uint32_t i, guest_addr_entry_num; -+ gchar *hdr = NULL, *trans = NULL; -+ struct guest_addr_entry *guest_addr_data; -+ struct kvm_csv_receive_encrypt_data update = {}; -+ void *hva = NULL; -+ MemoryRegion *mr = NULL; -+ -+ /* get packet header */ -+ update.hdr_len = qemu_get_be32(f); -+ -+ hdr = g_new(gchar, update.hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); -+ update.hdr_uaddr = (uintptr_t)hdr; -+ -+ /* get guest addr data */ -+ update.guest_addr_len = qemu_get_be32(f); -+ -+ guest_addr_data = (struct guest_addr_entry *)g_new(gchar, update.guest_addr_len); -+ qemu_get_buffer(f, (uint8_t *)guest_addr_data, update.guest_addr_len); -+ update.guest_addr_data = (uintptr_t)guest_addr_data; -+ -+ /* get transport buffer */ -+ update.trans_len = qemu_get_be32(f); -+ -+ trans = g_new(gchar, update.trans_len); -+ update.trans_uaddr = (uintptr_t)trans; -+ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+ /* update share memory. */ -+ guest_addr_entry_num = update.guest_addr_len / sizeof(struct guest_addr_entry); -+ for (i = 0; i < guest_addr_entry_num; i++) { -+ if (guest_addr_data[i].share) { -+ hva = gpa2hva(&mr, -+ ((uint64_t)guest_addr_data[i].gfn << TARGET_PAGE_BITS), -+ TARGET_PAGE_SIZE, -+ NULL); -+ if (hva) -+ memcpy(hva, trans + i * TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); -+ } -+ } -+ -+ trace_kvm_csv_receive_encrypt_data(trans, update.trans_len, hdr, update.hdr_len); -+ -+ ret = csv_ioctl(KVM_CSV_RECEIVE_ENCRYPT_DATA, &update, &fw_error); -+ if (ret) { -+ error_report("Error RECEIVE_ENCRYPT_DATA ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+err: -+ g_free(trans); -+ g_free(guest_addr_data); -+ g_free(hdr); -+ return ret; -+} -+ -+int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr) -+{ -+ /* -+ * If this is first buffer and SEV is not in recieiving state then -+ * use RECEIVE_START command to create a encryption context. -+ */ -+ if (!csv_check_state(SEV_STATE_RECEIVE_UPDATE) && -+ csv_receive_start(f)) { -+ return 1; -+ } -+ -+ return csv_receive_encrypt_data(f, ptr); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 273d69d12c..c8639cfa9a 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -89,6 +89,7 @@ struct CsvGuestState { - size_t guest_addr_len; - - int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); -+ int (*sev_receive_start)(QEMUFile *f); - }; - - typedef struct CsvGuestState CsvGuestState; -@@ -102,6 +103,7 @@ int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - - int csv_shared_region_dma_map(uint64_t start, uint64_t end); - void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); -+int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); - int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); - -diff --git a/target/i386/sev.c b/target/i386/sev.c -index 31af1ecdf3..40e52985ac 100644 ---- a/target/i386/sev.c -+++ b/target/i386/sev.c -@@ -2562,10 +2562,18 @@ static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) - return sev_send_start(s, f, bytes_sent); - } - -+static int _sev_receive_start(QEMUFile *f) -+{ -+ SevGuestState *s = sev_guest; -+ -+ return sev_receive_start(s, f); -+} -+ - struct sev_ops sev_ops = { - .sev_ioctl = sev_ioctl, - .fw_error_to_str = fw_error_to_str, - .sev_send_start = _sev_send_start, -+ .sev_receive_start = _sev_receive_start, - }; - - static void -diff --git a/target/i386/sev.h b/target/i386/sev.h -index 6d1a918413..9e5c6506c8 100644 ---- a/target/i386/sev.h -+++ b/target/i386/sev.h -@@ -90,6 +90,7 @@ struct sev_ops { - int (*sev_ioctl)(int fd, int cmd, void *data, int *error); - const char *(*fw_error_to_str)(int code); - int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); -+ int (*sev_receive_start)(QEMUFile *f); - }; - - #endif -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 8db3e36385..1854356fc5 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -23,3 +23,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 - kvm_csv_send_encrypt_data(void *dst, int len) "trans %p len %d" -+kvm_csv_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" --- -2.17.1 - diff --git a/1071-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch b/1071-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch deleted file mode 100644 index 629f713199a34df6b0c46545824e20bfc0404fb7..0000000000000000000000000000000000000000 --- a/1071-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch +++ /dev/null @@ -1,137 +0,0 @@ -From cd3f19da06a1691a790221a06a2899427e2140cd Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 09:52:31 +0800 -Subject: [PATCH 1071/1072] anolis: csv/i386: add support to migrate the - outgoing context - -CSV needs to migrate guest cpu's context pages. Prior to migration -of the context, it should query transfer buffer length and header -data length by SEND ENCRYPT CONTEXT command. New migration flag -RAM_SAVE_ENCRYPTED_CSV_CONTEXT is defined for CSV. - -Change-Id: I1989e76bd5c91c78074fb31eff075deacfa16078 ---- - target/i386/csv.c | 79 ++++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 1 + - target/i386/trace-events | 1 + - 3 files changed, 81 insertions(+) - -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 00ff7d20a5..271c48867e 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -44,6 +44,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = { - .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, - .queue_incoming_page = NULL, - .load_queued_incoming_pages = NULL, -+ .save_outgoing_cpu_state = csv3_save_outgoing_context, - }; - - #define CSV_OUTGOING_PAGE_NUM (CSV3_OUTGOING_PAGE_WINDOW_SIZE/TARGET_PAGE_SIZE) -@@ -569,3 +570,81 @@ int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr) - - return csv_receive_encrypt_data(f, ptr); - } -+ -+static int -+csv_send_get_context_len(int *fw_err, int *context_len, int *hdr_len) -+{ -+ int ret = 0; -+ struct kvm_csv_send_encrypt_context update = {}; -+ -+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_CONTEXT, &update, fw_err); -+ if (*fw_err != SEV_RET_INVALID_LEN) { -+ error_report("%s: failed to get context length ret=%d fw_error=%d '%s'", -+ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); -+ ret = -1; -+ goto err; -+ } -+ -+ if (update.trans_len <= INT_MAX && update.hdr_len <= INT_MAX) { -+ *context_len = update.trans_len; -+ *hdr_len = update.hdr_len; -+ } -+ ret = 0; -+err: -+ return ret; -+} -+ -+static int -+csv_send_encrypt_context(CsvGuestState *s, QEMUFile *f) -+{ -+ int ret, fw_error = 0; -+ int context_len = 0; -+ int hdr_len = 0; -+ guchar *trans; -+ guchar *hdr; -+ struct kvm_csv_send_encrypt_context update = { }; -+ -+ ret = csv_send_get_context_len(&fw_error, &context_len, &hdr_len); -+ if (context_len < 1 || hdr_len < 1) { -+ error_report("%s: fail to get context length fw_error=%d '%s'", -+ __func__, fw_error, fw_error_to_str(fw_error)); -+ return 1; -+ } -+ -+ /* allocate transport buffer */ -+ trans = g_new(guchar, context_len); -+ hdr = g_new(guchar, hdr_len); -+ -+ update.hdr_uaddr = (uintptr_t)hdr; -+ update.hdr_len = hdr_len; -+ update.trans_uaddr = (uintptr_t)trans; -+ update.trans_len = context_len; -+ -+ trace_kvm_csv_send_encrypt_context(trans, update.trans_len); -+ -+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_CONTEXT, &update, &fw_error); -+ if (ret) { -+ error_report("%s: SEND_ENCRYPT_CONTEXT ret=%d fw_error=%d '%s'", -+ __func__, ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+ qemu_put_be32(f, update.hdr_len); -+ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); -+ -+ qemu_put_be32(f, update.trans_len); -+ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+err: -+ g_free(trans); -+ g_free(hdr); -+ return ret; -+} -+ -+int csv3_save_outgoing_context(QEMUFile *f) -+{ -+ CsvGuestState *s = &csv_guest; -+ -+ /* send csv context. */ -+ return csv_send_encrypt_context(s, f); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index c8639cfa9a..9def1611d8 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -103,6 +103,7 @@ int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - - int csv_shared_region_dma_map(uint64_t start, uint64_t end); - void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); -+int csv3_save_outgoing_context(QEMUFile *f); - int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); - int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 1854356fc5..08a782ce15 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -23,4 +23,5 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int - # csv.c - kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 - kvm_csv_send_encrypt_data(void *dst, int len) "trans %p len %d" -+kvm_csv_send_encrypt_context(void *dst, int len) "trans %p len %d" - kvm_csv_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" --- -2.17.1 - diff --git a/1072-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch b/1072-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch deleted file mode 100644 index 1c6084baa09828fe7a718a4f982b534f29e76f02..0000000000000000000000000000000000000000 --- a/1072-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 40741ce0d0bb68d789d84407c77d2282ecd4f67f Mon Sep 17 00:00:00 2001 -From: jiangxin -Date: Fri, 17 Jun 2022 10:00:46 +0800 -Subject: [PATCH 1072/1072] anolis: csv/i386: add support to migrate the - incoming context - -The csv_load_incoming_context() provides the method to read incoming -guest's context from socket. It loads them into guest private memory. -This is the last step during migration and RECEIVE FINISH command is -performed by then to complete the whole migration. - -Change-Id: I7290e0e9527bb819eee5813038110d981908a880 ---- - target/i386/csv.c | 45 ++++++++++++++++++++++++++++++++++++++++ - target/i386/csv.h | 1 + - target/i386/trace-events | 1 + - 3 files changed, 47 insertions(+) - -diff --git a/target/i386/csv.c b/target/i386/csv.c -index 271c48867e..b0ca16980d 100644 ---- a/target/i386/csv.c -+++ b/target/i386/csv.c -@@ -45,6 +45,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = { - .queue_incoming_page = NULL, - .load_queued_incoming_pages = NULL, - .save_outgoing_cpu_state = csv3_save_outgoing_context, -+ .load_incoming_cpu_state = csv3_load_incoming_context, - }; - - #define CSV_OUTGOING_PAGE_NUM (CSV3_OUTGOING_PAGE_WINDOW_SIZE/TARGET_PAGE_SIZE) -@@ -641,6 +642,42 @@ err: - return ret; - } - -+static int -+csv_receive_encrypt_context(CsvGuestState *s, QEMUFile *f) -+{ -+ int ret = 1, fw_error = 0; -+ gchar *hdr = NULL, *trans = NULL; -+ struct kvm_csv_receive_encrypt_context update = {}; -+ -+ /* get packet header */ -+ update.hdr_len = qemu_get_be32(f); -+ -+ hdr = g_new(gchar, update.hdr_len); -+ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); -+ update.hdr_uaddr = (uintptr_t)hdr; -+ -+ /* get transport buffer */ -+ update.trans_len = qemu_get_be32(f); -+ -+ trans = g_new(gchar, update.trans_len); -+ update.trans_uaddr = (uintptr_t)trans; -+ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); -+ -+ trace_kvm_csv_receive_encrypt_context(trans, update.trans_len, hdr, update.hdr_len); -+ -+ ret = csv_ioctl(KVM_CSV_RECEIVE_ENCRYPT_CONTEXT, &update, &fw_error); -+ if (ret) { -+ error_report("Error RECEIVE_ENCRYPT_CONTEXT ret=%d fw_error=%d '%s'", -+ ret, fw_error, fw_error_to_str(fw_error)); -+ goto err; -+ } -+ -+err: -+ g_free(trans); -+ g_free(hdr); -+ return ret; -+} -+ - int csv3_save_outgoing_context(QEMUFile *f) - { - CsvGuestState *s = &csv_guest; -@@ -648,3 +685,11 @@ int csv3_save_outgoing_context(QEMUFile *f) - /* send csv context. */ - return csv_send_encrypt_context(s, f); - } -+ -+int csv3_load_incoming_context(QEMUFile *f) -+{ -+ CsvGuestState *s = &csv_guest; -+ -+ /* receive csv context. */ -+ return csv_receive_encrypt_context(s, f); -+} -diff --git a/target/i386/csv.h b/target/i386/csv.h -index 9def1611d8..2e0506313d 100644 ---- a/target/i386/csv.h -+++ b/target/i386/csv.h -@@ -104,6 +104,7 @@ int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); - int csv_shared_region_dma_map(uint64_t start, uint64_t end); - void csv_shared_region_dma_unmap(uint64_t start, uint64_t end); - int csv3_save_outgoing_context(QEMUFile *f); -+int csv3_load_incoming_context(QEMUFile *f); - int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); - int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); - int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); -diff --git a/target/i386/trace-events b/target/i386/trace-events -index 08a782ce15..47ab390de6 100644 ---- a/target/i386/trace-events -+++ b/target/i386/trace-events -@@ -25,3 +25,4 @@ kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PR - kvm_csv_send_encrypt_data(void *dst, int len) "trans %p len %d" - kvm_csv_send_encrypt_context(void *dst, int len) "trans %p len %d" - kvm_csv_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" -+kvm_csv_receive_encrypt_context(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" --- -2.17.1 - diff --git a/1073-anolis-target-i386-sev-Add-support-for-reuse-ASID-fo.patch b/1073-anolis-target-i386-sev-Add-support-for-reuse-ASID-fo.patch deleted file mode 100644 index 7e6f98e8cc3ffb2195455298523337c0337db05f..0000000000000000000000000000000000000000 --- a/1073-anolis-target-i386-sev-Add-support-for-reuse-ASID-fo.patch +++ /dev/null @@ -1,192 +0,0 @@ -From 9cd331388ce95e3d7365fceab30016756eae2483 Mon Sep 17 00:00:00 2001 -From: appleLin -Date: Wed, 3 Aug 2022 21:02:41 +0800 -Subject: [PATCH] anolis: target/i386/sev: Add support for reuse ASID for - different CSV guests - -In you want to reuse one ASID for many CSV guests, you should provide a -label (i.e. userid) and the length of the label when launch CSV guest. -The CSV guests which were provided the same userid will share the same -ASID. - -Signed-off-by: hanliyang ---- - linux-headers/linux/kvm.h | 5 +++++ - qapi/qom.json | 5 ++++- - qemu-options.hx | 5 ++++- - target/i386/csv.c | 2 -- - target/i386/csv.h | 3 +++ - target/i386/sev.c | 47 ++++++++++++++++++++++++++++++++++++++- - 6 files changed, 62 insertions(+), 5 deletions(-) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 5fe2f8d04..3875127a3 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -2011,6 +2011,11 @@ struct kvm_csv_receive_encrypt_context { - __u32 trans_len; - }; - -+struct kvm_csv_init { -+ __u64 userid_addr; -+ __u32 len; -+}; -+ - #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) - #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) -diff --git a/qapi/qom.json b/qapi/qom.json -index eeb5395ff..387c0a142 100644 ---- a/qapi/qom.json -+++ b/qapi/qom.json -@@ -773,6 +773,8 @@ - # designated guest firmware page for measured boot - # with -kernel (default: false) (since 6.2) - # -+# @user-id: the user id of the guest owner, only support on Hygon CPUs -+# - # Since: 2.12 - ## - { 'struct': 'SevGuestProperties', -@@ -783,7 +785,8 @@ - '*handle': 'uint32', - '*cbitpos': 'uint32', - 'reduced-phys-bits': 'uint32', -- '*kernel-hashes': 'bool' } } -+ '*kernel-hashes': 'bool', -+ '*user-id': 'str' } } - - ## - # @ObjectType: -diff --git a/qemu-options.hx b/qemu-options.hx -index 8997969d5..115e1835f 100644 ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -5189,7 +5189,7 @@ SRST - -object secret,id=sec0,keyid=secmaster0,format=base64,\\ - data=$SECRET,iv=$(dh_cert_file = g_strdup(value); - } - -+static char * -+sev_guest_get_user_id(Object *obj, Error **errp) -+{ -+ SevGuestState *s = SEV_GUEST(obj); -+ -+ return g_strdup(s->user_id); -+} -+ -+static void -+sev_guest_set_user_id(Object *obj, const char *value, Error **errp) -+{ -+ SevGuestState *s = SEV_GUEST(obj); -+ -+ s->user_id = g_strdup(value); -+} -+ - static char * - sev_guest_get_sev_device(Object *obj, Error **errp) - { -@@ -436,6 +453,11 @@ sev_guest_class_init(ObjectClass *oc, void *data) - sev_guest_set_kernel_hashes); - object_class_property_set_description(oc, "kernel-hashes", - "add kernel hashes to guest firmware for measured Linux boot"); -+ object_class_property_add_str(oc, "user-id", -+ sev_guest_get_user_id, -+ sev_guest_set_user_id); -+ object_class_property_set_description(oc, "user-id", -+ "user id of the guest owner"); - } - - static void -@@ -1137,7 +1159,30 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) - } - - trace_kvm_sev_init(); -- ret = sev_ioctl(sev->sev_fd, cmd, NULL, &fw_error); -+ -+ /* Only support reuse asid for CSV/CSV2 guest */ -+ if (is_hygon_cpu() && -+ (sev_guest->policy & GUEST_POLICY_REUSE_ASID) && -+ !(sev_guest->policy & GUEST_POLICY_CSV_BIT)) { -+ char *user_id = NULL; -+ struct kvm_csv_init *init_cmd_buf = NULL; -+ -+ user_id = object_property_get_str(OBJECT(sev), "user-id", NULL); -+ if (user_id && strlen(user_id)) { -+ init_cmd_buf = g_new0(struct kvm_csv_init, 1); -+ init_cmd_buf->len = strlen(user_id); -+ init_cmd_buf->userid_addr = (__u64)user_id; -+ } -+ ret = sev_ioctl(sev->sev_fd, cmd, init_cmd_buf, &fw_error); -+ -+ if (user_id) { -+ g_free(user_id); -+ g_free(init_cmd_buf); -+ } -+ } else { -+ ret = sev_ioctl(sev->sev_fd, cmd, NULL, &fw_error); -+ } -+ - if (ret) { - error_setg(errp, "%s: failed to initialize ret=%d fw_error=%d '%s'", - __func__, ret, fw_error, fw_error_to_str(fw_error)); --- -2.31.1 - diff --git a/1074-newfeature-support-vpsp.patch b/1074-newfeature-support-vpsp.patch deleted file mode 100644 index 2efaa127db0132ad828866dd11f379036ad7426e..0000000000000000000000000000000000000000 --- a/1074-newfeature-support-vpsp.patch +++ /dev/null @@ -1,190 +0,0 @@ -From fd593b7516631ed0dce757cdce4d10b28971c553 Mon Sep 17 00:00:00 2001 -From: xiongmengbiao -Date: Wed, 6 Mar 2024 17:43:57 +0800 -Subject: [PATCH] [newfeature]: support vpsp - -simulate a psp misc device for support tkm's key isolation - -Signed-off-by: xiongmengbiao ---- - hw/misc/Kconfig | 4 ++ - hw/misc/meson.build | 1 + - hw/misc/psp.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 146 insertions(+) - create mode 100644 hw/misc/psp.c - -diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig -index 507058d8b..d1d05442d 100644 ---- a/hw/misc/Kconfig -+++ b/hw/misc/Kconfig -@@ -171,4 +171,8 @@ config SIFIVE_U_PRCI - config VIRT_CTRL - bool - -+config PSP_DEV -+ bool -+ default y -+ - source macio/Kconfig -diff --git a/hw/misc/meson.build b/hw/misc/meson.build -index 3f41a3a5b..39e583631 100644 ---- a/hw/misc/meson.build -+++ b/hw/misc/meson.build -@@ -10,6 +10,7 @@ softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) - softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c')) - softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c')) - softmmu_ss.add(when: 'CONFIG_PVPANIC_COMMON', if_true: files('pvpanic.c')) -+softmmu_ss.add(when: 'CONFIG_PSP_DEV', if_true: files('psp.c')) - - # ARM devices - softmmu_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c')) -diff --git a/hw/misc/psp.c b/hw/misc/psp.c -new file mode 100644 -index 000000000..1cfbab859 ---- /dev/null -+++ b/hw/misc/psp.c -@@ -0,0 +1,141 @@ -+/* -+ * hygon psp device emulation -+ * -+ * Copyright 2024 HYGON Corp. -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or (at -+ * your option) any later version. See the COPYING file in the top-level -+ * directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu/compiler.h" -+#include "qemu/error-report.h" -+#include "qapi/error.h" -+#include "migration/vmstate.h" -+#include "hw/qdev-properties.h" -+#include "sysemu/runstate.h" -+#include -+ -+#define TYPE_PSP_DEV "psp" -+OBJECT_DECLARE_SIMPLE_TYPE(PSPDevState, PSP_DEV) -+ -+struct PSPDevState { -+ /* Private */ -+ DeviceState pdev; -+ -+ /* Public */ -+ Notifier shutdown_notifier; -+ int dev_fd; -+ uint8_t enabled; -+ -+ /** -+ * vid is used to identify a virtual machine in qemu. -+ * When a virtual machine accesses a tkm key, -+ * the TKM module uses different key spaces based on different vids. -+ */ -+ uint32_t vid; -+}; -+ -+#define PSP_DEV_PATH "/dev/hygon_psp_config" -+#define HYGON_PSP_IOC_TYPE 'H' -+#define PSP_IOC_MUTEX_ENABLE _IOWR(HYGON_PSP_IOC_TYPE, 1, NULL) -+#define PSP_IOC_MUTEX_DISABLE _IOWR(HYGON_PSP_IOC_TYPE, 2, NULL) -+#define PSP_IOC_VPSP_OPT _IOWR(HYGON_PSP_IOC_TYPE, 3, NULL) -+ -+enum VPSP_DEV_CTRL_OPCODE { -+ VPSP_OP_VID_ADD, -+ VPSP_OP_VID_DEL, -+}; -+ -+struct psp_dev_ctrl { -+ unsigned char op; -+ union { -+ unsigned int vid; -+ unsigned char reserved[128]; -+ } data; -+}; -+ -+static void psp_dev_destroy(PSPDevState *state) -+{ -+ struct psp_dev_ctrl ctrl = { 0 }; -+ if (state && state->dev_fd) { -+ if (state->enabled) { -+ ctrl.op = VPSP_OP_VID_DEL; -+ if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { -+ error_report("VPSP_OP_VID_DEL: %d", -errno); -+ } else { -+ state->enabled = false; -+ } -+ } -+ qemu_close(state->dev_fd); -+ state->dev_fd = 0; -+ } -+} -+ -+/** -+ * Guest OS performs shut down operations through 'shutdown' and 'powerdown' event. -+ * The 'powerdown' event will also trigger 'shutdown' in the end, -+ * so only attention to the 'shutdown' event. -+ * -+ * When Guest OS trigger 'reboot' or 'reset' event, to do nothing. -+*/ -+static void psp_dev_shutdown_notify(Notifier *notifier, void *data) -+{ -+ PSPDevState *state = container_of(notifier, PSPDevState, shutdown_notifier); -+ psp_dev_destroy(state); -+} -+ -+static void psp_dev_realize(DeviceState *dev, Error **errp) -+{ -+ struct psp_dev_ctrl ctrl = { 0 }; -+ PSPDevState *state = PSP_DEV(dev); -+ -+ state->dev_fd = qemu_open_old(PSP_DEV_PATH, O_RDWR); -+ if (state->dev_fd < 0) { -+ error_setg(errp, "fail to open %s, errno %d.", PSP_DEV_PATH, errno); -+ goto end; -+ } -+ -+ ctrl.op = VPSP_OP_VID_ADD; -+ ctrl.data.vid = state->vid; -+ if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { -+ error_setg(errp, "psp_dev_realize VPSP_OP_VID_ADD vid %d, return %d", ctrl.data.vid, -errno); -+ goto end; -+ } -+ -+ state->enabled = true; -+ state->shutdown_notifier.notify = psp_dev_shutdown_notify; -+ qemu_register_shutdown_notifier(&state->shutdown_notifier); -+end: -+ return; -+} -+ -+static struct Property psp_dev_properties[] = { -+ DEFINE_PROP_UINT32("vid", PSPDevState, vid, 0), -+ DEFINE_PROP_END_OF_LIST(), -+}; -+ -+static void psp_dev_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ -+ dc->desc = "PSP Device"; -+ dc->realize = psp_dev_realize; -+ set_bit(DEVICE_CATEGORY_MISC, dc->categories); -+ device_class_set_props(dc, psp_dev_properties); -+} -+ -+static const TypeInfo psp_dev_info = { -+ .name = TYPE_PSP_DEV, -+ .parent = TYPE_DEVICE, -+ .instance_size = sizeof(PSPDevState), -+ .class_init = psp_dev_class_init, -+}; -+ -+static void psp_dev_register_types(void) -+{ -+ type_register_static(&psp_dev_info); -+} -+ -+type_init(psp_dev_register_types) --- -2.36.6 - diff --git a/1075-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch b/1075-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch deleted file mode 100644 index abbf1da4e64e24469ad0431514db479abda4c002..0000000000000000000000000000000000000000 --- a/1075-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 858884a2a18df9bcb07176fc14a6ea5ee872f8dc Mon Sep 17 00:00:00 2001 -From: Yanjing Zhou -Date: Tue, 11 Jun 2024 14:28:12 +0800 -Subject: [PATCH 1/2] target/i386: Add Hygon Dhyana-v3 CPU model - -Add the following feature bits for Dhyana CPU model: -perfctr-core, clzero, xsaveerptr, aes, pclmulqdq, sha-ni - -Disable xsaves feature bit for Erratum 1386 - -Signed-off-by: Yanjing Zhou ---- - target/i386/cpu.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index aa9e63680..43a57be0b 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -4057,6 +4057,20 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ } - }, - }, -+ { .version = 3, -+ .props = (PropValue[]) { -+ { "xsaves", "off" }, -+ { "perfctr-core", "on" }, -+ { "clzero", "on" }, -+ { "xsaveerptr", "on" }, -+ { "aes", "on" }, -+ { "pclmulqdq", "on" }, -+ { "sha-ni", "on" }, -+ { "model-id", -+ "Hygon Dhyana-v3 processor" }, -+ { /* end of list */ } -+ }, -+ }, - { /* end of list */ } - } - }, --- -2.39.3 - diff --git a/1076-target-i386-Add-new-Hygon-Dharma-CPU-model.patch b/1076-target-i386-Add-new-Hygon-Dharma-CPU-model.patch deleted file mode 100644 index d12c1a56035d2841e087416cf9838fe6cc8781e0..0000000000000000000000000000000000000000 --- a/1076-target-i386-Add-new-Hygon-Dharma-CPU-model.patch +++ /dev/null @@ -1,133 +0,0 @@ -From b3dfdd0e3cf7795fb66b094ffd821e193b9a773a Mon Sep 17 00:00:00 2001 -From: Yanjing Zhou -Date: Tue, 11 Jun 2024 14:29:34 +0800 -Subject: [PATCH 2/2] target/i386: Add new Hygon 'Dharma' CPU model - -Add the following feature bits compare to Dhyana CPU model: -stibp, ibrs, umip, ssbd - -Signed-off-by: Yanjing Zhou ---- - target/i386/cpu.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 99 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 43a57be0b..07b65da92 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1731,6 +1731,56 @@ static const CPUCaches epyc_milan_cache_info = { - }, - }; - -+static const CPUCaches dharma_cache_info = { -+ .l1d_cache = &(CPUCacheInfo) { -+ .type = DATA_CACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 64, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .l1i_cache = &(CPUCacheInfo) { -+ .type = INSTRUCTION_CACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 64, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .l2_cache = &(CPUCacheInfo) { -+ .type = UNIFIED_CACHE, -+ .level = 2, -+ .size = 512 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 1024, -+ .lines_per_tag = 1, -+ }, -+ .l3_cache = &(CPUCacheInfo) { -+ .type = UNIFIED_CACHE, -+ .level = 3, -+ .size = 16 * MiB, -+ .line_size = 64, -+ .associativity = 16, -+ .partitions = 1, -+ .sets = 16384, -+ .lines_per_tag = 1, -+ .self_init = true, -+ .inclusive = true, -+ .complex_indexing = true, -+ }, -+}; -+ - /* The following VMX features are not supported by KVM and are left out in the - * CPU definitions: - * -@@ -4191,6 +4241,55 @@ static const X86CPUDefinition builtin_x86_defs[] = { - .model_id = "AMD EPYC-Milan Processor", - .cache_info = &epyc_milan_cache_info, - }, -+ { -+ .name = "Dharma", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_HYGON, -+ .family = 24, -+ .model = 4, -+ .stepping = 0, -+ .features[FEAT_1_EDX] = -+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | -+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | -+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | -+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | -+ CPUID_VME | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | -+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | -+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | -+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | -+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | -+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | -+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | -+ CPUID_EXT3_TOPOEXT | CPUID_EXT3_PERFCORE, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_CLZERO | CPUID_8000_0008_EBX_XSAVEERPTR | -+ CPUID_8000_0008_EBX_IBPB | CPUID_8000_0008_EBX_IBRS | -+ CPUID_8000_0008_EBX_STIBP | CPUID_8000_0008_EBX_AMD_SSBD, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | -+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | -+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | -+ CPUID_7_0_EBX_SHA_NI, -+ .features[FEAT_7_0_ECX] = CPUID_7_0_ECX_UMIP, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_SVM] = -+ CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE, -+ .xlevel = 0x8000001E, -+ .model_id = "Hygon Dharma Processor", -+ .cache_info = &dharma_cache_info, -+ }, - }; - - /* --- -2.39.3 - diff --git a/1077-target-i386-add-FSRM-to-TCG.patch b/1077-target-i386-add-FSRM-to-TCG.patch deleted file mode 100644 index bf309ac4b6232b4122b08ff366a48d73ed815e4f..0000000000000000000000000000000000000000 --- a/1077-target-i386-add-FSRM-to-TCG.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: Paolo Bonzini -Date: Mon, 27 Feb 2023 10:57:09 +0100 -Subject: [PATCH] target/i386: add FSRM to TCG - -commit c0728d4e3d23356691e4182eac54c67e1ca26618 upstream. - -Fast short REP MOVS can be added to TCG, since a trivial translation -of string operation is a good option for short lengths. - -Intel-SIG: commit c0728d4e3d23 target/i386: add FSRM to TCG. -Add SPR/GNR/SRA new ISAs backporting - -Reviewed-by: Xiaoyao Li -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 7d779c6a8..e54a60d3c 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -661,7 +661,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | \ - /* CPUID_7_0_ECX_OSPKE is dynamic */ \ - CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) --#define TCG_7_0_EDX_FEATURES 0 -+#define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM - #define TCG_7_1_EAX_FEATURES 0 - #define TCG_APM_FEATURES 0 - #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT --- -2.25.1 diff --git a/1078-target-i386-add-FZRM-FSRS-FSRC.patch b/1078-target-i386-add-FZRM-FSRS-FSRC.patch deleted file mode 100644 index 5b872b34e11bcfab9f275dbdd516eb4a6a0136a9..0000000000000000000000000000000000000000 --- a/1078-target-i386-add-FZRM-FSRS-FSRC.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Paolo Bonzini -Date: Mon, 27 Feb 2023 10:55:46 +0100 -Subject: [PATCH] target/i386: add FZRM, FSRS, FSRC - -commit 58794f644e43ef8e60ed05395c58099311c1fcd1 upstream. - -These are three more markers for string operation optimizations. -They can all be added to TCG, whose string operations are more or -less as fast as they can be for short lengths. - -Intel-SIG: commit 58794f644e43 target/i386: add FZRM, FSRS, FSRC. -Add SPR/GNR/SRA new ISAs backporting - -Reviewed-by: Xiaoyao Li -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 7 ++++--- - target/i386/cpu.h | 7 +++++++ - 2 files changed, 11 insertions(+), 3 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index e54a60d3c..04cb9292b 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -662,7 +662,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - /* CPUID_7_0_ECX_OSPKE is dynamic */ \ - CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) - #define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM --#define TCG_7_1_EAX_FEATURES 0 -+#define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ -+ CPUID_7_1_EAX_FSRC) - #define TCG_APM_FEATURES 0 - #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT - #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) -@@ -872,8 +873,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .feat_names = { - NULL, NULL, NULL, NULL, - "avx-vnni", "avx512-bf16", NULL, NULL, -- NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, NULL, "fzrm", "fsrs", -+ "fsrc", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 1415a33fb..98f885ace 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -879,6 +879,13 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) - /* AVX512 BFloat16 Instruction */ - #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) -+/* Fast Zero REP MOVS */ -+#define CPUID_7_1_EAX_FZRM (1U << 10) -+/* Fast Short REP STOS */ -+#define CPUID_7_1_EAX_FSRS (1U << 11) -+/* Fast Short REP CMPS/SCAS */ -+#define CPUID_7_1_EAX_FSRC (1U << 12) -+ - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) - --- -2.25.1 diff --git a/1079-i386-Add-new-CPU-model-SapphireRapids.patch b/1079-i386-Add-new-CPU-model-SapphireRapids.patch deleted file mode 100644 index 6176a1af05b44affc2dd1de0fbea4610405d73bb..0000000000000000000000000000000000000000 --- a/1079-i386-Add-new-CPU-model-SapphireRapids.patch +++ /dev/null @@ -1,226 +0,0 @@ -From: "Wang, Lei" -Date: Thu, 11 Aug 2022 22:57:51 -0700 -Subject: [PATCH] i386: Add new CPU model SapphireRapids - -commit 7eb061b06e97af9a8da7f31b839d78997ae737fc upstream. - -The new CPU model mostly inherits features from Icelake-Server, while -adding new features: - - AMX (Advance Matrix eXtensions) - - Bus Lock Debug Exception -and new instructions: - - AVX VNNI (Vector Neural Network Instruction): - - VPDPBUS: Multiply and Add Unsigned and Signed Bytes - - VPDPBUSDS: Multiply and Add Unsigned and Signed Bytes with Saturation - - VPDPWSSD: Multiply and Add Signed Word Integers - - VPDPWSSDS: Multiply and Add Signed Integers with Saturation - - FP16: Replicates existing AVX512 computational SP (FP32) instructions - using FP16 instead of FP32 for ~2X performance gain - - SERIALIZE: Provide software with a simple way to force the processor to - complete all modifications, faster, allowed in all privilege levels and - not causing an unconditional VM exit - - TSX Suspend Load Address Tracking: Allows programmers to choose which - memory accesses do not need to be tracked in the TSX read set - - AVX512_BF16: Vector Neural Network Instructions supporting BFLOAT16 - inputs and conversion instructions from IEEE single precision - - fast zero-length MOVSB (KVM doesn't support yet) - - fast short STOSB (KVM doesn't support yet) - - fast short CMPSB, SCASB (KVM doesn't support yet) - -Features that may be added in future versions: - - CET (virtualization support hasn't been merged) - -Intel-SIG: commit 7eb061b06e97 i386: Add new CPU model SapphireRapids. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Wang, Lei -Reviewed-by: Robert Hoo -Message-Id: <20220812055751.14553-1-lei4.wang@intel.com> -Reviewed-by: Xiaoyao Li -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 133 +++++++++++++++++++++++++++++++++++++++++++++- - target/i386/cpu.h | 4 ++ - 2 files changed, 135 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 04cb9292b..30d19b794 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3546,6 +3546,135 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ } - } - }, -+ { -+ .name = "SapphireRapids", -+ .level = 0x20, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 143, -+ .stepping = 4, -+ /* -+ * please keep the ascending order so that we can have a clear view of -+ * bit position of each feature. -+ */ -+ .features[FEAT_1_EDX] = -+ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | -+ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | -+ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | -+ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | -+ CPUID_SSE | CPUID_SSE2, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | -+ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | -+ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | -+ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | -+ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_WBNOINVD, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_HLE | -+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | -+ CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RTM | -+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | -+ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | -+ CPUID_7_0_EBX_AVX512IFMA | CPUID_7_0_EBX_CLFLUSHOPT | -+ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | -+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, -+ .features[FEAT_7_0_ECX] = -+ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | -+ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | -+ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | -+ CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | -+ CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57 | -+ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | -+ CPUID_7_0_EDX_TSX_LDTRK | CPUID_7_0_EDX_AMX_BF16 | -+ CPUID_7_0_EDX_AVX512_FP16 | CPUID_7_0_EDX_AMX_TILE | -+ CPUID_7_0_EDX_AMX_INT8 | CPUID_7_0_EDX_SPEC_CTRL | -+ CPUID_7_0_EDX_ARCH_CAPABILITIES | CPUID_7_0_EDX_SPEC_CTRL_SSBD, -+ .features[FEAT_ARCH_CAPABILITIES] = -+ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | -+ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | -+ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES | CPUID_D_1_EAX_XFD, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_7_1_EAX] = -+ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16 | -+ CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_FSRC, -+ .features[FEAT_VMX_BASIC] = -+ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = -+ MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_PAGE_WALK_LENGTH_5 | -+ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | -+ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | -+ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = -+ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | -+ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | -+ VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = -+ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | -+ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | -+ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | -+ VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | -+ VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | -+ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | -+ VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | -+ VMX_SECONDARY_EXEC_XSAVES, -+ .features[FEAT_VMX_VMFUNC] = -+ MSR_VMX_VMFUNC_EPT_SWITCHING, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon Processor (SapphireRapids)", -+ .versions = (X86CPUVersionDefinition[]) { -+ { .version = 1 }, -+ { /* end of list */ }, -+ }, -+ }, - { - .name = "Denverton", - .level = 21, -@@ -5616,7 +5745,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - break; - } - case 0x1D: { -- /* AMX TILE */ -+ /* AMX TILE, for now hardcoded for Sapphire Rapids*/ - *eax = 0; - *ebx = 0; - *ecx = 0; -@@ -5637,7 +5766,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - break; - } - case 0x1E: { -- /* AMX TMUL */ -+ /* AMX TMUL, for now hardcoded for Sapphire Rapids */ - *eax = 0; - *ebx = 0; - *ecx = 0; -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 98f885ace..d156ccd17 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -858,10 +858,14 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_0_EDX_SERIALIZE (1U << 14) - /* TSX Suspend Load Address Tracking instruction */ - #define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) -+/* AMX_BF16 instruction */ -+#define CPUID_7_0_EDX_AMX_BF16 (1U << 22) - /* AVX512_FP16 instruction */ - #define CPUID_7_0_EDX_AVX512_FP16 (1U << 23) - /* AMX tile (two-dimensional register) */ - #define CPUID_7_0_EDX_AMX_TILE (1U << 24) -+/* AMX_INT8 instruction */ -+#define CPUID_7_0_EDX_AMX_INT8 (1U << 25) - /* Speculation Control */ - #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) - /* Single Thread Indirect Branch Predictors */ --- -2.25.1 diff --git a/1080-target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch b/1080-target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch deleted file mode 100644 index de83c1178b229530c10b57871b784d81e131c4fe..0000000000000000000000000000000000000000 --- a/1080-target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch +++ /dev/null @@ -1,59 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:08 +0800 -Subject: [PATCH] target/i386: Add support for CMPCCXADD in CPUID enumeration - -commit a9ce107fd0f2017af84255a9cf6542fa3eb3e214 upstream. - -CMPccXADD is a new set of instructions in the latest Intel platform -Sierra Forest. This new instruction set includes a semaphore operation -that can compare and add the operands if condition is met, which can -improve database performance. - -The bit definition: -CPUID.(EAX=7,ECX=1):EAX[bit 7] - -Add CPUID definition for CMPCCXADD. - -Intel-SIG: commit a9ce107fd0f2 target/i386: Add support for CMPCCXADD in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-2-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 30d19b794..6a8e07904 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -872,7 +872,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { - NULL, NULL, NULL, NULL, -- "avx-vnni", "avx512-bf16", NULL, NULL, -+ "avx-vnni", "avx512-bf16", NULL, "cmpccxadd", - NULL, NULL, "fzrm", "fsrs", - "fsrc", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index d156ccd17..f8f5c1d85 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -883,6 +883,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) - /* AVX512 BFloat16 Instruction */ - #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) -+/* CMPCCXADD Instructions */ -+#define CPUID_7_1_EAX_CMPCCXADD (1U << 7) - /* Fast Zero REP MOVS */ - #define CPUID_7_1_EAX_FZRM (1U << 10) - /* Fast Short REP STOS */ --- -2.25.1 diff --git a/1081-target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch b/1081-target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch deleted file mode 100644 index b4d6ebcdcf5f8ccca502b31259e572c4a20af256..0000000000000000000000000000000000000000 --- a/1081-target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch +++ /dev/null @@ -1,60 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:09 +0800 -Subject: [PATCH] target/i386: Add support for AMX-FP16 in CPUID enumeration - -commit 99ed8445ea27742a4df40f51a3a5fbd6f8e76fa5 upstream. - -Latest Intel platform Granite Rapids has introduced a new instruction - -AMX-FP16, which performs dot-products of two FP16 tiles and accumulates -the results into a packed single precision tile. AMX-FP16 adds FP16 -capability and allows a FP16 GPU trained model to run faster without -loss of accuracy or added SW overhead. - -The bit definition: -CPUID.(EAX=7,ECX=1):EAX[bit 21] - -Add CPUID definition for AMX-FP16. - -Intel-SIG: commit 99ed8445ea27 target/i386: Add support for AMX-FP16 in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-3-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 6a8e07904..074dcb573 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -876,7 +876,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - NULL, NULL, "fzrm", "fsrs", - "fsrc", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, "amx-fp16", NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - }, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index f8f5c1d85..62f61cefb 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -891,6 +891,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EAX_FSRS (1U << 11) - /* Fast Short REP CMPS/SCAS */ - #define CPUID_7_1_EAX_FSRC (1U << 12) -+/* Support Tile Computational Operations on FP16 Numbers */ -+#define CPUID_7_1_EAX_AMX_FP16 (1U << 21) - - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) --- -2.25.1 diff --git a/1082-target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch b/1082-target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch deleted file mode 100644 index 1234f5dd13d788459fa4b6696e0cf5d88939596f..0000000000000000000000000000000000000000 --- a/1082-target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch +++ /dev/null @@ -1,58 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:10 +0800 -Subject: [PATCH] target/i386: Add support for AVX-IFMA in CPUID enumeration - -commit a957a88416ecbec51e147cba9fe89b93f6646b3b upstream. - -AVX-IFMA is a new instruction in the latest Intel platform Sierra -Forest. This instruction packed multiplies unsigned 52-bit integers and -adds the low/high 52-bit products to Qword Accumulators. - -The bit definition: -CPUID.(EAX=7,ECX=1):EAX[bit 23] - -Add CPUID definition for AVX-IFMA. - -Intel-SIG: commit a957a88416ec target/i386: Add support for AVX-IFMA in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-4-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 074dcb573..556810da8 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -876,7 +876,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - NULL, NULL, "fzrm", "fsrs", - "fsrc", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, "amx-fp16", NULL, NULL, -+ NULL, "amx-fp16", NULL, "avx-ifma", - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - }, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 62f61cefb..4f5e1f35d 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -893,6 +893,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EAX_FSRC (1U << 12) - /* Support Tile Computational Operations on FP16 Numbers */ - #define CPUID_7_1_EAX_AMX_FP16 (1U << 21) -+/* Support for VPMADD52[H,L]UQ */ -+#define CPUID_7_1_EAX_AVX_IFMA (1U << 23) - - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) --- -2.25.1 diff --git a/1083-target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch b/1083-target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch deleted file mode 100644 index 066813d82d564530d4fdc79fbeb8a120992da712..0000000000000000000000000000000000000000 --- a/1083-target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch +++ /dev/null @@ -1,108 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:11 +0800 -Subject: [PATCH] target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration - -commit eaaa197d5b112ea2758b54df58881a2626de3af5 upstream. - -AVX-VNNI-INT8 is a new set of instructions in the latest Intel platform -Sierra Forest, aims for the platform to have superior AI capabilities. -This instruction multiplies the individual bytes of two unsigned or -unsigned source operands, then adds and accumulates the results into the -destination dword element size operand. - -The bit definition: -CPUID.(EAX=7,ECX=1):EDX[bit 4] - -AVX-VNNI-INT8 is on a new feature bits leaf. Add a CPUID feature word -FEAT_7_1_EDX for this leaf. - -Add CPUID definition for AVX-VNNI-INT8. - -Intel-SIG: commit eaaa197d5b11 target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-5-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 22 +++++++++++++++++++++- - target/i386/cpu.h | 4 ++++ - 2 files changed, 25 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 556810da8..cd7ee2473 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -664,6 +664,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - #define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM - #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ - CPUID_7_1_EAX_FSRC) -+#define TCG_7_1_EDX_FEATURES 0 - #define TCG_APM_FEATURES 0 - #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT - #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) -@@ -887,6 +888,25 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - }, - .tcg_features = TCG_7_1_EAX_FEATURES, - }, -+ [FEAT_7_1_EDX] = { -+ .type = CPUID_FEATURE_WORD, -+ .feat_names = { -+ NULL, NULL, NULL, NULL, -+ "avx-vnni-int8", NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .cpuid = { -+ .eax = 7, -+ .needs_ecx = true, .ecx = 1, -+ .reg = R_EDX, -+ }, -+ .tcg_features = TCG_7_1_EDX_FEATURES, -+ }, - [FEAT_8000_0007_EDX] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { -@@ -5525,9 +5545,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - } - } else if (count == 1) { - *eax = env->features[FEAT_7_1_EAX]; -+ *edx = env->features[FEAT_7_1_EDX]; - *ebx = 0; - *ecx = 0; -- *edx = 0; - } else { - *eax = 0; - *ebx = 0; -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 4f5e1f35d..79e456d47 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -602,6 +602,7 @@ typedef enum FeatureWord { - FEAT_SGX_12_0_EAX, /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */ - FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ - FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ -+ FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */ - FEATURE_WORDS, - } FeatureWord; - -@@ -896,6 +897,9 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - /* Support for VPMADD52[H,L]UQ */ - #define CPUID_7_1_EAX_AVX_IFMA (1U << 23) - -+/* Support for VPDPB[SU,UU,SS]D[,S] */ -+#define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) -+ - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) - --- -2.25.1 diff --git a/1084-target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch b/1084-target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch deleted file mode 100644 index 3672e8be2883847eee0c234f8ee980e760e632c6..0000000000000000000000000000000000000000 --- a/1084-target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch +++ /dev/null @@ -1,59 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:12 +0800 -Subject: [PATCH] target/i386: Add support for AVX-NE-CONVERT in CPUID enumeration - -commit ecd2e6ca037d7bf3673c5478590d686d5cd6135a upstream. - -AVX-NE-CONVERT is a new set of instructions which can convert low -precision floating point like BF16/FP16 to high precision floating point -FP32, as well as convert FP32 elements to BF16. This instruction allows -the platform to have improved AI capabilities and better compatibility. - -The bit definition: -CPUID.(EAX=7,ECX=1):EDX[bit 5] - -Add CPUID definition for AVX-NE-CONVERT. - -Intel-SIG: commit ecd2e6ca037d target/i386: Add support for AVX-NE-CONVERT in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-6-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index cd7ee2473..eb5e0b0b7 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -892,7 +892,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { - NULL, NULL, NULL, NULL, -- "avx-vnni-int8", NULL, NULL, NULL, -+ "avx-vnni-int8", "avx-ne-convert", NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 79e456d47..4757479ac 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -899,6 +899,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - - /* Support for VPDPB[SU,UU,SS]D[,S] */ - #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) -+/* AVX NE CONVERT Instructions */ -+#define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) - - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) --- -2.25.1 diff --git a/1085-target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch b/1085-target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch deleted file mode 100644 index 38b6f03ef6e73cd1f8c8e5830a168b88af1bac35..0000000000000000000000000000000000000000 --- a/1085-target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch +++ /dev/null @@ -1,58 +0,0 @@ -From: Jiaxi Chen -Date: Fri, 3 Mar 2023 14:59:13 +0800 -Subject: [PATCH] target/i386: Add support for PREFETCHIT0/1 in CPUID enumeration - -commit d1a1111514333e46a98b136235f71eef90d610fa upstream. - -Latest Intel platform Granite Rapids has introduced a new instruction - -PREFETCHIT0/1, which moves code to memory (cache) closer to the -processor depending on specific hints. - -The bit definition: -CPUID.(EAX=7,ECX=1):EDX[bit 14] - -Add CPUID definition for PREFETCHIT0/1. - -Intel-SIG: commit d1a111151433 target/i386: Add support for PREFETCHIT0/1 in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Jiaxi Chen -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-Id: <20230303065913.1246327-7-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index eb5e0b0b7..7738d29e8 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -894,7 +894,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - NULL, NULL, NULL, NULL, - "avx-vnni-int8", "avx-ne-convert", NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, NULL, "prefetchiti", NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 4757479ac..435f458cf 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -901,6 +901,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) - /* AVX NE CONVERT Instructions */ - #define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) -+/* PREFETCHIT0/1 Instructions */ -+#define CPUID_7_1_EDX_PREFETCHITI (1U << 14) - - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) --- -2.25.1 diff --git a/1086-target-i386-Adjust-feature-level-according-to-FEAT_7.patch b/1086-target-i386-Adjust-feature-level-according-to-FEAT_7.patch deleted file mode 100644 index d4990f081043fdba9dcc8b5ca96aa5cf20847756..0000000000000000000000000000000000000000 --- a/1086-target-i386-Adjust-feature-level-according-to-FEAT_7.patch +++ /dev/null @@ -1,43 +0,0 @@ -From: Tao Su -Date: Thu, 6 Jul 2023 13:49:44 +0800 -Subject: [PATCH] target/i386: Adjust feature level according to FEAT_7_1_EDX - -commit 8731336e90dea3dd04948127e775c9f087f97a4c upstream. - -If FEAT_7_1_EAX is 0 and FEAT_7_1_EDX is non-zero, as is the case -with a Granite Rapids host and -'-cpu host,-avx-vnni,-avx512-bf16,-fzrm,-fsrs,-fsrc,-amx-fp16', we can't -get CPUID_7_1 leaf even though CPUID_7_1_EDX has non-zero value. - -Update cpuid_level_func7 according to CPUID_7_1_EDX, otherwise -guest may report wrong maximum number sub-leaves in leaf 07H. - -Fixes: eaaa197d5b11 ("target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration") -Intel-SIG: commit 8731336e90de target/i386: Adjust feature level according to FEAT_7_1_EDX. -Add SPR/GNR/SRA new ISAs backporting - -Cc: qemu-stable@nongnu.org -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-ID: <20230706054949.66556-2-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 7738d29e8..32937b0d0 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -6369,6 +6369,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX); - x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX); -+ x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX); --- -2.25.1 diff --git a/1087-target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch b/1087-target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch deleted file mode 100644 index 69cacca9b91c1c6bd77a414ce9a5dead857a8c74..0000000000000000000000000000000000000000 --- a/1087-target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch +++ /dev/null @@ -1,40 +0,0 @@ -From: Tao Su -Date: Thu, 6 Jul 2023 13:49:47 +0800 -Subject: [PATCH] target/i386: Add new bit definitions of MSR_IA32_ARCH_CAPABILITIES - -commit 6c43ec3b206956a8a3008accafe9eb2dfd885190 upstream. - -Currently, bit 13, 14, 15 and 24 of MSR_IA32_ARCH_CAPABILITIES are -disclosed for fixing security issues, so add those bit definitions. - -Intel-SIG: commit 6c43ec3b2069 target/i386: Add new bit definitions of MSR_IA32_ARCH_CAPABILITIES. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Tao Su -Reviewed-by: Igor Mammedov -Message-ID: <20230706054949.66556-5-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.h | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 435f458cf..c65133ab6 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -977,7 +977,11 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define MSR_ARCH_CAP_PSCHANGE_MC_NO (1U << 6) - #define MSR_ARCH_CAP_TSX_CTRL_MSR (1U << 7) - #define MSR_ARCH_CAP_TAA_NO (1U << 8) -+#define MSR_ARCH_CAP_SBDR_SSDP_NO (1U << 13) -+#define MSR_ARCH_CAP_FBSDP_NO (1U << 14) -+#define MSR_ARCH_CAP_PSDP_NO (1U << 15) - #define MSR_ARCH_CAP_FB_CLEAR (1U << 17) -+#define MSR_ARCH_CAP_PBRSB_NO (1U << 24) - - #define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) - --- -2.25.1 diff --git a/1088-target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch b/1088-target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch deleted file mode 100644 index 0fcfd8e19120131a717d4e8be599e2f144033f55..0000000000000000000000000000000000000000 --- a/1088-target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch +++ /dev/null @@ -1,110 +0,0 @@ -From: Tao Su -Date: Thu, 6 Jul 2023 13:49:45 +0800 -Subject: [PATCH] target/i386: Add support for MCDT_NO in CPUID enumeration - -commit 9dd8b71091f47bac395f543779269c14d8d93c60 upstream. - -CPUID.(EAX=7,ECX=2):EDX[bit 5] enumerates MCDT_NO. Processors enumerate -this bit as 1 do not exhibit MXCSR Configuration Dependent Timing (MCDT) -behavior and do not need to be mitigated to avoid data-dependent behavior -for certain instructions. - -Since MCDT_NO is in a new sub-leaf, add a new CPUID feature word -FEAT_7_2_EDX. Also update cpuid_level_func7 by FEAT_7_2_EDX. - -Intel-SIG: commit 9dd8b71091f4 target/i386: Add support for MCDT_NO in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-ID: <20230706054949.66556-3-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 26 ++++++++++++++++++++++++++ - target/i386/cpu.h | 4 ++++ - 2 files changed, 30 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 32937b0d0..0547dda2e 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -665,6 +665,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ - CPUID_7_1_EAX_FSRC) - #define TCG_7_1_EDX_FEATURES 0 -+#define TCG_7_2_EDX_FEATURES 0 - #define TCG_APM_FEATURES 0 - #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT - #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) -@@ -907,6 +908,25 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - }, - .tcg_features = TCG_7_1_EDX_FEATURES, - }, -+ [FEAT_7_2_EDX] = { -+ .type = CPUID_FEATURE_WORD, -+ .feat_names = { -+ NULL, NULL, NULL, NULL, -+ NULL, "mcdt-no", NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .cpuid = { -+ .eax = 7, -+ .needs_ecx = true, .ecx = 2, -+ .reg = R_EDX, -+ }, -+ .tcg_features = TCG_7_2_EDX_FEATURES, -+ }, - [FEAT_8000_0007_EDX] = { - .type = CPUID_FEATURE_WORD, - .feat_names = { -@@ -5548,6 +5568,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - *edx = env->features[FEAT_7_1_EDX]; - *ebx = 0; - *ecx = 0; -+ } else if (count == 2) { -+ *edx = env->features[FEAT_7_2_EDX]; -+ *eax = 0; -+ *ebx = 0; -+ *ecx = 0; - } else { - *eax = 0; - *ebx = 0; -@@ -6370,6 +6395,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX); - x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EDX); -+ x86_cpu_adjust_feat_level(cpu, FEAT_7_2_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX); -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index c65133ab6..26572b846 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -603,6 +603,7 @@ typedef enum FeatureWord { - FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ - FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ - FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */ -+ FEAT_7_2_EDX, /* CPUID[EAX=7,ECX=2].EDX */ - FEATURE_WORDS, - } FeatureWord; - -@@ -904,6 +905,9 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - /* PREFETCHIT0/1 Instructions */ - #define CPUID_7_1_EDX_PREFETCHITI (1U << 14) - -+/* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ -+#define CPUID_7_2_EDX_MCDT_NO (1U << 5) -+ - /* XFD Extend Feature Disabled */ - #define CPUID_D_1_EAX_XFD (1U << 4) - --- -2.25.1 diff --git a/1089-target-i386-Add-new-CPU-model-GraniteRapids.patch b/1089-target-i386-Add-new-CPU-model-GraniteRapids.patch deleted file mode 100644 index 938ced80d8e9e46064dbe27d5378830c61f5ebd6..0000000000000000000000000000000000000000 --- a/1089-target-i386-Add-new-CPU-model-GraniteRapids.patch +++ /dev/null @@ -1,181 +0,0 @@ -From: Tao Su -Date: Thu, 6 Jul 2023 13:49:49 +0800 -Subject: [PATCH] target/i386: Add new CPU model GraniteRapids - -commit 6d5e9694ef374159072984c0958c3eaab6dd1d52 upstream. - -The GraniteRapids CPU model mainly adds the following new features -based on SapphireRapids: -- PREFETCHITI CPUID.(EAX=7,ECX=1):EDX[bit 14] -- AMX-FP16 CPUID.(EAX=7,ECX=1):EAX[bit 21] - -And adds the following security fix for corresponding vulnerabilities: -- MCDT_NO CPUID.(EAX=7,ECX=2):EDX[bit 5] -- SBDR_SSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 13] -- FBSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 14] -- PSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 15] -- PBRSB_NO MSR_IA32_ARCH_CAPABILITIES[bit 24] - -Intel-SIG: commit 6d5e9694ef37 target/i386: Add new CPU model GraniteRapids. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Tao Su -Tested-by: Xuelian Guo -Reviewed-by: Xiaoyao Li -Message-ID: <20230706054949.66556-7-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 136 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 0547dda2e..b7cdca7cc 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3966,6 +3966,142 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ }, - }, - }, -+ { -+ .name = "GraniteRapids", -+ .level = 0x20, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 173, -+ .stepping = 0, -+ /* -+ * please keep the ascending order so that we can have a clear view of -+ * bit position of each feature. -+ */ -+ .features[FEAT_1_EDX] = -+ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | -+ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | -+ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | -+ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | -+ CPUID_SSE | CPUID_SSE2, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | -+ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | -+ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | -+ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | -+ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_WBNOINVD, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_HLE | -+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | -+ CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RTM | -+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | -+ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | -+ CPUID_7_0_EBX_AVX512IFMA | CPUID_7_0_EBX_CLFLUSHOPT | -+ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | -+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, -+ .features[FEAT_7_0_ECX] = -+ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | -+ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | -+ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | -+ CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | -+ CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57 | -+ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | -+ CPUID_7_0_EDX_TSX_LDTRK | CPUID_7_0_EDX_AMX_BF16 | -+ CPUID_7_0_EDX_AVX512_FP16 | CPUID_7_0_EDX_AMX_TILE | -+ CPUID_7_0_EDX_AMX_INT8 | CPUID_7_0_EDX_SPEC_CTRL | -+ CPUID_7_0_EDX_ARCH_CAPABILITIES | CPUID_7_0_EDX_SPEC_CTRL_SSBD, -+ .features[FEAT_ARCH_CAPABILITIES] = -+ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | -+ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | -+ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO | -+ MSR_ARCH_CAP_SBDR_SSDP_NO | MSR_ARCH_CAP_FBSDP_NO | -+ MSR_ARCH_CAP_PSDP_NO | MSR_ARCH_CAP_PBRSB_NO, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES | CPUID_D_1_EAX_XFD, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_7_1_EAX] = -+ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16 | -+ CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_FSRC | -+ CPUID_7_1_EAX_AMX_FP16, -+ .features[FEAT_7_1_EDX] = -+ CPUID_7_1_EDX_PREFETCHITI, -+ .features[FEAT_7_2_EDX] = -+ CPUID_7_2_EDX_MCDT_NO, -+ .features[FEAT_VMX_BASIC] = -+ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = -+ MSR_VMX_EPT_EXECONLY | -+ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_PAGE_WALK_LENGTH_5 | -+ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | -+ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | -+ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = -+ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | -+ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | -+ VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = -+ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | -+ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | -+ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | -+ VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | -+ VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | -+ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | -+ VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | -+ VMX_SECONDARY_EXEC_XSAVES, -+ .features[FEAT_VMX_VMFUNC] = -+ MSR_VMX_VMFUNC_EPT_SWITCHING, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon Processor (GraniteRapids)", -+ .versions = (X86CPUVersionDefinition[]) { -+ { .version = 1 }, -+ { /* end of list */ }, -+ }, -+ }, - { - .name = "KnightsMill", - .level = 0xd, --- -2.25.1 diff --git a/1090-target-i386-Add-support-for-AMX-COMPLEX-in-CPUID-enu.patch b/1090-target-i386-Add-support-for-AMX-COMPLEX-in-CPUID-enu.patch deleted file mode 100644 index 5d175da0c140ef16c73c66cae230dd6d684b6f99..0000000000000000000000000000000000000000 --- a/1090-target-i386-Add-support-for-AMX-COMPLEX-in-CPUID-enu.patch +++ /dev/null @@ -1,57 +0,0 @@ -From: Tao Su -Date: Wed, 30 Aug 2023 15:43:24 +0800 -Subject: [PATCH] target/i386: Add support for AMX-COMPLEX in CPUID enumeration - -commit 3e76bafb28c8292be5c4a32cab873b3a82cbcc87 upstream. - -Latest Intel platform GraniteRapids-D introduces AMX-COMPLEX, which adds -two instructions to perform matrix multiplication of two tiles containing -complex elements and accumulate the results into a packed single precision -tile. - -AMX-COMPLEX is enumerated via CPUID.(EAX=7,ECX=1):EDX[bit 8]. Add the CPUID -definition for AMX-COMPLEX, AMX-COMPLEX will be enabled automatically when -using '-cpu host' and KVM advertises AMX-COMPLEX to userspace. - -Intel-SIG: commit 3e76bafb28c8 target/i386: Add support for AMX-COMPLEX in CPUID enumeration. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Tao Su -Reviewed-by: Xiaoyao Li -Message-ID: <20230830074324.84059-1-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index b7cdca7cc..4a33baade 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -894,7 +894,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .feat_names = { - NULL, NULL, NULL, NULL, - "avx-vnni-int8", "avx-ne-convert", NULL, NULL, -- NULL, NULL, NULL, NULL, -+ "amx-complex", NULL, NULL, NULL, - NULL, NULL, "prefetchiti", NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 26572b846..e84cb8265 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -902,6 +902,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) - /* AVX NE CONVERT Instructions */ - #define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) -+/* AMX COMPLEX Instructions */ -+#define CPUID_7_1_EDX_AMX_COMPLEX (1U << 8) - /* PREFETCHIT0/1 Instructions */ - #define CPUID_7_1_EDX_PREFETCHITI (1U << 14) - --- -2.25.1 diff --git a/1091-target-i386-Add-new-CPU-model-SierraForest.patch b/1091-target-i386-Add-new-CPU-model-SierraForest.patch deleted file mode 100644 index 8ab9a0978da89c409df0b69aed6d5fa8871d45a0..0000000000000000000000000000000000000000 --- a/1091-target-i386-Add-new-CPU-model-SierraForest.patch +++ /dev/null @@ -1,207 +0,0 @@ -From: Tao Su -Date: Wed, 20 Mar 2024 10:10:44 +0800 -Subject: [PATCH] target/i386: Add new CPU model SierraForest - -commit 6e82d3b6220777667968a04c87e1667f164ebe88 upstream. - -According to table 1-2 in Intel Architecture Instruction Set Extensions and -Future Features (rev 051) [1], SierraForest has the following new features -which have already been virtualized: - -- CMPCCXADD CPUID.(EAX=7,ECX=1):EAX[bit 7] -- AVX-IFMA CPUID.(EAX=7,ECX=1):EAX[bit 23] -- AVX-VNNI-INT8 CPUID.(EAX=7,ECX=1):EDX[bit 4] -- AVX-NE-CONVERT CPUID.(EAX=7,ECX=1):EDX[bit 5] - -Add above features to new CPU model SierraForest. Comparing with GraniteRapids -CPU model, SierraForest bare-metal removes the following features: - -- HLE CPUID.(EAX=7,ECX=0):EBX[bit 4] -- RTM CPUID.(EAX=7,ECX=0):EBX[bit 11] -- AVX512F CPUID.(EAX=7,ECX=0):EBX[bit 16] -- AVX512DQ CPUID.(EAX=7,ECX=0):EBX[bit 17] -- AVX512_IFMA CPUID.(EAX=7,ECX=0):EBX[bit 21] -- AVX512CD CPUID.(EAX=7,ECX=0):EBX[bit 28] -- AVX512BW CPUID.(EAX=7,ECX=0):EBX[bit 30] -- AVX512VL CPUID.(EAX=7,ECX=0):EBX[bit 31] -- AVX512_VBMI CPUID.(EAX=7,ECX=0):ECX[bit 1] -- AVX512_VBMI2 CPUID.(EAX=7,ECX=0):ECX[bit 6] -- AVX512_VNNI CPUID.(EAX=7,ECX=0):ECX[bit 11] -- AVX512_BITALG CPUID.(EAX=7,ECX=0):ECX[bit 12] -- AVX512_VPOPCNTDQ CPUID.(EAX=7,ECX=0):ECX[bit 14] -- LA57 CPUID.(EAX=7,ECX=0):ECX[bit 16] -- TSXLDTRK CPUID.(EAX=7,ECX=0):EDX[bit 16] -- AMX-BF16 CPUID.(EAX=7,ECX=0):EDX[bit 22] -- AVX512_FP16 CPUID.(EAX=7,ECX=0):EDX[bit 23] -- AMX-TILE CPUID.(EAX=7,ECX=0):EDX[bit 24] -- AMX-INT8 CPUID.(EAX=7,ECX=0):EDX[bit 25] -- AVX512_BF16 CPUID.(EAX=7,ECX=1):EAX[bit 5] -- fast zero-length MOVSB CPUID.(EAX=7,ECX=1):EAX[bit 10] -- fast short CMPSB, SCASB CPUID.(EAX=7,ECX=1):EAX[bit 12] -- AMX-FP16 CPUID.(EAX=7,ECX=1):EAX[bit 21] -- PREFETCHI CPUID.(EAX=7,ECX=1):EDX[bit 14] -- XFD CPUID.(EAX=0xD,ECX=1):EAX[bit 4] -- EPT_PAGE_WALK_LENGTH_5 VMX_EPT_VPID_CAP(0x48c)[bit 7] - -Add all features of GraniteRapids CPU model except above features to -SierraForest CPU model. - -SierraForest doesn’t support TSX and RTM but supports TAA_NO. When RTM is -not enabled in host, KVM will not report TAA_NO. So, just don't include -TAA_NO in SierraForest CPU model. - -[1] https://cdrdv2.intel.com/v1/dl/getContent/671368 - -Intel-SIG: commit 6e82d3b62207 target/i386: Add new CPU model SierraForest. -Add SPR/GNR/SRA new ISAs backporting - -Reviewed-by: Zhao Liu -Reviewed-by: Xiaoyao Li -Signed-off-by: Tao Su -Message-ID: <20240320021044.508263-1-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 126 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 4a33baade..00157dae9 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3715,6 +3715,132 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ }, - }, - }, -+ { -+ .name = "SierraForest", -+ .level = 0x23, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 175, -+ .stepping = 0, -+ /* -+ * please keep the ascending order so that we can have a clear view of -+ * bit position of each feature. -+ */ -+ .features[FEAT_1_EDX] = -+ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | -+ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | -+ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | -+ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | -+ CPUID_SSE | CPUID_SSE2, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | -+ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | -+ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | -+ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | -+ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_WBNOINVD, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | -+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | -+ CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | -+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB | -+ CPUID_7_0_EBX_SHA_NI, -+ .features[FEAT_7_0_ECX] = -+ CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_GFNI | -+ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | -+ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | -+ CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_ARCH_CAPABILITIES | -+ CPUID_7_0_EDX_SPEC_CTRL_SSBD, -+ .features[FEAT_ARCH_CAPABILITIES] = -+ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | -+ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | -+ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_SBDR_SSDP_NO | -+ MSR_ARCH_CAP_FBSDP_NO | MSR_ARCH_CAP_PSDP_NO | -+ MSR_ARCH_CAP_PBRSB_NO, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_7_1_EAX] = -+ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_CMPCCXADD | -+ CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_AVX_IFMA, -+ .features[FEAT_7_1_EDX] = -+ CPUID_7_1_EDX_AVX_VNNI_INT8 | CPUID_7_1_EDX_AVX_NE_CONVERT, -+ .features[FEAT_7_2_EDX] = -+ CPUID_7_2_EDX_MCDT_NO, -+ .features[FEAT_VMX_BASIC] = -+ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, -+ .features[FEAT_VMX_ENTRY_CTLS] = -+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | -+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, -+ .features[FEAT_VMX_EPT_VPID_CAPS] = -+ MSR_VMX_EPT_EXECONLY | MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | -+ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | -+ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | -+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | -+ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | -+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, -+ .features[FEAT_VMX_EXIT_CTLS] = -+ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | -+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | -+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | -+ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, -+ .features[FEAT_VMX_MISC] = -+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | -+ MSR_VMX_MISC_VMWRITE_VMEXIT, -+ .features[FEAT_VMX_PINBASED_CTLS] = -+ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | -+ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | -+ VMX_PIN_BASED_POSTED_INTR, -+ .features[FEAT_VMX_PROCBASED_CTLS] = -+ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | -+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | -+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | -+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | -+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | -+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | -+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | -+ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | -+ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | -+ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | -+ VMX_CPU_BASED_PAUSE_EXITING | -+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, -+ .features[FEAT_VMX_SECONDARY_CTLS] = -+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -+ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | -+ VMX_SECONDARY_EXEC_RDTSCP | -+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | -+ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | -+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | -+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -+ VMX_SECONDARY_EXEC_RDRAND_EXITING | -+ VMX_SECONDARY_EXEC_ENABLE_INVPCID | -+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | -+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | -+ VMX_SECONDARY_EXEC_XSAVES, -+ .features[FEAT_VMX_VMFUNC] = -+ MSR_VMX_VMFUNC_EPT_SWITCHING, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon Processor (SierraForest)", -+ .versions = (X86CPUVersionDefinition[]) { -+ { .version = 1 }, -+ { /* end of list */ }, -+ }, -+ }, - { - .name = "Denverton", - .level = 21, --- -2.25.1 diff --git a/1092-target-i386-Export-RFDS-bit-to-guests.patch b/1092-target-i386-Export-RFDS-bit-to-guests.patch deleted file mode 100644 index 87d94658fda39268363141996e054c6f8952f6f7..0000000000000000000000000000000000000000 --- a/1092-target-i386-Export-RFDS-bit-to-guests.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: Pawan Gupta -Date: Wed, 13 Mar 2024 07:53:23 -0700 -Subject: [PATCH] target/i386: Export RFDS bit to guests - -commit 41bdd9812863c150284a9339a048ed88c40f4df7 upstream. - -Register File Data Sampling (RFDS) is a CPU side-channel vulnerability -that may expose stale register value. CPUs that set RFDS_NO bit in MSR -IA32_ARCH_CAPABILITIES indicate that they are not vulnerable to RFDS. -Similarly, RFDS_CLEAR indicates that CPU is affected by RFDS, and has -the microcode to help mitigate RFDS. - -Make RFDS_CLEAR and RFDS_NO bits available to guests. - -Intel-SIG: commit 41bdd9812863 target/i386: Export RFDS bit to guests. -Add SPR/GNR/SRA new ISAs backporting - -Signed-off-by: Pawan Gupta -Reviewed-by: Xiaoyao Li -Reviewed-by: Zhao Liu -Message-ID: <9a38877857392b5c2deae7e7db1b170d15510314.1710341348.git.pawan.kumar.gupta@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 00157dae9..80c3b58d1 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1025,8 +1025,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - NULL, NULL, NULL, NULL, - NULL, "fb-clear", NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, "rfds-no", -+ "rfds-clear", NULL, NULL, NULL, - }, - .msr = { - .index = MSR_IA32_ARCH_CAPABILITIES, --- -2.25.1 diff --git a/1093-target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch b/1093-target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch deleted file mode 100644 index 48bd8388c44c50ddd1565228fe844b4f0fe08be3..0000000000000000000000000000000000000000 --- a/1093-target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch +++ /dev/null @@ -1,50 +0,0 @@ -From: Lei Wang -Date: Thu, 6 Jul 2023 13:49:48 +0800 -Subject: [PATCH] target/i386: Add few security fix bits in ARCH_CAPABILITIES into SapphireRapids CPU model - -commit 3baf7ae63505eb1652d1e52d65798307fead8539 upstream. - -SapphireRapids has bit 13, 14 and 15 of MSR_IA32_ARCH_CAPABILITIES -enabled, which are related to some security fixes. - -Add version 2 of SapphireRapids CPU model with those bits enabled also. - -Intel-SIG: commit 3baf7ae63505 target/i386: Add few security fix bits in ARCH_CAPABILITIES into SapphireRapids CPU model. -6.2-SPR new model support - -Signed-off-by: Lei Wang -Signed-off-by: Tao Su -Message-ID: <20230706054949.66556-6-tao1.su@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 0a3c76854..8a045e065 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3762,8 +3762,17 @@ static const X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Xeon Processor (SapphireRapids)", - .versions = (X86CPUVersionDefinition[]) { - { .version = 1 }, -- { /* end of list */ }, -- }, -+ { -+ .version = 2, -+ .props = (PropValue[]) { -+ { "sbdr-ssdp-no", "on" }, -+ { "fbsdp-no", "on" }, -+ { "psdp-no", "on" }, -+ { /* end of list */ } -+ } -+ }, -+ { /* end of list */ } -+ } - }, - { - .name = "SierraForest", --- -2.25.1 diff --git a/1094-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch b/1094-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch deleted file mode 100644 index a035ee120ae650079c33b4932988cb4f1dbd8b10..0000000000000000000000000000000000000000 --- a/1094-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: Lei Wang -Date: Wed, 24 Apr 2024 03:29:12 -0400 -Subject: [PATCH] target/i386: Introduce SapphireRapids-v3 to add missing features - -commit b10b2481738304db13d28252e86c10555121a5b3 upstream. - -Add the missing features(ss, tsc-adjust, cldemote, movdiri, movdir64b) in -the SapphireRapids-v3 CPU model. - -Intel-SIG: commit b10b24817383 target/i386: Introduce SapphireRapids-v3 to add missing features. -6.2-SPR new model support - -Signed-off-by: Lei Wang -Message-ID: <20240424072912.43188-1-lei4.wang@intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index f4b5c95c5..baa1a8207 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3730,6 +3730,17 @@ static const X86CPUDefinition builtin_x86_defs[] = { - { /* end of list */ } - } - }, -+ { -+ .version = 3, -+ .props = (PropValue[]) { -+ { "ss", "on" }, -+ { "tsc-adjust", "on" }, -+ { "cldemote", "on" }, -+ { "movdiri", "on" }, -+ { "movdir64b", "on" }, -+ { /* end of list */ } -+ } -+ }, - { /* end of list */ } - } - }, --- -2.25.1 diff --git a/1095-ebpf-replace-deprecated-bpf_program__set_socket_filt.patch b/1095-ebpf-replace-deprecated-bpf_program__set_socket_filt.patch deleted file mode 100644 index 574626b422a5a54adbed9c688b4109f396207a45..0000000000000000000000000000000000000000 --- a/1095-ebpf-replace-deprecated-bpf_program__set_socket_filt.patch +++ /dev/null @@ -1,37 +0,0 @@ -From: Haochen Tong -Date: Sat, 28 May 2022 03:06:58 +0800 -Subject: [PATCH] ebpf: replace deprecated bpf_program__set_socket_filter - -commit a495eba03c31c96d6a0817b13598ce2219326691 upstream. - -bpf_program__set_ functions have been deprecated since libbpf 0.8. -Replace with the equivalent bpf_program__set_type call to avoid a -deprecation warning. - -Intel-SIG: commit a495eba03c31 ebpf: replace deprecated bpf_program__set_socket_filter. -6.2-SPR new model support - -Signed-off-by: Haochen Tong -Reviewed-by: Zhang Chen -Signed-off-by: Jason Wang -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - ebpf/ebpf_rss.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c -index 118c68da83..cee658c158 100644 ---- a/ebpf/ebpf_rss.c -+++ b/ebpf/ebpf_rss.c -@@ -49,7 +49,7 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx) - goto error; - } - -- bpf_program__set_socket_filter(rss_bpf_ctx->progs.tun_rss_steering_prog); -+ bpf_program__set_type(rss_bpf_ctx->progs.tun_rss_steering_prog, BPF_PROG_TYPE_SOCKET_FILTER); - - if (rss_bpf__load(rss_bpf_ctx)) { - trace_ebpf_error("eBPF RSS", "can not load RSS program"); --- -2.25.1 diff --git a/1096-target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch b/1096-target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch deleted file mode 100644 index 03873421fc2106c10a4e6cf41fcbac15b915fb3f..0000000000000000000000000000000000000000 --- a/1096-target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: Pawan Gupta -Date: Fri, 23 Jun 2023 13:26:25 -0700 -Subject: [PATCH] target/i386: Export MSR_ARCH_CAPABILITIES bits to guests - -commit 5bef742cc4f0e21c80a31611af7881ba811e507f upstream. - -On Intel CPUs there are certain bits in MSR_ARCH_CAPABILITIES that -indicates if the CPU is not affected by a vulnerability. Without these -bits guests may try to deploy the mitigation even if the CPU is not -affected. - -Export the bits to guests that indicate immunity to hardware -vulnerabilities. - -Intel-SIG: commit 5bef742cc4f0 target/i386: Export MSR_ARCH_CAPABILITIES bits to guests. -6.2-SPR new model support - -Signed-off-by: Pawan Gupta -Message-ID: <63d85cc76d4cdc51e6c732478b81d8f13be11e5a.1687551881.git.pawan.kumar.gupta@linux.intel.com> -Signed-off-by: Paolo Bonzini -[ Quanxian Wang: amend commit log ] -Signed-off-by: Quanxian Wang ---- - target/i386/cpu.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 11f52c79b..62149367b 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1022,10 +1022,10 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - "rdctl-no", "ibrs-all", "rsba", "skip-l1dfl-vmentry", - "ssb-no", "mds-no", "pschange-mc-no", "tsx-ctrl", - "taa-no", NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, "sbdr-ssdp-no", "fbsdp-no", "psdp-no", - NULL, "fb-clear", NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, "rfds-no", -+ "pbrsb-no", NULL, NULL, "rfds-no", - "rfds-clear", NULL, NULL, NULL, - }, - .msr = { --- -2.25.1 diff --git a/81-kvm-anolis.rules b/81-kvm-rhel.rules similarity index 100% rename from 81-kvm-anolis.rules rename to 81-kvm-rhel.rules diff --git a/Add-lbt-support-for-kvm.patch b/Add-lbt-support-for-kvm.patch deleted file mode 100644 index 660785f9b96191c48b1c33fb93082979741ee81b..0000000000000000000000000000000000000000 --- a/Add-lbt-support-for-kvm.patch +++ /dev/null @@ -1,154 +0,0 @@ -From b7760c4fd70de74df6014394c5d27d498fed3e31 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 08:00:52 -0400 -Subject: [PATCH 22/28] Add lbt support for kvm - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 4 ++-- - linux-headers/asm-loongarch64/kvm.h | 10 ++++++++- - target/loongarch64/cpu.h | 10 +++++++++ - target/loongarch64/kvm.c | 35 +++++++++++++++++++++++++++++ - 4 files changed, 56 insertions(+), 3 deletions(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 8fc79546d..2affc5048 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -348,8 +348,8 @@ struct kvm_cpucfg ls3a5k_cpucfgs = { - CPUCFG1_IOCSRBRD, - .cpucfg[LOONGARCH_CPUCFG2] = CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP | - CPUCFG2_FPVERS | CPUCFG2_LSX | CPUCFG2_LASX | CPUCFG2_COMPLEX | -- CPUCFG2_CRYPTO | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | CPUCFG2_LSPW | -- CPUCFG2_LAM, -+ CPUCFG2_CRYPTO | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | CPUCFG2_X86BT | -+ CPUCFG2_ARMBT | CPUCFG2_MIPSBT | CPUCFG2_LSPW | CPUCFG2_LAM, - .cpucfg[LOONGARCH_CPUCFG3] = CPUCFG3_CCDMA | CPUCFG3_SFB | CPUCFG3_UCACC | - CPUCFG3_LLEXC | CPUCFG3_SCDLY | CPUCFG3_LLDBAR | CPUCFG3_ITLBT | - CPUCFG3_ICACHET | CPUCFG3_SPW_LVL | CPUCFG3_SPW_HG_HF | CPUCFG3_RVA | -diff --git a/linux-headers/asm-loongarch64/kvm.h b/linux-headers/asm-loongarch64/kvm.h -index 799af7594..3687a358f 100644 ---- a/linux-headers/asm-loongarch64/kvm.h -+++ b/linux-headers/asm-loongarch64/kvm.h -@@ -77,6 +77,7 @@ struct kvm_fpu { - * Register set = 2: KVM specific registers (see definitions below). - * - * Register set = 3: FPU / MSA registers (see definitions below). -+ * Register set = 4: LBT registers (see definitions below). - * - * Other sets registers may be added in the future. Each set would - * have its own identifier in bits[31..16]. -@@ -86,7 +87,7 @@ struct kvm_fpu { - #define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x0000000000010000ULL) - #define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x0000000000020000ULL) - #define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x0000000000030000ULL) -- -+#define KVM_REG_LOONGARCH_LBT (KVM_REG_LOONGARCH | 0x0000000000040000ULL) - - /* - * KVM_REG_LOONGARCH_GP - General purpose registers from kvm_regs. -@@ -168,6 +169,13 @@ struct kvm_fpu { - - #define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4) - -+#define KVM_REG_LBT_SCR0 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 1) -+#define KVM_REG_LBT_SCR1 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 2) -+#define KVM_REG_LBT_SCR2 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 3) -+#define KVM_REG_LBT_SCR3 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 4) -+#define KVM_REG_LBT_FLAGS (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 5) -+#define KVM_REG_LBT_FTOP (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 6) -+ - struct kvm_iocsr_entry { - __u32 addr; - __u32 pad; -diff --git a/target/loongarch64/cpu.h b/target/loongarch64/cpu.h -index 078556a22..ab88658e4 100644 ---- a/target/loongarch64/cpu.h -+++ b/target/loongarch64/cpu.h -@@ -55,6 +55,7 @@ typedef struct CPULOONGARCHFPUContext { - uint32_t fcsr0; - uint32_t fcsr0_rw_bitmask; - uint32_t vcsr16; -+ uint64_t ftop; - } CPULOONGARCHFPUContext; - - /* fp control and status register definition */ -@@ -167,6 +168,15 @@ struct CPULOONGARCHState { - struct { - uint64_t guest_addr; - } st; -+ struct { -+ /* scratch registers */ -+ unsigned long scr0; -+ unsigned long scr1; -+ unsigned long scr2; -+ unsigned long scr3; -+ /* loongarch eflag */ -+ unsigned long eflag; -+ } lbt; - }; - - -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -index b6711da91..0eaabe394 100644 ---- a/target/loongarch64/kvm.c -+++ b/target/loongarch64/kvm.c -@@ -1295,6 +1295,39 @@ int kvm_loongarch_get_pvtime(LOONGARCHCPU *cpu) - return 0; - } - -+ -+static int kvm_loongarch_put_lbt_registers(CPUState *cs) -+{ -+ int ret = 0; -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR0, &env->lbt.scr0); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR1, &env->lbt.scr1); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR2, &env->lbt.scr2); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_SCR3, &env->lbt.scr3); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_FLAGS, &env->lbt.eflag); -+ ret |= kvm_larch_putq(cs, KVM_REG_LBT_FTOP, &env->active_fpu.ftop); -+ -+ return ret; -+} -+ -+static int kvm_loongarch_get_lbt_registers(CPUState *cs) -+{ -+ int ret = 0; -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ CPULOONGARCHState *env = &cpu->env; -+ -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR0, &env->lbt.scr0); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR1, &env->lbt.scr1); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR2, &env->lbt.scr2); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_SCR3, &env->lbt.scr3); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_FLAGS, &env->lbt.eflag); -+ ret |= kvm_larch_getq(cs, KVM_REG_LBT_FTOP, &env->active_fpu.ftop); -+ -+ return ret; -+} -+ - int kvm_arch_put_registers(CPUState *cs, int level) - { - LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -@@ -1326,6 +1359,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) - return ret; - } - -+ kvm_loongarch_put_lbt_registers(cs); - return ret; - } - -@@ -1352,6 +1386,7 @@ int kvm_arch_get_registers(CPUState *cs) - - kvm_loongarch_get_csr_registers(cs); - kvm_loongarch_get_fpu_registers(cs); -+ kvm_loongarch_get_lbt_registers(cs); - - return ret; - } --- -2.43.5 - diff --git a/Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch b/Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch deleted file mode 100644 index 330b37d5accfd60c8c1a79fcbeae37e2067c8e09..0000000000000000000000000000000000000000 --- a/Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 3e8ddd1af3c46387ed45319dd0dc3c0a673b989f Mon Sep 17 00:00:00 2001 -From: Tianrui Zhao -Date: Mon, 19 Jun 2023 09:38:16 +0800 -Subject: [PATCH 25/28] Add loongarch into QEMU_ARCH_VIRTIO_PCI to support qdev - alias - -Signed-off-by: Tianrui Zhao ---- - softmmu/qdev-monitor.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c -index 01f3834db..ece96121d 100644 ---- a/softmmu/qdev-monitor.c -+++ b/softmmu/qdev-monitor.c -@@ -60,7 +60,8 @@ typedef struct QDevAlias - QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \ - QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \ - QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \ -- QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA) -+ QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \ -+ QEMU_ARCH_LOONGARCH64) - #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X) - #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K) - --- -2.43.5 - diff --git a/Add-usb-storage-config-for-loongarch.patch b/Add-usb-storage-config-for-loongarch.patch deleted file mode 100644 index 05295153a337d02bbd1f197d409854f8f7d72bd9..0000000000000000000000000000000000000000 --- a/Add-usb-storage-config-for-loongarch.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 1f41256389e5d8862d08b2253d752569727f1e79 Mon Sep 17 00:00:00 2001 -From: Tianrui Zhao -Date: Mon, 19 Jun 2023 09:34:02 +0800 -Subject: [PATCH 24/28] Add usb-storage config for loongarch - -Signed-off-by: Tianrui Zhao ---- - configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -index 696ee9b72..15fc2d00f 100644 ---- a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -+++ b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -@@ -147,6 +147,8 @@ CONFIG_USB_EHCI=y - CONFIG_USB_EHCI_PCI=y - CONFIG_USB_EHCI_SYSBUS=y - CONFIG_USB_STORAGE_BOT=y -+CONFIG_USB_STORAGE_CORE=y -+CONFIG_USB_STORAGE_CLASSIC=y - CONFIG_TPM_EMULATOR=y - CONFIG_TPM_TIS=y - CONFIG_PLATFORM_BUS=y --- -2.43.5 - diff --git a/Fix-LoongArch-KVM-header-macros.patch b/Fix-LoongArch-KVM-header-macros.patch deleted file mode 100644 index 57ea9d8ad249c803a1183250aefd711f23b392c6..0000000000000000000000000000000000000000 --- a/Fix-LoongArch-KVM-header-macros.patch +++ /dev/null @@ -1,32 +0,0 @@ -From d090e30797ef1acc5f0f5488a60040606f60ff44 Mon Sep 17 00:00:00 2001 -From: Tianrui Zhao -Date: Tue, 20 Jun 2023 16:34:43 +0800 -Subject: [PATCH 27/28] Fix LoongArch KVM header macros - -Signed-off-by: Tianrui Zhao ---- - linux-headers/linux/kvm.h | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index f5589b068..0e50d3749 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -2126,10 +2126,10 @@ struct kvm_loongarch_vcpu_state { - __u64 core_ext_ioisr[4]; - }; - --#define KVM_CAP_LOONGARCH_FPU 800 --#define KVM_CAP_LOONGARCH_LSX 801 --#define KVM_CAP_LOONGARCH_VZ 802 --#define KVM_REG_LOONGARCH 0x9000000000000000ULL -+#define KVM_CAP_LOONGARCH_FPU 165 -+#define KVM_CAP_LOONGARCH_LSX 166 -+#define KVM_CAP_LOONGARCH_VZ 167 -+#define KVM_REG_LOONGARCH 0x8000000000000000ULL - #define KVM_LARCH_GET_VCPU_STATE _IOR(KVMIO, 0xc0, struct kvm_loongarch_vcpu_state) - #define KVM_LARCH_SET_VCPU_STATE _IOW(KVMIO, 0xc1, struct kvm_loongarch_vcpu_state) - #define KVM_LARCH_GET_CPUCFG _IOR(KVMIO, 0xc2, struct kvm_cpucfg) --- -2.43.5 - diff --git a/Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch b/Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch deleted file mode 100644 index 9d6896c7f9504e0d9b1ae8b85368ae62009274d0..0000000000000000000000000000000000000000 --- a/Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ff15ca716d827e6364e51f1ee9d7bc6440d55c20 Mon Sep 17 00:00:00 2001 -From: Tianrui Zhao -Date: Mon, 19 Jun 2023 16:38:29 +0800 -Subject: [PATCH 26/28] Fix host architecture macro of LoongArch to - HOST_LOONGARCH64 - -Signed-off-by: Tianrui Zhao ---- - accel/kvm/kvm-all.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 48034d427..6d63f0ab0 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -2503,7 +2503,7 @@ static int kvm_init(MachineState *ms) - soft_vcpus_limit = kvm_recommended_vcpus(s); - hard_vcpus_limit = kvm_max_vcpus(s); - --#if defined(HOST_PPC64) || defined(HOST_LOONGARCH) -+#if defined(HOST_PPC64) || defined(HOST_LOONGARCH64) - /* - * On POWER, the kernel advertises a soft limit based on the - * number of CPU threads on the host. We want to allow exceeding --- -2.43.5 - diff --git a/Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch b/Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch deleted file mode 100644 index 09a842dac43c86903cdcbb1ceb96bd64b4d8f3a0..0000000000000000000000000000000000000000 --- a/Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch +++ /dev/null @@ -1,31 +0,0 @@ -From d24d2e0d530e6354d4f9a4b213983779136f4ab7 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:38:26 -0400 -Subject: [PATCH 16/28] Fix irq routing and fpu option to compat with kernel - v6.4 - -Fix set irq routing and enable fpu for kvm to compat -with kernel v6.4 - -Signed-off-by: lixianglai ---- - target/loongarch64/kvm.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -index 6885ec6c9..b6711da91 100644 ---- a/target/loongarch64/kvm.c -+++ b/target/loongarch64/kvm.c -@@ -107,6 +107,9 @@ int kvm_arch_init_vcpu(CPUState *cs) - CPULOONGARCHState *env = &cpu->env; - int ret = 0; - -+ kvm_vcpu_enable_cap(cs, KVM_CAP_LOONGARCH_FPU, 0, 0); -+ kvm_vcpu_enable_cap(cs, KVM_CAP_LOONGARCH_LSX, 0, 0); -+ - cpu->cpuStateEntry = qemu_add_vm_change_state_handler(kvm_loongarch_update_state, cs); - cpu->kvm_csr_buf = g_malloc0(CSR_BUF_SIZE + CSR_BUF_SIZE); - --- -2.43.5 - diff --git a/Fix-smp.cores-value.patch b/Fix-smp.cores-value.patch deleted file mode 100644 index 9517ef98fa9162771e6f9f19e860abbdbc901078..0000000000000000000000000000000000000000 --- a/Fix-smp.cores-value.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 902dc77676bc6ada74ddbdb57d00821435550bdb Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:55:12 -0400 -Subject: [PATCH 21/28] Fix smp.cores value - -The smp.cores should use the default value passed from -qemu start command, and the argument is cores_per_socket. - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index b1501e0ea..8fc79546d 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -1211,14 +1211,7 @@ static void loongarch_build_smbios(LoongarchMachineState *lsms) - uint8_t *smbios_tables, *smbios_anchor; - size_t smbios_tables_len, smbios_anchor_len; - const char *product = "QEMU Virtual Machine"; -- int nb_numa_nodes, smp_cpus; - -- smp_cpus = ms->smp.cpus; -- nb_numa_nodes = ms->numa_state->num_nodes; -- if (nb_numa_nodes == 0) { -- nb_numa_nodes = 1; -- } -- ms->smp.cores = smp_cpus / nb_numa_nodes; - if (!lsms->fw_cfg) { - return; - } --- -2.43.5 - diff --git a/Fixed-the-issue-where-qemu-specifies-the-boot-order.patch b/Fixed-the-issue-where-qemu-specifies-the-boot-order.patch deleted file mode 100644 index b86a98133830e68a54eeb3a0ded6483927c59b1f..0000000000000000000000000000000000000000 --- a/Fixed-the-issue-where-qemu-specifies-the-boot-order.patch +++ /dev/null @@ -1,140 +0,0 @@ -From d280c3a4a6ea0b3b9bf03bd4d4bd36b7e763287e Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Wed, 23 Aug 2023 07:10:25 -0400 -Subject: [PATCH 28/28] Fixed the issue where qemu specifies the boot order - -Fixed the issue that the device path of bootorder -in the generated fw_cfg was abnormal because the -PCIeHost device did not initialize the memory space -of sysbus, which caused the QEMU boot order to not -take effect. - -Change-Id: Ifde4c8b8432c5c8748c1b38a3c33bafef4f24083 -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 14 -------------- - hw/loongarch/ls7a_nb.c | 28 ++++++++++++++++++++++++++-- - include/hw/loongarch/larch.h | 6 ++++++ - include/hw/loongarch/ls7a.h | 2 ++ - 4 files changed, 34 insertions(+), 16 deletions(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 2affc5048..1a4e982b7 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -86,12 +86,6 @@ - - #define TARGET_REALPAGE_MASK (TARGET_PAGE_MASK << 2) - --#ifdef CONFIG_KVM --#define LS_ISA_IO_SIZE 0x02000000 --#else --#define LS_ISA_IO_SIZE 0x00010000 --#endif -- - #ifdef CONFIG_KVM - #define align(x) (((x) + 63) & ~63) - #else -@@ -1618,8 +1612,6 @@ static void ls3a5k_init(MachineState *args) - ram_addr_t ram_size = args->ram_size; - MemoryRegion *address_space_mem = get_system_memory(); - ram_addr_t offset = 0; -- MemoryRegion *isa_io = g_new(MemoryRegion, 1); -- MemoryRegion *isa_mem = g_new(MemoryRegion, 1); - MachineState *machine = args; - MachineClass *mc = MACHINE_GET_CLASS(machine); - LoongarchMachineState *lsms = LoongarchMACHINE(machine); -@@ -1799,12 +1791,6 @@ static void ls3a5k_init(MachineState *args) - &machine->device_memory->mr); - } - -- memory_region_init_alias(isa_io, NULL, "isa-io", -- get_system_io(), 0, LS_ISA_IO_SIZE); -- memory_region_init(isa_mem, NULL, "isa-mem", PCIE_MEMORY_SIZE); -- memory_region_add_subregion(get_system_memory(), lsmc->isa_io_base, isa_io); -- memory_region_add_subregion(get_system_memory(), PCIE_MEMORY_BASE, isa_mem); -- - if (!strcmp(lsmc->bridge_name, "ls7a")) { - /*Initialize the 7A IO interrupt subsystem*/ - DeviceState *ls7a_dev; -diff --git a/hw/loongarch/ls7a_nb.c b/hw/loongarch/ls7a_nb.c -index 5a231e6f0..f11b855a7 100644 ---- a/hw/loongarch/ls7a_nb.c -+++ b/hw/loongarch/ls7a_nb.c -@@ -162,17 +162,41 @@ static PCIBus *pci_ls7a_init(MachineState *machine, DeviceState *dev, - { - LoongarchMachineState *lsms = LoongarchMACHINE(machine); - LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ LS7APCIEHost *pciehost = LS7A_PCIE_HOST_BRIDGE(dev); - PCIExpressHost *e; -+ SysBusDevice *sysbus; - PCIHostState *phb; -+ MemoryRegion *mmio_alias; - - e = PCIE_HOST_BRIDGE(dev); -+ sysbus = SYS_BUS_DEVICE(e); - phb = PCI_HOST_BRIDGE(e); -+ -+ sysbus_init_mmio(sysbus, &e->mmio); -+ -+ memory_region_init(&pciehost->io_mmio, OBJECT(pciehost), -+ "pciehost-mmio", UINT64_MAX); -+ sysbus_init_mmio(sysbus, &pciehost->io_mmio); -+ mmio_alias = g_new0(MemoryRegion, 1); -+ memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", -+ &pciehost->io_mmio, PCIE_MEMORY_BASE, -+ PCIE_MEMORY_SIZE); -+ memory_region_add_subregion(get_system_memory(), -+ PCIE_MEMORY_BASE, mmio_alias); -+ -+ memory_region_init(&pciehost->io_ioport, OBJECT(pciehost), -+ "pciehost-ioport", LS_ISA_IO_SIZE); -+ sysbus_init_mmio(sysbus, &pciehost->io_ioport); -+ -+ sysbus_mmio_map(sysbus, 2, LS3A5K_ISA_IO_BASE); -+ -+ - phb->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq, - pci_ls7a_map_irq, pic, -- get_system_memory(), get_system_io(), -+ &pciehost->io_mmio, &pciehost->io_ioport, - (1 << 3), 128, TYPE_PCIE_BUS); -+ /*update pcie config memory*/ - pcie_host_mmcfg_update(e, true, lsmc->pciecfg_base, LS_PCIECFG_SIZE); -- DPRINTF("------ %d\n", __LINE__); - - pci_bus_set_route_irq_fn(phb->bus, ls7a_route_intx_pin_to_irq); - -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -index b8f28e330..3f4fdd946 100644 ---- a/include/hw/loongarch/larch.h -+++ b/include/hw/loongarch/larch.h -@@ -40,6 +40,12 @@ - #define LOONGARCH_HOTPLUG_MEM_ALIGN (1ULL << 28) - #define LOONGARCH_MAX_RAM_SLOTS 10 - -+#ifdef CONFIG_KVM -+#define LS_ISA_IO_SIZE 0x02000000 -+#else -+#define LS_ISA_IO_SIZE 0x00010000 -+#endif -+ - /* Memory types: */ - #define SYSTEM_RAM 1 - #define SYSTEM_RAM_RESERVED 2 -diff --git a/include/hw/loongarch/ls7a.h b/include/hw/loongarch/ls7a.h -index 63a070296..05edee603 100644 ---- a/include/hw/loongarch/ls7a.h -+++ b/include/hw/loongarch/ls7a.h -@@ -121,6 +121,8 @@ - typedef struct LS7APCIState LS7APCIState; - typedef struct LS7APCIEHost { - PCIExpressHost parent_obj; -+ MemoryRegion io_ioport; -+ MemoryRegion io_mmio; - LS7APCIState *pci_dev; - } LS7APCIEHost; - --- -2.43.5 - diff --git a/Modify-smbios-option-lack-and-Modify-the-maximum-num.patch b/Modify-smbios-option-lack-and-Modify-the-maximum-num.patch deleted file mode 100644 index 10eb346c3ad1ba8ddcee365d2090a0ba1578f1c9..0000000000000000000000000000000000000000 --- a/Modify-smbios-option-lack-and-Modify-the-maximum-num.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 3839b5ecff1bb68ed03e0cb901acfd331668d4fd Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 05:48:46 -0400 -Subject: [PATCH 10/28] Modify smbios option lack and Modify the maximum number - of CPUs supported by the virtual machine. - -Add smbios option support for loongarch. -The number of virtual CPUs can be greater than the number of CPUs of the host machine. - -Signed-off-by: lixianglai ---- - accel/kvm/kvm-all.c | 2 +- - qemu-options.hx | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 3b7bc3982..48034d427 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -2503,7 +2503,7 @@ static int kvm_init(MachineState *ms) - soft_vcpus_limit = kvm_recommended_vcpus(s); - hard_vcpus_limit = kvm_max_vcpus(s); - --#ifdef HOST_PPC64 -+#if defined(HOST_PPC64) || defined(HOST_LOONGARCH) - /* - * On POWER, the kernel advertises a soft limit based on the - * number of CPU threads on the host. We want to allow exceeding -diff --git a/qemu-options.hx b/qemu-options.hx -index 981248e28..1b3f2df49 100644 ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -2480,7 +2480,7 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, - " specify SMBIOS type 17 fields\n" - "-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]\n" - " specify SMBIOS type 41 fields\n", -- QEMU_ARCH_I386 | QEMU_ARCH_ARM) -+ QEMU_ARCH_I386 | QEMU_ARCH_ARM | QEMU_ARCH_LOONGARCH64) - SRST - ``-smbios file=binary`` - Load SMBIOS entry from binary file. --- -2.43.5 - diff --git a/Modify-the-ioctl-command-of-kvm.patch b/Modify-the-ioctl-command-of-kvm.patch deleted file mode 100644 index 6b41fb1c89dcc2d8dc65fea11e6fd3eea1fcb013..0000000000000000000000000000000000000000 --- a/Modify-the-ioctl-command-of-kvm.patch +++ /dev/null @@ -1,32 +0,0 @@ -From c593589f83c7655dcd8b9c144bf6061933d4ed40 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 08:44:26 -0400 -Subject: [PATCH 23/28] Modify the ioctl command of kvm. - -Signed-off-by: lixianglai ---- - linux-headers/linux/kvm.h | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 0e50d3749..f5589b068 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -2126,10 +2126,10 @@ struct kvm_loongarch_vcpu_state { - __u64 core_ext_ioisr[4]; - }; - --#define KVM_CAP_LOONGARCH_FPU 165 --#define KVM_CAP_LOONGARCH_LSX 166 --#define KVM_CAP_LOONGARCH_VZ 167 --#define KVM_REG_LOONGARCH 0x8000000000000000ULL -+#define KVM_CAP_LOONGARCH_FPU 800 -+#define KVM_CAP_LOONGARCH_LSX 801 -+#define KVM_CAP_LOONGARCH_VZ 802 -+#define KVM_REG_LOONGARCH 0x9000000000000000ULL - #define KVM_LARCH_GET_VCPU_STATE _IOR(KVMIO, 0xc0, struct kvm_loongarch_vcpu_state) - #define KVM_LARCH_SET_VCPU_STATE _IOW(KVMIO, 0xc1, struct kvm_loongarch_vcpu_state) - #define KVM_LARCH_GET_CPUCFG _IOR(KVMIO, 0xc2, struct kvm_cpucfg) --- -2.43.5 - diff --git a/Support-TPM.patch b/Support-TPM.patch deleted file mode 100644 index 8bfa5304ed8003784a95626aefcdde9c9555e82f..0000000000000000000000000000000000000000 --- a/Support-TPM.patch +++ /dev/null @@ -1,518 +0,0 @@ -From 8eea4ea57942c83f0e1d9d4073004409505fda59 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:16:34 -0400 -Subject: [PATCH 13/28] Support TPM. - -Signed-off-by: lixianglai ---- - hw/loongarch/acpi-build.c | 44 +++++++ - hw/loongarch/larch_3a.c | 53 ++++++++- - hw/loongarch/larch_hotplug.c | 16 ++- - hw/loongarch/meson.build | 1 + - hw/loongarch/sysbus-fdt.c | 183 ++++++++++++++++++++++++++++++ - include/hw/loongarch/larch.h | 1 + - include/hw/loongarch/ls7a.h | 5 + - include/hw/loongarch/sysbus-fdt.h | 37 ++++++ - 8 files changed, 333 insertions(+), 7 deletions(-) - create mode 100644 hw/loongarch/sysbus-fdt.c - create mode 100644 include/hw/loongarch/sysbus-fdt.h - -diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c -index 6ba637be5..682e016be 100644 ---- a/hw/loongarch/acpi-build.c -+++ b/hw/loongarch/acpi-build.c -@@ -58,6 +58,7 @@ - #include "hw/acpi/aml-build.h" - #include "hw/loongarch/larch.h" - #include "hw/loongarch/ls7a.h" -+#include "hw/platform-bus.h" - - #include "hw/acpi/ipmi.h" - #include "hw/acpi/ls7a.h" -@@ -474,7 +475,40 @@ static void build_ls7a_uart_device_aml(Aml *table) - aml_append(scope, dev); - aml_append(table, scope); - } -+#ifdef CONFIG_TPM -+static void acpi_dsdt_add_tpm(Aml *scope, LoongarchMachineState *vms) -+{ -+ PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); -+ hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS; -+ SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find()); -+ MemoryRegion *sbdev_mr; -+ hwaddr tpm_base; -+ -+ if (!sbdev) { -+ return; -+ } -+ -+ tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); -+ assert(tpm_base != -1); - -+ tpm_base += pbus_base; -+ -+ sbdev_mr = sysbus_mmio_get_region(sbdev, 0); -+ -+ Aml *dev = aml_device("TPM0"); -+ aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); -+ aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device"))); -+ aml_append(dev, aml_name_decl("_UID", aml_int(0))); -+ -+ Aml *crs = aml_resource_template(); -+ aml_append(crs, -+ aml_memory32_fixed(tpm_base, -+ (uint32_t)memory_region_size(sbdev_mr), -+ AML_READ_WRITE)); -+ aml_append(dev, aml_name_decl("_CRS", crs)); -+ aml_append(scope, dev); -+} -+#endif - static void - build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) - { -@@ -500,6 +534,10 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) - aml_append(dev, aml_name_decl("_UID", aml_int(1))); - aml_append(dev, build_ls7a_osc_method()); - aml_append(sb_scope, dev); -+ -+#ifdef CONFIG_TPM -+ acpi_dsdt_add_tpm(sb_scope, lsms); -+#endif - aml_append(dsdt, sb_scope); - - build_ls7a_pci0_int(dsdt); -@@ -633,6 +671,12 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) - lsms->oem_table_id); - } - -+ if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) { -+ acpi_add_table(table_offsets, tables_blob); -+ build_tpm2(tables_blob, tables->linker, tables->tcpalog, -+ lsms->oem_id, lsms->oem_table_id); -+ } -+ - /* Build mcfg */ - acpi_add_table(table_offsets, tables_blob); - { -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 3194a822c..6c2602050 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -52,6 +52,7 @@ - #include "hw/rtc/mc146818rtc.h" - #include "hw/irq.h" - #include "net/net.h" -+#include "hw/platform-bus.h" - #include "hw/timer/i8254.h" - #include "hw/loongarch/larch.h" - #include "hw/loongarch/ls7a.h" -@@ -65,6 +66,8 @@ - #include "sysemu/device_tree.h" - #include "qapi/visitor.h" - #include "qapi/qapi-visit-common.h" -+#include "sysemu/tpm.h" -+#include "hw/loongarch/sysbus-fdt.h" - - #include - -@@ -1235,6 +1238,19 @@ void loongarch_machine_done(Notifier *notifier, void *data) - { - LoongarchMachineState *lsms = container_of(notifier, - LoongarchMachineState, machine_done); -+ -+ platform_bus_add_all_fdt_nodes(lsms->fdt, NULL, -+ VIRT_PLATFORM_BUS_BASEADDRESS, -+ VIRT_PLATFORM_BUS_SIZE, -+ VIRT_PLATFORM_BUS_IRQ); -+ -+ qemu_fdt_dumpdtb(lsms->fdt, lsms->fdt_size); -+ /* load fdt */ -+ MemoryRegion *fdt_rom = g_new(MemoryRegion, 1); -+ memory_region_init_rom(fdt_rom, NULL, "fdt", LS_FDT_SIZE, &error_fatal); -+ memory_region_add_subregion(get_system_memory(), LS_FDT_BASE, fdt_rom); -+ rom_add_blob_fixed("fdt", lsms->fdt, lsms->fdt_size, LS_FDT_BASE); -+ - loongarch_acpi_setup(); - loongarch_build_smbios(lsms); - } -@@ -1562,7 +1578,31 @@ static void fdt_add_pcie_node(const LoongarchMachineState *lsms) - 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, - 2, base_mmio, 2, size_mmio); - g_free(nodename); -- qemu_fdt_dumpdtb(lsms->fdt, lsms->fdt_size); -+} -+ -+static void create_platform_bus(LoongarchMachineState *s, qemu_irq *pic) -+{ -+ DeviceState *dev; -+ SysBusDevice *sysbus; -+ int i; -+ MemoryRegion *sysmem = get_system_memory(); -+ -+ dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); -+ dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); -+ qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS); -+ qdev_prop_set_uint32(dev, "mmio_size", VIRT_PLATFORM_BUS_SIZE); -+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); -+ s->platform_bus_dev = dev; -+ -+ sysbus = SYS_BUS_DEVICE(dev); -+ for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) { -+ int irq = VIRT_PLATFORM_BUS_IRQ + i; -+ sysbus_connect_irq(sysbus, i, pic[irq - LOONGARCH_PCH_IRQ_BASE]); -+ } -+ -+ memory_region_add_subregion(sysmem, -+ VIRT_PLATFORM_BUS_BASEADDRESS, -+ sysbus_mmio_get_region(sysbus, 0)); - } - - static void ls3a5k_init(MachineState *args) -@@ -1784,6 +1824,8 @@ static void ls3a5k_init(MachineState *args) - object_property_set_link(OBJECT(machine), LOONGARCH_MACHINE_ACPI_DEVICE_PROP, - OBJECT(ls7a_dev), &error_abort); - -+ create_platform_bus(lsms, ls7a_apic); -+ - #ifdef CONFIG_KVM - if (kvm_enabled()) { - kvm_direct_msi_allowed = (kvm_check_extension(kvm_state, -@@ -1835,11 +1877,6 @@ static void ls3a5k_init(MachineState *args) - - fdt_add_pcie_node(lsms); - -- /* load fdt */ -- MemoryRegion *fdt_rom = g_new(MemoryRegion, 1); -- memory_region_init_rom(fdt_rom, NULL, "fdt", LS_FDT_SIZE, &error_fatal); -- memory_region_add_subregion(get_system_memory(), LS_FDT_BASE, fdt_rom); -- rom_add_blob_fixed("fdt", lsms->fdt, lsms->fdt_size, LS_FDT_BASE); - } - - static const CPUArchIdList *loongarch_possible_cpu_arch_ids(MachineState *ms) -@@ -1986,6 +2023,10 @@ static void loongarch_class_init(ObjectClass *oc, void *data) - mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000"); - mc->default_ram_id = "loongarch_ls3a.ram"; - -+#ifdef CONFIG_TPM -+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); -+#endif -+ - mc->reset = ls3a_board_reset; - mc->max_cpus = LOONGARCH_MAX_VCPUS; - hc->pre_plug = loongarch_machine_device_pre_plug; -diff --git a/hw/loongarch/larch_hotplug.c b/hw/loongarch/larch_hotplug.c -index 7bce95712..bb3e9826b 100644 ---- a/hw/loongarch/larch_hotplug.c -+++ b/hw/loongarch/larch_hotplug.c -@@ -32,6 +32,7 @@ - #include "hw/loongarch/larch.h" - #include "hw/cpu/core.h" - #include "hw/nvram/fw_cfg.h" -+#include "hw/platform-bus.h" - - /* find cpu slot in machine->possible_cpus by core_id */ - static CPUArchId *loongarch_find_cpu_slot(MachineState *ms, uint32_t id, -@@ -327,7 +328,8 @@ HotplugHandler *loongarch_get_hotpug_handler(MachineState *machine, - DeviceState *dev) - { - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || -- object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -+ object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU) || -+ object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)) { - return HOTPLUG_HANDLER(machine); - } - return NULL; -@@ -346,6 +348,18 @@ void loongarch_machine_device_pre_plug(HotplugHandler *hotplug_dev, - void loongarch_machine_device_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) - { -+ LoongarchMachineState *lsms = LoongarchMACHINE(hotplug_dev); -+ -+ if (lsms->platform_bus_dev) { -+ MachineClass *mc = MACHINE_GET_CLASS(lsms); -+ -+ if (device_is_dynamic_sysbus(mc, dev)) { -+ platform_bus_link_device( -+ PLATFORM_BUS_DEVICE(lsms->platform_bus_dev), -+ SYS_BUS_DEVICE(dev)); -+ } -+ } -+ - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - loongarch_memory_plug(hotplug_dev, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { -diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build -index 81ee99a02..47d886ddd 100644 ---- a/hw/loongarch/meson.build -+++ b/hw/loongarch/meson.build -@@ -9,6 +9,7 @@ loongarch_ss.add(files( - 'ipi.c', - 'apic.c', - 'iocsr.c', -+ 'sysbus-fdt.c', - )) - - hw_arch += {'loongarch64': loongarch_ss} -diff --git a/hw/loongarch/sysbus-fdt.c b/hw/loongarch/sysbus-fdt.c -new file mode 100644 -index 000000000..f750ad6b6 ---- /dev/null -+++ b/hw/loongarch/sysbus-fdt.c -@@ -0,0 +1,183 @@ -+/* -+ * Loongarch Platform Bus device tree generation helpers -+ * -+ * Copyright (c) 2014 Linaro Limited -+ * -+ * Authors: -+ * Alex Graf -+ * Eric Auger -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program. If not, see . -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include -+#include "qemu/error-report.h" -+#include "sysemu/device_tree.h" -+#include "hw/platform-bus.h" -+#include "hw/display/ramfb.h" -+#include "hw/loongarch/sysbus-fdt.h" -+#include "sysemu/tpm.h" -+ -+/* -+ * internal struct that contains the information to create dynamic -+ * sysbus device node -+ */ -+typedef struct PlatformBusFDTData { -+ void *fdt; /* device tree handle */ -+ int irq_start; /* index of the first IRQ usable by platform bus devices */ -+ const char *pbus_node_name; /* name of the platform bus node */ -+ PlatformBusDevice *pbus; -+} PlatformBusFDTData; -+ -+/* struct that allows to match a device and create its FDT node */ -+typedef struct BindingEntry { -+ const char *typename; -+ const char *compat; -+ int (*add_fn)(SysBusDevice *sbdev, void *opaque); -+ bool (*match_fn)(SysBusDevice *sbdev, const struct BindingEntry *combo); -+} BindingEntry; -+ -+ -+ -+static int no_fdt_node(SysBusDevice *sbdev, void *opaque) -+{ -+ return 0; -+} -+ -+/* Device type based matching */ -+static bool type_match(SysBusDevice *sbdev, const BindingEntry *entry) -+{ -+ return !strcmp(object_get_typename(OBJECT(sbdev)), entry->typename); -+} -+ -+#define TYPE_BINDING(type, add_fn) {(type), NULL, (add_fn), NULL} -+ -+#ifdef CONFIG_TPM -+/* -+ * add_tpm_tis_fdt_node: Create a DT node for TPM TIS -+ * -+ * See kernel documentation: -+ * Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt -+ * Optional interrupt for command completion is not exposed -+ */ -+static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque) -+{ -+ PlatformBusFDTData *data = opaque; -+ PlatformBusDevice *pbus = data->pbus; -+ void *fdt = data->fdt; -+ const char *parent_node = data->pbus_node_name; -+ char *nodename; -+ uint32_t reg_attr[2]; -+ uint64_t mmio_base; -+ -+ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); -+ nodename = g_strdup_printf("%s/tpm_tis@%" PRIx64, parent_node, mmio_base); -+ qemu_fdt_add_subnode(fdt, nodename); -+ -+ qemu_fdt_setprop_string(fdt, nodename, "compatible", "tcg,tpm-tis-mmio"); -+ -+ reg_attr[0] = cpu_to_be32(mmio_base); -+ reg_attr[1] = cpu_to_be32(0x5000); -+ qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, 2 * sizeof(uint32_t)); -+ -+ g_free(nodename); -+ -+ return 0; -+} -+#endif -+ -+/* list of supported dynamic sysbus bindings */ -+static const BindingEntry bindings[] = { -+#ifdef CONFIG_TPM -+ TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node), -+#endif -+ TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node), -+ TYPE_BINDING("", NULL), /* last element */ -+}; -+ -+/* Generic Code */ -+ -+/** -+ * add_fdt_node - add the device tree node of a dynamic sysbus device -+ * -+ * @sbdev: handle to the sysbus device -+ * @opaque: handle to the PlatformBusFDTData -+ * -+ * Checks the sysbus type belongs to the list of device types that -+ * are dynamically instantiable and if so call the node creation -+ * function. -+ */ -+static void add_fdt_node(SysBusDevice *sbdev, void *opaque) -+{ -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(bindings); i++) { -+ const BindingEntry *iter = &bindings[i]; -+ -+ if (type_match(sbdev, iter)) { -+ if (!iter->match_fn || iter->match_fn(sbdev, iter)) { -+ ret = iter->add_fn(sbdev, opaque); -+ assert(!ret); -+ return; -+ } -+ } -+ } -+ error_report("Device %s can not be dynamically instantiated", -+ qdev_fw_name(DEVICE(sbdev))); -+ exit(1); -+} -+ -+void platform_bus_add_all_fdt_nodes(void *fdt, const char *intc, hwaddr addr, -+ hwaddr bus_size, int irq_start) -+{ -+ const char platcomp[] = "qemu,platform\0simple-bus"; -+ PlatformBusDevice *pbus; -+ DeviceState *dev; -+ gchar *node; -+ -+ assert(fdt); -+ -+ node = g_strdup_printf("/platform@%"PRIx64, addr); -+ -+ /* Create a /platform node that we can put all devices into */ -+ qemu_fdt_add_subnode(fdt, node); -+ qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); -+ -+ /* -+ * Our platform bus region is less than 32bits, so 1 cell is enough for -+ * address and size -+ */ -+ qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); -+ qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); -+ qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, bus_size); -+ if (intc != NULL) { -+ qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", intc); -+ } -+ dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE); -+ pbus = PLATFORM_BUS_DEVICE(dev); -+ -+ PlatformBusFDTData data = { -+ .fdt = fdt, -+ .irq_start = irq_start, -+ .pbus_node_name = node, -+ .pbus = pbus, -+ }; -+ -+ /* Loop through all dynamic sysbus devices and create their node */ -+ foreach_dynamic_sysbus_device(add_fdt_node, &data); -+ -+ g_free(node); -+} -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -index 62e2830e2..81dcb78f4 100644 ---- a/include/hw/loongarch/larch.h -+++ b/include/hw/loongarch/larch.h -@@ -103,6 +103,7 @@ typedef struct LoongarchMachineState { - void *fdt; - int fdt_size; - unsigned int hotpluged_cpu_num; -+ DeviceState *platform_bus_dev; - OnOffAuto acpi; - char *oem_id; - char *oem_table_id; -diff --git a/include/hw/loongarch/ls7a.h b/include/hw/loongarch/ls7a.h -index 686af763a..fc78083be 100644 ---- a/include/hw/loongarch/ls7a.h -+++ b/include/hw/loongarch/ls7a.h -@@ -121,6 +121,11 @@ - #define INT_ROUTER_REGS_CORE2_INTISR 0x50 - #define INT_ROUTER_REGS_CORE3_INTISR 0x58 - -+#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 -+#define VIRT_PLATFORM_BUS_SIZE 0x2000000 -+#define VIRT_PLATFORM_BUS_NUM_IRQS 2 -+#define VIRT_PLATFORM_BUS_IRQ 69 -+ - typedef struct LS7APCIState LS7APCIState; - typedef struct LS7APCIEHost { - PCIExpressHost parent_obj; -diff --git a/include/hw/loongarch/sysbus-fdt.h b/include/hw/loongarch/sysbus-fdt.h -new file mode 100644 -index 000000000..340c382cd ---- /dev/null -+++ b/include/hw/loongarch/sysbus-fdt.h -@@ -0,0 +1,37 @@ -+/* -+ * Dynamic sysbus device tree node generation API -+ * -+ * Copyright Linaro Limited, 2014 -+ * -+ * Authors: -+ * Alex Graf -+ * Eric Auger -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2 or later, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program. If not, see . -+ * -+ */ -+ -+#ifndef HW_ARM_SYSBUS_FDT_H -+#define HW_ARM_SYSBUS_FDT_H -+ -+#include "exec/hwaddr.h" -+ -+/** -+ * platform_bus_add_all_fdt_nodes - create all the platform bus nodes -+ * -+ * builds the parent platform bus node and all the nodes of dynamic -+ * sysbus devices attached to it. -+ */ -+void platform_bus_add_all_fdt_nodes(void *fdt, const char *intc, hwaddr addr, -+ hwaddr bus_size, int irq_start); -+#endif --- -2.43.5 - diff --git a/Support-vfio-config.patch b/Support-vfio-config.patch deleted file mode 100644 index 01b2bb6b27835903a107675f9053112f17cc0cf5..0000000000000000000000000000000000000000 --- a/Support-vfio-config.patch +++ /dev/null @@ -1,47 +0,0 @@ -From e2e67dd2c2b0c3ff2737cd477bfc79cac64d4053 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:41:14 -0400 -Subject: [PATCH 17/28] Support vfio config - -Signed-off-by: lixianglai ---- - configs/devices/loongarch64-softmmu/default.mak | 9 +++++++++ - .../loongarch64-softmmu/loongarch64-rh-devices.mak | 8 ++++++++ - 2 files changed, 17 insertions(+) - -diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak -index fcb7e45dd..b4994d8a6 100644 ---- a/configs/devices/loongarch64-softmmu/default.mak -+++ b/configs/devices/loongarch64-softmmu/default.mak -@@ -152,3 +152,12 @@ CONFIG_PLATFORM_BUS=y - CONFIG_TPM_TIS_SYSBUS=y - CONFIG_ACPI_LOONGARCH=y - CONFIG_LS7A_RTC=y -+ -+#vfio config -+CONFIG_VFIO=y -+CONFIG_VFIO_PCI=y -+CONFIG_VFIO_PLATFORM=y -+CONFIG_VFIO_XGMAC=y -+CONFIG_VFIO_AMD_XGBE=y -+ -+ -diff --git a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -index e7b5bdc8e..696ee9b72 100644 ---- a/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -+++ b/configs/devices/loongarch64-softmmu/loongarch64-rh-devices.mak -@@ -153,3 +153,11 @@ CONFIG_PLATFORM_BUS=y - CONFIG_TPM_TIS_SYSBUS=y - CONFIG_ACPI_LOONGARCH=y - CONFIG_LS7A_RTC=y -+ -+#vfio config -+CONFIG_VFIO=y -+CONFIG_VFIO_PCI=y -+CONFIG_VFIO_PLATFORM=y -+CONFIG_VFIO_XGMAC=y -+CONFIG_VFIO_AMD_XGBE=y -+ --- -2.43.5 - diff --git a/address-space-code-cleanup-on-7A-virt-machine.patch b/address-space-code-cleanup-on-7A-virt-machine.patch deleted file mode 100644 index 61c4d7882e4b81657b03c47a0d4a6fd855421748..0000000000000000000000000000000000000000 --- a/address-space-code-cleanup-on-7A-virt-machine.patch +++ /dev/null @@ -1,276 +0,0 @@ -From 731b161d2cfddb67e4088282a33acaf90c2bd928 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:33:26 -0400 -Subject: [PATCH 15/28] address space code cleanup on 7A virt-machine. - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 16 +++----- - hw/loongarch/ls7a_nb.c | 49 ------------------------- - include/hw/loongarch/larch.h | 1 - - include/hw/loongarch/ls7a.h | 71 ++++++++++++++++-------------------- - 4 files changed, 37 insertions(+), 100 deletions(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 6c2602050..6eaa53d74 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -88,10 +88,8 @@ - - #ifdef CONFIG_KVM - #define LS_ISA_IO_SIZE 0x02000000 --#define LS_ISA_MEM_SIZE 0x40000000 - #else - #define LS_ISA_IO_SIZE 0x00010000 --#define LS_ISA_MEM_SIZE 0x01000000 - #endif - - #ifdef CONFIG_KVM -@@ -626,8 +624,8 @@ static struct irq_source_routing_table *init_irq_source(void *g_irq_source) - irq_info->ht_enable = 0x0000d17b; - irq_info->node_id = 0; - -- irq_info->pci_mem_start_addr = LS_ISA_MEM_BASE; -- irq_info->pci_mem_end_addr = irq_info->pci_mem_start_addr + LS_ISA_MEM_SIZE - 1; -+ irq_info->pci_mem_start_addr = PCIE_MEMORY_BASE; -+ irq_info->pci_mem_end_addr = irq_info->pci_mem_start_addr + PCIE_MEMORY_SIZE - 1; - - if (strstr(lsmc->cpu_name, "5000")) { - irq_info->pci_io_start_addr = LS3A5K_ISA_IO_BASE; -@@ -1551,8 +1549,8 @@ static void fdt_add_fw_cfg_node(const LoongarchMachineState *lsms) - static void fdt_add_pcie_node(const LoongarchMachineState *lsms) - { - char *nodename; -- hwaddr base_mmio = LS_ISA_MEM_BASE; -- hwaddr size_mmio = LS_ISA_MEM_SIZE; -+ hwaddr base_mmio = PCIE_MEMORY_BASE; -+ hwaddr size_mmio = PCIE_MEMORY_SIZE; - hwaddr base_pio = LS3A5K_ISA_IO_BASE; - hwaddr size_pio = LS_ISA_IO_SIZE; - hwaddr base_pcie = LS_PCIECFG_BASE; -@@ -1650,7 +1648,6 @@ static void ls3a5k_init(MachineState *args) - create_fdt(lsms); - - DPRINTF("isa 0x%lx\n", lsmc->isa_io_base); -- DPRINTF("ht1lo 0x%lx\n", lsmc->ht1lo_pcicfg_base); - DPRINTF("cpu_name %s bridge_name %s\n", - lsmc->cpu_name, lsmc->bridge_name); - -@@ -1800,9 +1797,9 @@ static void ls3a5k_init(MachineState *args) - - memory_region_init_alias(isa_io, NULL, "isa-io", - get_system_io(), 0, LS_ISA_IO_SIZE); -- memory_region_init(isa_mem, NULL, "isa-mem", LS_ISA_MEM_SIZE); -+ memory_region_init(isa_mem, NULL, "isa-mem", PCIE_MEMORY_SIZE); - memory_region_add_subregion(get_system_memory(), lsmc->isa_io_base, isa_io); -- memory_region_add_subregion(get_system_memory(), LS_ISA_MEM_BASE, isa_mem); -+ memory_region_add_subregion(get_system_memory(), PCIE_MEMORY_BASE, isa_mem); - - if (!strcmp(lsmc->bridge_name, "ls7a")) { - /*Initialize the 7A IO interrupt subsystem*/ -@@ -1950,7 +1947,6 @@ static void ls3a5k_ls7a_machine_options(MachineClass *m) - m->alias = "loongson7a"; - m->is_default = 1; - lsmc->isa_io_base = LS3A5K_ISA_IO_BASE; -- lsmc->ht1lo_pcicfg_base = LS3A5K_HT1LO_PCICFG_BASE; - lsmc->pciecfg_base = LS_PCIECFG_BASE; - lsmc->ls7a_ioapic_reg_base = LS3A5K_LS7A_IOAPIC_REG_BASE; - lsmc->node_shift = 44; -diff --git a/hw/loongarch/ls7a_nb.c b/hw/loongarch/ls7a_nb.c -index 5a500fbd5..5a231e6f0 100644 ---- a/hw/loongarch/ls7a_nb.c -+++ b/hw/loongarch/ls7a_nb.c -@@ -108,7 +108,6 @@ static const VMStateDescription vmstate_ls7a_pcie = { - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, LS7APCIState), - VMSTATE_STRUCT(pm, LS7APCIState, 0, vmstate_ls7a_pm, LS7APCIPMRegs), -- VMSTATE_UINT32_ARRAY(regs, LS7APCIState, LS7A_REGS), - VMSTATE_END_OF_LIST() - } - }; -@@ -153,47 +152,6 @@ static void ls7a_pcie_realize(PCIDevice *dev, Error **errp) - qemu_register_reset(ls7a_reset, s); - } - --static void pci_ls7a_config_write(void *opaque, hwaddr addr, -- uint64_t val, unsigned size) --{ -- hwaddr tmp_addr; -- tmp_addr = addr & 0xffffff; -- -- pci_data_write(opaque, tmp_addr, val, size); --} -- --static uint64_t pci_ls7a_config_read(void *opaque, -- hwaddr addr, unsigned size) --{ -- uint64_t val; -- hwaddr tmp_addr; -- -- tmp_addr = addr & 0xffffff; -- val = pci_data_read(opaque, tmp_addr, size); -- -- if (addr & 0x3c) { -- DPRINTF(TARGET_FMT_plx" val %lx\n", addr, val); -- } -- return val; --} -- --static const MemoryRegionOps pci_ls7a_config_ops = { -- .read = pci_ls7a_config_read, -- .write = pci_ls7a_config_write, -- /* Set to access 64bits data, because default to 32bits*/ -- .valid = { -- .min_access_size = 1, -- .max_access_size = 4, -- }, -- /* Set to access 64bits data, because default to 32bits*/ -- .impl = { -- .min_access_size = 1, -- .max_access_size = 4, -- }, -- .endianness = DEVICE_NATIVE_ENDIAN, -- --}; -- - static AddressSpace *ls7a_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) - { - return &address_space_memory; -@@ -205,12 +163,9 @@ static PCIBus *pci_ls7a_init(MachineState *machine, DeviceState *dev, - LoongarchMachineState *lsms = LoongarchMACHINE(machine); - LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); - PCIExpressHost *e; -- SysBusDevice *sysbus; -- MemoryRegion *iomem = g_new(MemoryRegion, 1); - PCIHostState *phb; - - e = PCIE_HOST_BRIDGE(dev); -- sysbus = SYS_BUS_DEVICE(e); - phb = PCI_HOST_BRIDGE(e); - phb->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq, - pci_ls7a_map_irq, pic, -@@ -220,10 +175,6 @@ static PCIBus *pci_ls7a_init(MachineState *machine, DeviceState *dev, - DPRINTF("------ %d\n", __LINE__); - - pci_bus_set_route_irq_fn(phb->bus, ls7a_route_intx_pin_to_irq); -- memory_region_init_io(iomem, NULL, &pci_ls7a_config_ops, phb->bus, -- "ls7a_pci_conf", HT1LO_PCICFG_SIZE); -- sysbus_init_mmio(sysbus, iomem); -- sysbus_mmio_map(sysbus, 0, lsmc->ht1lo_pcicfg_base); - - return phb->bus; - } -diff --git a/include/hw/loongarch/larch.h b/include/hw/loongarch/larch.h -index 81dcb78f4..b8f28e330 100644 ---- a/include/hw/loongarch/larch.h -+++ b/include/hw/loongarch/larch.h -@@ -64,7 +64,6 @@ typedef struct LoongarchMachineClass { - uint64_t ht_control_regs_base; - uint64_t hpet_mmio_addr; - uint64_t smbus_cfg_base; -- uint64_t ht1lo_pcicfg_base; - uint64_t pciecfg_base; - uint64_t ls7a_ioapic_reg_base; - uint32_t node_shift; -diff --git a/include/hw/loongarch/ls7a.h b/include/hw/loongarch/ls7a.h -index fc78083be..63a070296 100644 ---- a/include/hw/loongarch/ls7a.h -+++ b/include/hw/loongarch/ls7a.h -@@ -39,44 +39,33 @@ - #define ACPI_IO_SIZE (LS7A_ACPI_IO_SIZE) - #define ACPI_SCI_IRQ (LS7A_SCI_IRQ) - --#define LS3A5K_ISA_IO_BASE 0x18000000UL --#define LS_ISA_MEM_BASE 0x40000000 --#define LS3A5K_HT1LO_PCICFG_BASE 0x1a000000 --#define HT1LO_PCICFG_SIZE 0x02000000 -+#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 -+#define VIRT_PLATFORM_BUS_SIZE 0x02000000 -+#define VIRT_PLATFORM_BUS_NUM_IRQS 2 -+#define VIRT_PLATFORM_BUS_IRQ (LOONGARCH_PCH_IRQ_BASE + 5) -+ -+#define LS3A5K_ISA_IO_BASE 0x18000000UL - #define LS_BIOS_BASE 0x1c000000 - #define LS_BIOS_VAR_BASE 0x1c3a0000 --#define LS_BIOS_SIZE (4 * 1024 * 1024) -- --#define FW_CFG_ADDR 0x1e020000 --#define LS7A_REG_BASE 0x1FE00000 --#define LS7A_PCICONFIG_BASE (LS7A_REG_BASE + 0x30) --#define LS7A_PCICONFIG_SIZE (0x100) --#define LS7A_INTERNAL_REG_BASE (LS7A_REG_BASE + 0x100) --#define LS7A_INTERNAL_REG_SIZE (0xE0) --#define LS7A_REGS (0xE0 >> 2) --#define LS7A_UART_BASE 0x1fe001e0 --#define LS7A_UART_LEN 0x8 -- --#define LS_FDT_BASE 0x1c400000 --#define LS_FDT_SIZE 0x100000 -- --#define LS_PCIECFG_BASE 0x20000000 --#define LS_PCIECFG_SIZE 0x08000000 --#define MSI_ADDR_LOW 0x2FF00000 --#define MSI_ADDR_HI 0x0 -- -+#define LS_BIOS_SIZE (4 * 1024 * 1024) -+#define LS_FDT_BASE 0x1c400000 -+#define LS_FDT_SIZE 0x00100000 -+ -+#define FW_CFG_ADDR 0x1e020000 -+#define LS7A_REG_BASE 0x1FE00000 -+#define LS7A_UART_BASE 0x1fe001e0 -+#define LS7A_UART_LEN 0x8 - #define SMP_GIPI_MAILBOX 0x1f000000ULL --#define CORE0_STATUS_OFF 0x000 --#define CORE0_EN_OFF 0x004 --#define CORE0_SET_OFF 0x008 --#define CORE0_CLEAR_OFF 0x00c --#define CORE0_BUF_20 0x020 --#define CORE0_BUF_28 0x028 --#define CORE0_BUF_30 0x030 --#define CORE0_BUF_38 0x038 --#define CORE0_IPI_SEND 0x040 --#define CORE0_MAIL_SEND 0x048 -- -+#define CORE0_STATUS_OFF 0x000 -+#define CORE0_EN_OFF 0x004 -+#define CORE0_SET_OFF 0x008 -+#define CORE0_CLEAR_OFF 0x00c -+#define CORE0_BUF_20 0x020 -+#define CORE0_BUF_28 0x028 -+#define CORE0_BUF_30 0x030 -+#define CORE0_BUF_38 0x038 -+#define CORE0_IPI_SEND 0x040 -+#define CORE0_MAIL_SEND 0x048 - #define INT_ROUTER_REGS_BASE 0x1fe01400UL - #define INT_ROUTER_REGS_SIZE 0x100 - #define INT_ROUTER_REGS_SYS_INT0 0x00 -@@ -121,10 +110,13 @@ - #define INT_ROUTER_REGS_CORE2_INTISR 0x50 - #define INT_ROUTER_REGS_CORE3_INTISR 0x58 - --#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 --#define VIRT_PLATFORM_BUS_SIZE 0x2000000 --#define VIRT_PLATFORM_BUS_NUM_IRQS 2 --#define VIRT_PLATFORM_BUS_IRQ 69 -+#define LS_PCIECFG_BASE 0x20000000 -+#define LS_PCIECFG_SIZE 0x08000000 -+#define MSI_ADDR_LOW 0x2FF00000 -+#define MSI_ADDR_HI 0x0 -+ -+#define PCIE_MEMORY_BASE 0x40000000 -+#define PCIE_MEMORY_SIZE 0x40000000 - - typedef struct LS7APCIState LS7APCIState; - typedef struct LS7APCIEHost { -@@ -136,7 +128,6 @@ struct LS7APCIState { - PCIDevice dev; - - LS7APCIEHost *pciehost; -- uint32_t regs[LS7A_REGS]; - - /* LS7A registers */ - MemoryRegion iomem; --- -2.43.5 - diff --git a/code-cleanup-for-loongarch-kvm.patch b/code-cleanup-for-loongarch-kvm.patch deleted file mode 100644 index e94f6de3443f3019750b528f12b2eb02ff16be2b..0000000000000000000000000000000000000000 --- a/code-cleanup-for-loongarch-kvm.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 4bf40ba9ed6f98e7082623927d1c0c9ec6090f12 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:04:10 -0400 -Subject: [PATCH 12/28] code cleanup for loongarch kvm. - -Signed-off-by: lixianglai ---- - linux-headers/asm-loongarch64/kvm.h | 10 +--------- - 1 file changed, 1 insertion(+), 9 deletions(-) - -diff --git a/linux-headers/asm-loongarch64/kvm.h b/linux-headers/asm-loongarch64/kvm.h -index a24375ee5..799af7594 100644 ---- a/linux-headers/asm-loongarch64/kvm.h -+++ b/linux-headers/asm-loongarch64/kvm.h -@@ -72,15 +72,7 @@ struct kvm_fpu { - * - * Register set = 0: GP registers from kvm_regs (see definitions below). - * -- * Register set = 1: CP0 registers. -- * bits[15..8] - COP0 register set. -- * -- * COP0 register set = 0: Main CP0 registers. -- * bits[7..3] - Register 'rd' index. -- * bits[2..0] - Register 'sel' index. -- * -- * COP0 register set = 1: MAARs. -- * bits[7..0] - MAAR index. -+ * Register set = 1: CSR registers. - * - * Register set = 2: KVM specific registers (see definitions below). - * --- -2.43.5 - diff --git a/fix-smbios-type4-info-for-numa-support.patch b/fix-smbios-type4-info-for-numa-support.patch deleted file mode 100644 index 3e5f0fb7b9cb241b0d08bef048df7202d0a0c101..0000000000000000000000000000000000000000 --- a/fix-smbios-type4-info-for-numa-support.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 1565426c6bc04bffe941ad6d7ce819278da323e8 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:53:36 -0400 -Subject: [PATCH 20/28] fix smbios type4 info for numa support. - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 5e271f339..b1501e0ea 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -1211,8 +1211,14 @@ static void loongarch_build_smbios(LoongarchMachineState *lsms) - uint8_t *smbios_tables, *smbios_anchor; - size_t smbios_tables_len, smbios_anchor_len; - const char *product = "QEMU Virtual Machine"; -- ms->smp.cores = 4; -+ int nb_numa_nodes, smp_cpus; - -+ smp_cpus = ms->smp.cpus; -+ nb_numa_nodes = ms->numa_state->num_nodes; -+ if (nb_numa_nodes == 0) { -+ nb_numa_nodes = 1; -+ } -+ ms->smp.cores = smp_cpus / nb_numa_nodes; - if (!lsms->fw_cfg) { - return; - } -@@ -2004,6 +2010,10 @@ static int64_t ls3a_get_default_cpu_node_id(const MachineState *ms, int idx) - { - int nb_numa_nodes = ms->numa_state->num_nodes; - int smp_cores = ms->smp.cores; -+ -+ if (nb_numa_nodes == 0) { -+ nb_numa_nodes = 1; -+ } - return idx / smp_cores % nb_numa_nodes; - } - --- -2.43.5 - diff --git a/fixup-can-t-find-cpu-type.patch b/fixup-can-t-find-cpu-type.patch deleted file mode 100644 index 3ffeaf4c7517721cc6816495d0d77d7dea8d069b..0000000000000000000000000000000000000000 --- a/fixup-can-t-find-cpu-type.patch +++ /dev/null @@ -1,34 +0,0 @@ -From a08da06ba1ca817465e894737dced362babc9f18 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:51:55 -0400 -Subject: [PATCH 19/28] fixup can't find cpu type. - -Signed-off-by: lixianglai ---- - hw/loongarch/larch_3a.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index f83bd3750..5e271f339 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -547,7 +547,15 @@ static char *get_host_cpu_model_name(void) - fprintf(stderr, "read err...\n"); - } - close(fd); -- buf_p = strstr(buf, "name"); -+ buf_p = strstr(buf, "Name"); -+ if (!buf_p) { -+ buf_p = strstr(buf, "name"); -+ } -+ if (!buf_p) { -+ fprintf(stderr, "Can't find cpu name\n"); -+ return 0; -+ } -+ - - while (*buf_p != ':') { - buf_p++; --- -2.43.5 - diff --git a/kvm-csr-save-and-restore-optimization.patch b/kvm-csr-save-and-restore-optimization.patch deleted file mode 100644 index a5c3954fca1b90644afd79d1fa433de30d915588..0000000000000000000000000000000000000000 --- a/kvm-csr-save-and-restore-optimization.patch +++ /dev/null @@ -1,599 +0,0 @@ -From 2b5b79cc839c3b471724c263a1a5e35bf69c1bc9 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:25:52 -0400 -Subject: [PATCH 14/28] kvm csr save and restore optimization. - -Signed-off-by: lixianglai ---- - target/loongarch64/kvm.c | 547 +++++++++++---------------------------- - 1 file changed, 153 insertions(+), 394 deletions(-) - -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -index b5c655812..6885ec6c9 100644 ---- a/target/loongarch64/kvm.c -+++ b/target/loongarch64/kvm.c -@@ -95,19 +95,165 @@ int kvm_arch_irqchip_create(KVMState *s) - return 0; - } - -+static void kvm_csr_set_addr(uint64_t **addr, uint32_t index, uint64_t *p) -+{ -+ addr[index] = p; -+} -+ - int kvm_arch_init_vcpu(CPUState *cs) - { - LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ uint64_t **addr; -+ CPULOONGARCHState *env = &cpu->env; - int ret = 0; - - cpu->cpuStateEntry = qemu_add_vm_change_state_handler(kvm_loongarch_update_state, cs); -- cpu->kvm_csr_buf = g_malloc0(CSR_BUF_SIZE); -+ cpu->kvm_csr_buf = g_malloc0(CSR_BUF_SIZE + CSR_BUF_SIZE); -+ -+ addr = (void *)cpu->kvm_csr_buf + CSR_BUF_SIZE; -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_CRMD, &env->CSR_CRMD); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRMD, &env->CSR_PRMD); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_EUEN, &env->CSR_EUEN); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_MISC, &env->CSR_MISC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ECFG, &env->CSR_ECFG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ESTAT, &env->CSR_ESTAT); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERA, &env->CSR_ERA); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_BADV, &env->CSR_BADV); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_BADI, &env->CSR_BADI); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_EEPN, &env->CSR_EEPN); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBIDX, &env->CSR_TLBIDX); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBEHI, &env->CSR_TLBEHI); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBELO0, &env->CSR_TLBELO0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBELO1, &env->CSR_TLBELO1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GTLBC, &env->CSR_GTLBC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TRGP, &env->CSR_TRGP); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ASID, &env->CSR_ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PGDL, &env->CSR_PGDL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PGDH, &env->CSR_PGDH); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PGD, &env->CSR_PGD); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PWCTL0, &env->CSR_PWCTL0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PWCTL1, &env->CSR_PWCTL1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_STLBPGSIZE, &env->CSR_STLBPGSIZE); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_RVACFG, &env->CSR_RVACFG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_CPUID, &env->CSR_CPUID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRCFG1, &env->CSR_PRCFG1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRCFG2, &env->CSR_PRCFG2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PRCFG3, &env->CSR_PRCFG3); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS0, &env->CSR_KS0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS1, &env->CSR_KS1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS2, &env->CSR_KS2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS3, &env->CSR_KS3); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS4, &env->CSR_KS4); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS5, &env->CSR_KS5); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS6, &env->CSR_KS6); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_KS7, &env->CSR_KS7); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TMID, &env->CSR_TMID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_CNTC, &env->CSR_CNTC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TINTCLR, &env->CSR_TINTCLR); -+ -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GSTAT, &env->CSR_GSTAT); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GCFG, &env->CSR_GCFG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GINTC, &env->CSR_GINTC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GCNTC, &env->CSR_GCNTC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_LLBCTL, &env->CSR_LLBCTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IMPCTL1, &env->CSR_IMPCTL1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IMPCTL2, &env->CSR_IMPCTL2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_GNMI, &env->CSR_GNMI); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRENT, &env->CSR_TLBRENT); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRBADV, &env->CSR_TLBRBADV); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRERA, &env->CSR_TLBRERA); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRSAVE, &env->CSR_TLBRSAVE); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRELO0, &env->CSR_TLBRELO0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRELO1, &env->CSR_TLBRELO1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBREHI, &env->CSR_TLBREHI); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_TLBRPRMD, &env->CSR_TLBRPRMD); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRCTL, &env->CSR_ERRCTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRINFO, &env->CSR_ERRINFO); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRINFO1, &env->CSR_ERRINFO1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRENT, &env->CSR_ERRENT); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRERA, &env->CSR_ERRERA); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_ERRSAVE, &env->CSR_ERRSAVE); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_CTAG, &env->CSR_CTAG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN0, &env->CSR_DMWIN0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN1, &env->CSR_DMWIN1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN2, &env->CSR_DMWIN2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DMWIN3, &env->CSR_DMWIN3); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL0, &env->CSR_PERFCTRL0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR0, &env->CSR_PERFCNTR0); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL1, &env->CSR_PERFCTRL1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR1, &env->CSR_PERFCNTR1); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL2, &env->CSR_PERFCTRL2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR2, &env->CSR_PERFCNTR2); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCTRL3, &env->CSR_PERFCTRL3); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_PERFCNTR3, &env->CSR_PERFCNTR3); -+ -+ /* debug */ -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_MWPC, &env->CSR_MWPC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_MWPS, &env->CSR_MWPS); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0ADDR, &env->CSR_DB0ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0MASK, &env->CSR_DB0MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0CTL, &env->CSR_DB0CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB0ASID, &env->CSR_DB0ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1ADDR, &env->CSR_DB1ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1MASK, &env->CSR_DB1MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1CTL, &env->CSR_DB1CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB1ASID, &env->CSR_DB1ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2ADDR, &env->CSR_DB2ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2MASK, &env->CSR_DB2MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2CTL, &env->CSR_DB2CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB2ASID, &env->CSR_DB2ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3ADDR, &env->CSR_DB3ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3MASK, &env->CSR_DB3MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3CTL, &env->CSR_DB3CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DB3ASID, &env->CSR_DB3ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_FWPC, &env->CSR_FWPC); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_FWPS, &env->CSR_FWPS); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0ADDR, &env->CSR_IB0ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0MASK, &env->CSR_IB0MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0CTL, &env->CSR_IB0CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB0ASID, &env->CSR_IB0ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1ADDR, &env->CSR_IB1ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1MASK, &env->CSR_IB1MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1CTL, &env->CSR_IB1CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB1ASID, &env->CSR_IB1ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2ADDR, &env->CSR_IB2ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2MASK, &env->CSR_IB2MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2CTL, &env->CSR_IB2CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB2ASID, &env->CSR_IB2ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3ADDR, &env->CSR_IB3ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3MASK, &env->CSR_IB3MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3CTL, &env->CSR_IB3CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB3ASID, &env->CSR_IB3ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4ADDR, &env->CSR_IB4ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4MASK, &env->CSR_IB4MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4CTL, &env->CSR_IB4CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB4ASID, &env->CSR_IB4ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5ADDR, &env->CSR_IB5ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5MASK, &env->CSR_IB5MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5CTL, &env->CSR_IB5CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB5ASID, &env->CSR_IB5ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6ADDR, &env->CSR_IB6ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6MASK, &env->CSR_IB6MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6CTL, &env->CSR_IB6CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB6ASID, &env->CSR_IB6ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7ADDR, &env->CSR_IB7ADDR); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7MASK, &env->CSR_IB7MASK); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7CTL, &env->CSR_IB7CTL); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_IB7ASID, &env->CSR_IB7ASID); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DEBUG, &env->CSR_DEBUG); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DERA, &env->CSR_DERA); -+ kvm_csr_set_addr(addr, LOONGARCH_CSR_DESAVE, &env->CSR_DESAVE); -+ - DPRINTF("%s\n", __func__); - return ret; - } - - int kvm_arch_destroy_vcpu(CPUState *cs) - { -+ LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); -+ -+ g_free(cpu->kvm_csr_buf); -+ cpu->kvm_csr_buf = NULL; - return 0; - } - -@@ -936,8 +1082,10 @@ static int kvm_loongarch_get_csr_registers(CPUState *cs) - CPULOONGARCHState *env = &cpu->env; - int ret = 0, i; - struct kvm_csr_entry *csrs = cpu->kvm_csr_buf->entries; -+ uint64_t **addr; - - kvm_csr_buf_reset(cpu); -+ addr = (void *)cpu->kvm_csr_buf + CSR_BUF_SIZE; - - kvm_csr_entry_add(cpu, LOONGARCH_CSR_CRMD, 0); - kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRMD, 0); -@@ -1082,399 +1230,10 @@ static int kvm_loongarch_get_csr_registers(CPUState *cs) - - for (i = 0; i < ret; i++) { - uint32_t index = csrs[i].index; -- -- switch (index) { -- case LOONGARCH_CSR_CRMD: -- env->CSR_CRMD = csrs[i].data; -- break; -- case LOONGARCH_CSR_PRMD: -- env->CSR_PRMD = csrs[i].data; -- break; -- case LOONGARCH_CSR_EUEN: -- env->CSR_EUEN = csrs[i].data; -- break; -- case LOONGARCH_CSR_MISC: -- env->CSR_MISC = csrs[i].data; -- break; -- case LOONGARCH_CSR_ECFG: -- env->CSR_ECFG = csrs[i].data; -- break; -- case LOONGARCH_CSR_ESTAT: -- env->CSR_ESTAT = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERA: -- env->CSR_ERA = csrs[i].data; -- break; -- case LOONGARCH_CSR_BADV: -- env->CSR_BADV = csrs[i].data; -- break; -- case LOONGARCH_CSR_BADI: -- env->CSR_BADI = csrs[i].data; -- break; -- case LOONGARCH_CSR_EEPN: -- env->CSR_EEPN = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBIDX: -- env->CSR_TLBIDX = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBEHI: -- env->CSR_TLBEHI = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBELO0: -- env->CSR_TLBELO0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBELO1: -- env->CSR_TLBELO1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_GTLBC: -- env->CSR_GTLBC = csrs[i].data; -- break; -- case LOONGARCH_CSR_TRGP: -- env->CSR_TRGP = csrs[i].data; -- break; -- case LOONGARCH_CSR_ASID: -- env->CSR_ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_PGDL: -- env->CSR_PGDL = csrs[i].data; -- break; -- case LOONGARCH_CSR_PGDH: -- env->CSR_PGDH = csrs[i].data; -- break; -- case LOONGARCH_CSR_PGD: -- env->CSR_PGD = csrs[i].data; -- break; -- case LOONGARCH_CSR_PWCTL0: -- env->CSR_PWCTL0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PWCTL1: -- env->CSR_PWCTL1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_STLBPGSIZE: -- env->CSR_STLBPGSIZE = csrs[i].data; -- break; -- case LOONGARCH_CSR_RVACFG: -- env->CSR_RVACFG = csrs[i].data; -- break; -- case LOONGARCH_CSR_CPUID: -- env->CSR_CPUID = csrs[i].data; -- break; -- case LOONGARCH_CSR_PRCFG1: -- env->CSR_PRCFG1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PRCFG2: -- env->CSR_PRCFG2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PRCFG3: -- env->CSR_PRCFG3 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS0: -- env->CSR_KS0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS1: -- env->CSR_KS1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS2: -- env->CSR_KS2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS3: -- env->CSR_KS3 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS4: -- env->CSR_KS4 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS5: -- env->CSR_KS5 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS6: -- env->CSR_KS6 = csrs[i].data; -- break; -- case LOONGARCH_CSR_KS7: -- env->CSR_KS7 = csrs[i].data; -- break; -- -- case LOONGARCH_CSR_TMID: -- env->CSR_TMID = csrs[i].data; -- break; -- case LOONGARCH_CSR_CNTC: -- env->CSR_CNTC = csrs[i].data; -- break; -- case LOONGARCH_CSR_TINTCLR: -- env->CSR_TINTCLR = csrs[i].data; -- break; -- case LOONGARCH_CSR_GSTAT: -- env->CSR_GSTAT = csrs[i].data; -- break; -- case LOONGARCH_CSR_GCFG: -- env->CSR_GCFG = csrs[i].data; -- break; -- case LOONGARCH_CSR_GINTC: -- env->CSR_GINTC = csrs[i].data; -- break; -- case LOONGARCH_CSR_GCNTC: -- env->CSR_GCNTC = csrs[i].data; -- break; -- case LOONGARCH_CSR_LLBCTL: -- env->CSR_LLBCTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IMPCTL1: -- env->CSR_IMPCTL1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_IMPCTL2: -- env->CSR_IMPCTL2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_GNMI: -- env->CSR_GNMI = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRENT: -- env->CSR_TLBRENT = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRBADV: -- env->CSR_TLBRBADV = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRERA: -- env->CSR_TLBRERA = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRSAVE: -- env->CSR_TLBRSAVE = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRELO0: -- env->CSR_TLBRELO0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRELO1: -- env->CSR_TLBRELO1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBREHI: -- env->CSR_TLBREHI = csrs[i].data; -- break; -- case LOONGARCH_CSR_TLBRPRMD: -- env->CSR_TLBRPRMD = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRCTL: -- env->CSR_ERRCTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRINFO: -- env->CSR_ERRINFO = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRINFO1: -- env->CSR_ERRINFO1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRENT: -- env->CSR_ERRENT = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRERA: -- env->CSR_ERRERA = csrs[i].data; -- break; -- case LOONGARCH_CSR_ERRSAVE: -- env->CSR_ERRSAVE = csrs[i].data; -- break; -- case LOONGARCH_CSR_CTAG: -- env->CSR_CTAG = csrs[i].data; -- break; -- case LOONGARCH_CSR_DMWIN0: -- env->CSR_DMWIN0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_DMWIN1: -- env->CSR_DMWIN1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_DMWIN2: -- env->CSR_DMWIN2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_DMWIN3: -- env->CSR_DMWIN3 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCTRL0: -- env->CSR_PERFCTRL0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCNTR0: -- env->CSR_PERFCNTR0 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCTRL1: -- env->CSR_PERFCTRL1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCNTR1: -- env->CSR_PERFCNTR1 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCTRL2: -- env->CSR_PERFCTRL2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCNTR2: -- env->CSR_PERFCNTR2 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCTRL3: -- env->CSR_PERFCTRL3 = csrs[i].data; -- break; -- case LOONGARCH_CSR_PERFCNTR3: -- env->CSR_PERFCNTR3 = csrs[i].data; -- break; -- -- case LOONGARCH_CSR_MWPC: -- env->CSR_MWPC = csrs[i].data; -- break; -- case LOONGARCH_CSR_MWPS: -- env->CSR_MWPS = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB0ADDR: -- env->CSR_DB0ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB0MASK: -- env->CSR_DB0MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB0CTL: -- env->CSR_DB0CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB0ASID: -- env->CSR_DB0ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB1ADDR: -- env->CSR_DB1ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB1MASK: -- env->CSR_DB1MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB1CTL: -- env->CSR_DB1CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB1ASID: -- env->CSR_DB1ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB2ADDR: -- env->CSR_DB2ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB2MASK: -- env->CSR_DB2MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB2CTL: -- env->CSR_DB2CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB2ASID: -- env->CSR_DB2ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB3ADDR: -- env->CSR_DB3ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB3MASK: -- env->CSR_DB3MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB3CTL: -- env->CSR_DB3CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_DB3ASID: -- env->CSR_DB3ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_FWPC: -- env->CSR_FWPC = csrs[i].data; -- break; -- case LOONGARCH_CSR_FWPS: -- env->CSR_FWPS = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB0ADDR: -- env->CSR_IB0ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB0MASK: -- env->CSR_IB0MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB0CTL: -- env->CSR_IB0CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB0ASID: -- env->CSR_IB0ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB1ADDR: -- env->CSR_IB1ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB1MASK: -- env->CSR_IB1MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB1CTL: -- env->CSR_IB1CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB1ASID: -- env->CSR_IB1ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB2ADDR: -- env->CSR_IB2ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB2MASK: -- env->CSR_IB2MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB2CTL: -- env->CSR_IB2CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB2ASID: -- env->CSR_IB2ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB3ADDR: -- env->CSR_IB3ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB3MASK: -- env->CSR_IB3MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB3CTL: -- env->CSR_IB3CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB3ASID: -- env->CSR_IB3ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB4ADDR: -- env->CSR_IB4ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB4MASK: -- env->CSR_IB4MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB4CTL: -- env->CSR_IB4CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB4ASID: -- env->CSR_IB4ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB5ADDR: -- env->CSR_IB5ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB5MASK: -- env->CSR_IB5MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB5CTL: -- env->CSR_IB5CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB5ASID: -- env->CSR_IB5ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB6ADDR: -- env->CSR_IB6ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB6MASK: -- env->CSR_IB6MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB6CTL: -- env->CSR_IB6CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB6ASID: -- env->CSR_IB6ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB7ADDR: -- env->CSR_IB7ADDR = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB7MASK: -- env->CSR_IB7MASK = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB7CTL: -- env->CSR_IB7CTL = csrs[i].data; -- break; -- case LOONGARCH_CSR_IB7ASID: -- env->CSR_IB7ASID = csrs[i].data; -- break; -- case LOONGARCH_CSR_DEBUG: -- env->CSR_DEBUG = csrs[i].data; -- break; -- case LOONGARCH_CSR_DERA: -- env->CSR_DERA = csrs[i].data; -- break; -- case LOONGARCH_CSR_DESAVE: -- env->CSR_DESAVE = csrs[i].data; -- break; -- default: -- break; -+ if (addr[index]) { -+ *addr[index] = csrs[i].data; -+ } else { -+ printf("Failed to get addr CSR 0x%"PRIx32"\n", i); - } - } - --- -2.43.5 - diff --git a/kvm-iotests-test-NBD-TLS-iothread.patch b/kvm-iotests-test-NBD-TLS-iothread.patch new file mode 100644 index 0000000000000000000000000000000000000000..c87e6731e73e0952fb8444f4ed807109ba66caa6 --- /dev/null +++ b/kvm-iotests-test-NBD-TLS-iothread.patch @@ -0,0 +1,277 @@ +From a0b12780f3cb97abad0a2c54d185c298d3f589e7 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Fri, 17 May 2024 21:50:15 -0500 +Subject: [PATCH 2/3] iotests: test NBD+TLS+iothread +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Eric Blake +RH-MergeRequest: 398: nbd/server: CVE-2024-7409: Avoid use-after-free when closing server +RH-Jira: RHEL-52611 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Commit: [2/3] f522ff5156086a83a7327c379dd3ccd8b583a421 (ebblake/qemu-kvm) + +Prevent regressions when using NBD with TLS in the presence of +iothreads, adding coverage the fix to qio channels made in the +previous patch. + +The shell function pick_unused_port() was copied from +nbdkit.git/tests/functions.sh.in, where it had all authors from Red +Hat, agreeing to the resulting relicensing from 2-clause BSD to GPLv2. + +CC: qemu-stable@nongnu.org +CC: "Richard W.M. Jones" +Signed-off-by: Eric Blake +Message-ID: <20240531180639.1392905-6-eblake@redhat.com> +Reviewed-by: Daniel P. Berrangé + +(cherry picked from commit a73c99378022ebb785481e84cfe1e81097546268) +Jira: https://issues.redhat.com/browse/RHEL-52611 +Conflicts: + tests/qemu-iotests/tests/nbd-tls-iothread{,.out} - drop unknown + "tls-hostname" parameter +Signed-off-by: Eric Blake +--- + tests/qemu-iotests/tests/nbd-tls-iothread | 167 ++++++++++++++++++ + tests/qemu-iotests/tests/nbd-tls-iothread.out | 53 ++++++ + 2 files changed, 220 insertions(+) + create mode 100755 tests/qemu-iotests/tests/nbd-tls-iothread + create mode 100644 tests/qemu-iotests/tests/nbd-tls-iothread.out + +diff --git a/tests/qemu-iotests/tests/nbd-tls-iothread b/tests/qemu-iotests/tests/nbd-tls-iothread +new file mode 100755 +index 0000000000..9e747e2639 +--- /dev/null ++++ b/tests/qemu-iotests/tests/nbd-tls-iothread +@@ -0,0 +1,167 @@ ++#!/usr/bin/env bash ++# group: rw quick ++# ++# Test of NBD+TLS+iothread ++# ++# Copyright (C) 2024 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# creator ++owner=eblake@redhat.com ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_qemu ++ _cleanup_test_img ++ rm -f "$dst_image" ++ tls_x509_cleanup ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++cd .. ++. ./common.rc ++. ./common.filter ++. ./common.qemu ++. ./common.tls ++. ./common.nbd ++ ++_supported_fmt qcow2 # Hardcoded to qcow2 command line and QMP below ++_supported_proto file ++ ++# pick_unused_port ++# ++# Picks and returns an "unused" port, setting the global variable ++# $port. ++# ++# This is inherently racy, but we need it because qemu does not currently ++# permit NBD+TLS over a Unix domain socket ++pick_unused_port () ++{ ++ if ! (ss --version) >/dev/null 2>&1; then ++ _notrun "ss utility required, skipped this test" ++ fi ++ ++ # Start at a random port to make it less likely that two parallel ++ # tests will conflict. ++ port=$(( 50000 + (RANDOM%15000) )) ++ while ss -ltn | grep -sqE ":$port\b"; do ++ ((port++)) ++ if [ $port -eq 65000 ]; then port=50000; fi ++ done ++ echo picked unused port ++} ++ ++tls_x509_init ++ ++size=1G ++DST_IMG="$TEST_DIR/dst.qcow2" ++ ++echo ++echo "== preparing TLS creds and spare port ==" ++ ++pick_unused_port ++tls_x509_create_root_ca "ca1" ++tls_x509_create_server "ca1" "server1" ++tls_x509_create_client "ca1" "client1" ++tls_obj_base=tls-creds-x509,id=tls0,verify-peer=true,dir="${tls_dir}" ++ ++echo ++echo "== preparing image ==" ++ ++_make_test_img $size ++$QEMU_IMG create -f qcow2 "$DST_IMG" $size | _filter_img_create ++ ++echo ++echo === Starting Src QEMU === ++echo ++ ++_launch_qemu -machine q35 \ ++ -object iothread,id=iothread0 \ ++ -object "${tls_obj_base}"/client1,endpoint=client \ ++ -device '{"driver":"pcie-root-port", "id":"root0", "multifunction":true, ++ "bus":"pcie.0"}' \ ++ -device '{"driver":"virtio-scsi-pci", "id":"virtio_scsi_pci0", ++ "bus":"root0", "iothread":"iothread0"}' \ ++ -device '{"driver":"scsi-hd", "id":"image1", "drive":"drive_image1", ++ "bus":"virtio_scsi_pci0.0"}' \ ++ -blockdev '{"driver":"file", "cache":{"direct":true, "no-flush":false}, ++ "filename":"'"$TEST_IMG"'", "node-name":"drive_sys1"}' \ ++ -blockdev '{"driver":"qcow2", "node-name":"drive_image1", ++ "file":"drive_sys1"}' ++h1=$QEMU_HANDLE ++_send_qemu_cmd $h1 '{"execute": "qmp_capabilities"}' 'return' ++ ++echo ++echo === Starting Dst VM2 === ++echo ++ ++_launch_qemu -machine q35 \ ++ -object iothread,id=iothread0 \ ++ -object "${tls_obj_base}"/server1,endpoint=server \ ++ -device '{"driver":"pcie-root-port", "id":"root0", "multifunction":true, ++ "bus":"pcie.0"}' \ ++ -device '{"driver":"virtio-scsi-pci", "id":"virtio_scsi_pci0", ++ "bus":"root0", "iothread":"iothread0"}' \ ++ -device '{"driver":"scsi-hd", "id":"image1", "drive":"drive_image1", ++ "bus":"virtio_scsi_pci0.0"}' \ ++ -blockdev '{"driver":"file", "cache":{"direct":true, "no-flush":false}, ++ "filename":"'"$DST_IMG"'", "node-name":"drive_sys1"}' \ ++ -blockdev '{"driver":"qcow2", "node-name":"drive_image1", ++ "file":"drive_sys1"}' \ ++ -incoming defer ++h2=$QEMU_HANDLE ++_send_qemu_cmd $h2 '{"execute": "qmp_capabilities"}' 'return' ++ ++echo ++echo === Dst VM: Enable NBD server for incoming storage migration === ++echo ++ ++_send_qemu_cmd $h2 '{"execute": "nbd-server-start", "arguments": ++ {"addr": {"type": "inet", "data": {"host": "127.0.0.1", "port": "'$port'"}}, ++ "tls-creds": "tls0"}}' '{"return": {}}' | sed "s/\"$port\"/PORT/g" ++_send_qemu_cmd $h2 '{"execute": "block-export-add", "arguments": ++ {"node-name": "drive_image1", "type": "nbd", "writable": true, ++ "id": "drive_image1"}}' '{"return": {}}' ++ ++echo ++echo === Src VM: Mirror to dst NBD for outgoing storage migration === ++echo ++ ++_send_qemu_cmd $h1 '{"execute": "blockdev-add", "arguments": ++ {"node-name": "mirror", "driver": "nbd", ++ "server": {"type": "inet", "host": "127.0.0.1", "port": "'$port'"}, ++ "export": "drive_image1", "tls-creds": "tls0"}}' '{"return": {}}' | sed "s/\"$port\"/PORT/g" ++_send_qemu_cmd $h1 '{"execute": "blockdev-mirror", "arguments": ++ {"sync": "full", "device": "drive_image1", "target": "mirror", ++ "job-id": "drive_image1_53"}}' '{"return": {}}' ++_timed_wait_for $h1 '"ready"' ++ ++echo ++echo === Cleaning up === ++echo ++ ++_send_qemu_cmd $h1 '{"execute":"quit"}' '' ++_send_qemu_cmd $h2 '{"execute":"quit"}' '' ++ ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/tests/nbd-tls-iothread.out b/tests/qemu-iotests/tests/nbd-tls-iothread.out +new file mode 100644 +index 0000000000..a3899fd2d7 +--- /dev/null ++++ b/tests/qemu-iotests/tests/nbd-tls-iothread.out +@@ -0,0 +1,53 @@ ++QA output created by nbd-tls-iothread ++ ++== preparing TLS creds and spare port == ++picked unused port ++Generating a self signed certificate... ++Generating a signed certificate... ++Generating a signed certificate... ++ ++== preparing image == ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 ++Formatting 'TEST_DIR/dst.IMGFMT', fmt=IMGFMT size=1073741824 ++ ++=== Starting Src QEMU === ++ ++{"execute": "qmp_capabilities"} ++{"return": {}} ++ ++=== Starting Dst VM2 === ++ ++{"execute": "qmp_capabilities"} ++{"return": {}} ++ ++=== Dst VM: Enable NBD server for incoming storage migration === ++ ++{"execute": "nbd-server-start", "arguments": ++ {"addr": {"type": "inet", "data": {"host": "127.0.0.1", "port": PORT}}, ++ "tls-creds": "tls0"}} ++{"return": {}} ++{"execute": "block-export-add", "arguments": ++ {"node-name": "drive_image1", "type": "nbd", "writable": true, ++ "id": "drive_image1"}} ++{"return": {}} ++ ++=== Src VM: Mirror to dst NBD for outgoing storage migration === ++ ++{"execute": "blockdev-add", "arguments": ++ {"node-name": "mirror", "driver": "nbd", ++ "server": {"type": "inet", "host": "127.0.0.1", "port": PORT}, ++ "export": "drive_image1", "tls-creds": "tls0"}} ++{"return": {}} ++{"execute": "blockdev-mirror", "arguments": ++ {"sync": "full", "device": "drive_image1", "target": "mirror", ++ "job-id": "drive_image1_53"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "drive_image1_53"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "drive_image1_53"}} ++{"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "drive_image1_53"}} ++ ++=== Cleaning up === ++ ++{"execute":"quit"} ++{"execute":"quit"} ++*** done +-- +2.39.3 + diff --git a/kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch b/kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..1fada413de0fc2836db2d94a9877110ba68b5872 --- /dev/null +++ b/kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch @@ -0,0 +1,101 @@ +From 676438ff8c42323c3e5d9e7eeeb1b3367999136c Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Thu, 22 Aug 2024 09:35:29 -0500 +Subject: [PATCH 3/3] nbd/server: CVE-2024-7409: Avoid use-after-free when + closing server + +RH-Author: Eric Blake +RH-MergeRequest: 398: nbd/server: CVE-2024-7409: Avoid use-after-free when closing server +RH-Jira: RHEL-52611 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Commit: [3/3] 1ee35a40ded067a085bf6fcafa690b40976d7f2d (ebblake/qemu-kvm) + +Commit 3e7ef738 plugged the use-after-free of the global nbd_server +object, but overlooked a use-after-free of nbd_server->listener. +Although this race is harder to hit, notice that our shutdown path +first drops the reference count of nbd_server->listener, then triggers +actions that can result in a pending client reaching the +nbd_blockdev_client_closed() callback, which in turn calls +qio_net_listener_set_client_func on a potentially stale object. + +If we know we don't want any more clients to connect, and have already +told the listener socket to shut down, then we should not be trying to +update the listener socket's associated function. + +Reproducer: + +> #!/usr/bin/python3 +> +> import os +> from threading import Thread +> +> def start_stop(): +> while 1: +> os.system('virsh qemu-monitor-command VM \'{"execute": "nbd-server-start", ++"arguments":{"addr":{"type":"unix","data":{"path":"/tmp/nbd-sock"}}}}\'') +> os.system('virsh qemu-monitor-command VM \'{"execute": "nbd-server-stop"}\'') +> +> def nbd_list(): +> while 1: +> os.system('/path/to/build/qemu-nbd -L -k /tmp/nbd-sock') +> +> def test(): +> sst = Thread(target=start_stop) +> sst.start() +> nlt = Thread(target=nbd_list) +> nlt.start() +> +> sst.join() +> nlt.join() +> +> test() + +Fixes: CVE-2024-7409 +Fixes: 3e7ef738c8 ("nbd/server: CVE-2024-7409: Close stray clients at server-stop") +CC: qemu-stable@nongnu.org +Reported-by: Andrey Drobyshev +Signed-off-by: Eric Blake +Message-ID: <20240822143617.800419-2-eblake@redhat.com> +Reviewed-by: Stefan Hajnoczi + +(cherry picked from commit 3874f5f73c441c52f1c699c848d463b0eda01e4c) +Jira: https://issues.redhat.com/browse/RHEL-52611 +Signed-off-by: Eric Blake +--- + blockdev-nbd.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index 87839c180b..b5d55e2518 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -87,10 +87,13 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, + + static void nbd_update_server_watch(NBDServerData *s) + { +- if (!s->max_connections || s->connections < s->max_connections) { +- qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, NULL); +- } else { +- qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); ++ if (s->listener) { ++ if (!s->max_connections || s->connections < s->max_connections) { ++ qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, ++ NULL); ++ } else { ++ qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); ++ } + } + } + +@@ -108,6 +111,7 @@ static void nbd_server_free(NBDServerData *server) + */ + qio_net_listener_disconnect(server->listener); + object_unref(OBJECT(server->listener)); ++ server->listener = NULL; + QLIST_FOREACH_SAFE(conn, &server->conns, next, tmp) { + qio_channel_shutdown(QIO_CHANNEL(conn->cioc), QIO_CHANNEL_SHUTDOWN_BOTH, + NULL); +-- +2.39.3 + diff --git a/kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch b/kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch new file mode 100644 index 0000000000000000000000000000000000000000..54030b0b75ed54c2cc3da8f3e19f6f25d18c87f0 --- /dev/null +++ b/kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch @@ -0,0 +1,161 @@ +From 00af174d1388ed2d2df7961ee78be6af3757a01c Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 30 Aug 2023 18:48:02 -0400 +Subject: [PATCH 1/3] nbd/server: Favor qemu_aio_context over iohandler context + +RH-Author: Eric Blake +RH-MergeRequest: 398: nbd/server: CVE-2024-7409: Avoid use-after-free when closing server +RH-Jira: RHEL-52611 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Commit: [1/3] 6ec0ef287fbc976175da83a0c14d9878e83affa2 (ebblake/qemu-kvm) + +DOWNSTREAM ONLY - but based on an idea originally included as a +side-effect in the larger upstream patch 06e0f098 "io: follow +coroutine AioContext in qio_channel_yield()", as well as handling the +state of the qio TLS channel before it is associated with a block +device as an alternative to 199e84de "qio: Inherit +follow_coroutine_ctx across TLS". + +The NBD server code wants to use qio_channel_shutdown() followed by +AIO_WAIT_WHILE() during nbd_server_free(), but cannot attach the ioc +to an AioContext until the client has completed the handshake to the +point that the server knows what block device to associate with the +connection. The qio code is set up to handle connections with no +AioContext in the iohandler context, but this context is specifically +designed to NOT make progress during AIO_WAIT_WHILE(). In order to +prevent things from deadlocking, the qio channels handling NBD +handshake MUST be in the qemu_aio_context, so that an early shutdown +triggered by nbd-server-stop can make progress. + +Note that upstream handled the main qio channel by the use of +qio_channel_set_follow_coroutine_ctx() in only one place in +nbd/server.c; upstream handled the TLS channel by a more generic +second patch that taught qio TLS channel to inherit the +follow_coroutine_ctx status from its parent. But since this patch is +already downstream only, the minimal diff is achieved by manually +setting the status of the TLS channel in NBD code, rather than +backporting the qio inheritance code. For testing that the second +call to qio_channel_set_favor_qemu_aio_ctx() matters, I used this test +setup (borrowing a pre-built PSK file for username alice from the +libnbd project, and using IPv4 since this qemu is too old to support +TLS over Unix sockets): + +$ # in terminal 1: +$ qemu-system-x86_64 --nographic --nodefaults --qmp stdio \ + --object tls-creds-psk,id=tls0,dir=/PATHTO/libnbd/tests,endpoint=server +{"execute": "qmp_capabilities"} +{"execute":"nbd-server-start","arguments":{"addr":{"type":"inet", + "data":{"host":"127.0.0.1","port":"10809"}},"tls-creds":"tls0"}} + +$ # in terminal 2: +$ nbdsh -c 'h.set_uri_allow_local_file(True)' --opt-mode -u \ + 'nbds://alice@127.0.0.1/?tls-psk-file=/PATHTO/libnbd/tests/keys.psk' \ + -c 'import time; time.sleep(15)' + +$ # in terminal 1, before 10 seconds elapse +{"execute":"nbd-server-stop"} +{"execute":"quit"} + +and observed that, when omitting the one-line TLS setting, qemu would +hit the same deadlock with a TLS client as what I was observing for a +non-TLS client without this entire patch. + +Jira: https://issues.redhat.com/browse/RHEL-52611 +Suggested-by: Kevin Wolf +Signed-off-by: Eric Blake +--- + include/io/channel.h | 16 ++++++++++++++++ + io/channel.c | 14 +++++++++++++- + nbd/server.c | 2 ++ + 3 files changed, 31 insertions(+), 1 deletion(-) + +diff --git a/include/io/channel.h b/include/io/channel.h +index 716235d496..f1ce19ea81 100644 +--- a/include/io/channel.h ++++ b/include/io/channel.h +@@ -84,6 +84,7 @@ struct QIOChannel { + AioContext *ctx; + Coroutine *read_coroutine; + Coroutine *write_coroutine; ++ bool favor_qemu_aio_ctx; + #ifdef _WIN32 + HANDLE event; /* For use with GSource on Win32 */ + #endif +@@ -498,6 +499,21 @@ int qio_channel_set_blocking(QIOChannel *ioc, + bool enabled, + Error **errp); + ++/** ++ * qio_channel_set_favor_qemu_aio_ctx: ++ * @ioc: the channel object ++ * @enabled: whether to fall back to qemu_aio_context ++ * ++ * If @enabled is true, calls to qio_channel_yield() with no AioContext ++ * set use the qemu_aio_context instead of the global iohandler context. ++ * ++ * If @enabled is false, calls to qio_channel_yield() use the global iohandler ++ * AioContext. This is may be used by coroutines that run in the main loop and ++ * do not wish to respond to I/O during nested event loops. This is the ++ * default for compatibility with code that is not aware of AioContexts. ++ */ ++void qio_channel_set_favor_qemu_aio_ctx(QIOChannel *ioc, bool enabled); ++ + /** + * qio_channel_close: + * @ioc: the channel object +diff --git a/io/channel.c b/io/channel.c +index a8c7f11649..74704d0464 100644 +--- a/io/channel.c ++++ b/io/channel.c +@@ -364,6 +364,12 @@ int qio_channel_set_blocking(QIOChannel *ioc, + } + + ++void qio_channel_set_favor_qemu_aio_ctx(QIOChannel *ioc, bool enabled) ++{ ++ ioc->favor_qemu_aio_ctx = enabled; ++} ++ ++ + int qio_channel_close(QIOChannel *ioc, + Error **errp) + { +@@ -545,7 +551,13 @@ static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc) + wr_handler = qio_channel_restart_write; + } + +- ctx = ioc->ctx ? ioc->ctx : iohandler_get_aio_context(); ++ if (ioc->ctx) { ++ ctx = ioc->ctx; ++ } else if (ioc->favor_qemu_aio_ctx) { ++ ctx = qemu_get_aio_context(); ++ } else { ++ ctx = iohandler_get_aio_context(); ++ } + qio_channel_set_aio_fd_handler(ioc, ctx, rd_handler, wr_handler, ioc); + } + +diff --git a/nbd/server.c b/nbd/server.c +index 1265068f70..41a2003300 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -758,6 +758,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, + return NULL; + } + ++ qio_channel_set_favor_qemu_aio_ctx(QIO_CHANNEL(tioc), true); + qio_channel_set_name(QIO_CHANNEL(tioc), "nbd-server-tls"); + trace_nbd_negotiate_handle_starttls_handshake(); + data.loop = g_main_loop_new(g_main_context_default(), FALSE); +@@ -1333,6 +1334,7 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) + */ + + qio_channel_set_blocking(client->ioc, false, NULL); ++ qio_channel_set_favor_qemu_aio_ctx(client->ioc, true); + + trace_nbd_negotiate_begin(); + memcpy(buf, "NBDMAGIC", 8); +-- +2.39.3 + diff --git a/kvm-virtiofsd-Adjust-limit-for-minor-version.patch b/kvm-virtiofsd-Adjust-limit-for-minor-version.patch deleted file mode 100644 index 30ec553d52c1fe085c19792806108a567a826c7d..0000000000000000000000000000000000000000 --- a/kvm-virtiofsd-Adjust-limit-for-minor-version.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 3b7200134925fcf5ae99b5c3b34465456d3bc002 Mon Sep 17 00:00:00 2001 -From: Jacob Wang -Date: Mon, 2 Aug 2021 01:16:05 +0800 -Subject: [PATCH 1/1] virtiofsd: Adjust limit for minor version - -Upstream virtiofsd only supports fuse >= 7.31 -(https://github.com/qemu/qemu/commit/72c42e2d65510e073cf78fdc924d121c77fa0080), -while Cloud Kernel has fuse version 7.27, which causes virtiofs fails to run -due to version mismatch. This limitation is unnecessary in Cloud Kernel because -we have already backported mandatory fuse patches to support virtofs -frontend in Kernel. Hence, adjust the minor version limit to 7.27 to -suppress the limitation. - -Note that current fuse implementation in Cloud Kernel might lack of some -certain capabilities in fuse 7.28 ~ 7.31, which may cause unexpected results, -this patch is merely a workaround to enable virtiofs in guest kernel side and -further action is ongoing to make sure fuse APIs in both sides are 100% -compatible. - -Signed-off-by: Jacob Wang -Acked-by: Caspar Zhang ---- - tools/virtiofsd/fuse_lowlevel.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c -index 2dd36ec..2bb4318 100644 ---- a/tools/virtiofsd/fuse_lowlevel.c -+++ b/tools/virtiofsd/fuse_lowlevel.c -@@ -1917,7 +1917,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - -- if (arg->major < 7 || (arg->major == 7 && arg->minor < 31)) { -+ if (arg->major < 7 || (arg->major == 7 && arg->minor < 27)) { - fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n", - arg->major, arg->minor); - fuse_reply_err(req, EPROTO); --- -1.8.3.1 - diff --git a/loongarch_bios.bin b/loongarch_bios.bin deleted file mode 100644 index d6330c6f0532effe458726efa18222166a444839..0000000000000000000000000000000000000000 Binary files a/loongarch_bios.bin and /dev/null differ diff --git a/loongarch_vars.bin b/loongarch_vars.bin deleted file mode 100644 index 65bdb77af90b92dc268c0c5c70c054dee71599f4..0000000000000000000000000000000000000000 Binary files a/loongarch_vars.bin and /dev/null differ diff --git a/pass-to-make-check.patch b/pass-to-make-check.patch deleted file mode 100644 index 3a3761e68d0177b1464044a6554533912609265e..0000000000000000000000000000000000000000 --- a/pass-to-make-check.patch +++ /dev/null @@ -1,164 +0,0 @@ -From d597742733befe23034a87afad7d18ee36d01ceb Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 07:49:06 -0400 -Subject: [PATCH 18/28] pass to make check. - -With this patch, when running make check command, qemu passes to -compile. - -Signed-off-by: lixianglai ---- - hw/loongarch/apic.c | 4 ++-- - hw/loongarch/ioapic.c | 4 ++-- - hw/loongarch/iocsr.c | 20 ++++++++++++++++++-- - hw/loongarch/ipi.c | 4 ++-- - hw/loongarch/larch_3a.c | 3 --- - target/loongarch64/machine.c | 7 +++++++ - 6 files changed, 31 insertions(+), 11 deletions(-) - -diff --git a/hw/loongarch/apic.c b/hw/loongarch/apic.c -index d6ba2a2ce..67994d201 100644 ---- a/hw/loongarch/apic.c -+++ b/hw/loongarch/apic.c -@@ -64,7 +64,7 @@ static int ext_irq_pre_save(void *opaque) - struct kvm_loongarch_ls3a_extirq_state *kstate; - int ret, length, i, vcpuid; - #endif -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - #ifdef CONFIG_KVM -@@ -112,7 +112,7 @@ static int ext_irq_post_load(void *opaque, int version) - struct kvm_loongarch_ls3a_extirq_state *kstate; - int ret, length, i, vcpuid; - #endif -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - #ifdef CONFIG_KVM -diff --git a/hw/loongarch/ioapic.c b/hw/loongarch/ioapic.c -index 3de0ed88d..60abff855 100644 ---- a/hw/loongarch/ioapic.c -+++ b/hw/loongarch/ioapic.c -@@ -253,7 +253,7 @@ static int kvm_ls7a_pre_save(void *opaque) - struct ls7a_ioapic_state *state; - int ret, i, length; - -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - -@@ -297,7 +297,7 @@ static int kvm_ls7a_post_load(void *opaque, int version) - struct ls7a_ioapic_state *state; - int ret, i, length; - -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - length = sizeof(struct loongarch_kvm_irqchip) + sizeof(struct ls7a_ioapic_state); -diff --git a/hw/loongarch/iocsr.c b/hw/loongarch/iocsr.c -index 60daafd6e..13d356d80 100644 ---- a/hw/loongarch/iocsr.c -+++ b/hw/loongarch/iocsr.c -@@ -95,6 +95,11 @@ static int kvm_iocsr_pre_save(void *opaque) - IOCSRState *s = opaque; - struct kvm_iocsr_entry entry; - int i = 0; -+ -+ if ((!kvm_enabled())) { -+ return 0; -+ } -+ - for (i = 0; i < IOCSR_MAX; i++) { - entry.addr = iocsr_array[i]; - kvm_vm_ioctl(kvm_state, KVM_LOONGARCH_GET_IOCSR, &entry); -@@ -172,8 +177,19 @@ static void iocsr_instance_init(Object *obj) - { - IOCSRState *s = IOCSR(obj); - int i; -- LoongarchMachineState *lsms = LoongarchMACHINE(qdev_get_machine()); -- LoongarchMachineClass *lsmc = LoongarchMACHINE_GET_CLASS(lsms); -+ LoongarchMachineState *lsms; -+ LoongarchMachineClass *lsmc; -+ Object *machine = qdev_get_machine(); -+ ObjectClass *mc = object_get_class(machine); -+ -+ -+ /* 'lams' should be initialized */ -+ if (!strcmp(MACHINE_CLASS(mc)->name, "none")) { -+ return; -+ } -+ -+ lsms = LoongarchMACHINE(machine); -+ lsmc = LoongarchMACHINE_GET_CLASS(lsms); - - init_vendor_cpuname((uint64_t *)&iocsr_init.iocsr_val[IOCSR_VENDOR], - (uint64_t *)&iocsr_init.iocsr_val[IOCSR_CPUNAME], -diff --git a/hw/loongarch/ipi.c b/hw/loongarch/ipi.c -index ade182abc..59186f1de 100644 ---- a/hw/loongarch/ipi.c -+++ b/hw/loongarch/ipi.c -@@ -25,7 +25,7 @@ static int gipi_pre_save(void *opaque) - int ret, i, j, length; - #endif - -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - -@@ -67,7 +67,7 @@ static int gipi_post_load(void *opaque, int version) - int ret, i, j, length; - #endif - -- if (!kvm_irqchip_in_kernel()) { -+ if ((!kvm_enabled()) || (!kvm_irqchip_in_kernel())) { - return 0; - } - -diff --git a/hw/loongarch/larch_3a.c b/hw/loongarch/larch_3a.c -index 6eaa53d74..f83bd3750 100644 ---- a/hw/loongarch/larch_3a.c -+++ b/hw/loongarch/larch_3a.c -@@ -1435,9 +1435,6 @@ static void ls3a5k_bios_init(LoongarchMachineState *lsms, - - if (kernel_filename) { - lsms->reset_info[0]->vector = load_kernel(); -- } else { -- error_report("Please specify at lease one of -bios and -kernel"); -- exit(1); - } - } - } -diff --git a/target/loongarch64/machine.c b/target/loongarch64/machine.c -index b69bca6a9..dea6a7034 100644 ---- a/target/loongarch64/machine.c -+++ b/target/loongarch64/machine.c -@@ -15,6 +15,10 @@ static int cpu_post_load(void *opaque, int version_id) - CPULOONGARCHState *env = &cpu->env; - int r = 0; - -+ if (!kvm_enabled()) { -+ return 0; -+ } -+ - #ifdef CONFIG_KVM - struct kvm_loongarch_vcpu_state vcpu_state; - int i; -@@ -48,6 +52,9 @@ static int cpu_pre_save(void *opaque) - LOONGARCHCPU *cpu = opaque; - struct kvm_loongarch_vcpu_state vcpu_state; - int i, r = 0; -+ if (!kvm_enabled()) { -+ return 0; -+ } - - r = kvm_vcpu_ioctl(CPU(cpu), KVM_LARCH_GET_VCPU_STATE, &vcpu_state); - if (r < 0) { --- -2.43.5 - diff --git a/qemu-kvm.spec b/qemu-kvm.spec index 08304dd24d100ec78d190e161cf1f255b1d85f9c..1a2b05a8fb71c684a5cebef38b7cfa43c397d3b9 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -1,4 +1,3 @@ -%define anolis_release .0.2 %global SLOF_gittagdate 20191022 %global SLOF_gittagcommit 899d9883 @@ -11,10 +10,6 @@ %global have_kvm_setup 0 %global have_memlock_limits 0 -%global user_static 0 -%ifarch x86_64 -%global user_static 1 -%endif # Release candidate version tracking @@ -59,11 +54,7 @@ %ifarch aarch64 %global kvm_target aarch64 %endif -%ifarch loongarch64 - %global kvm_target loongarch64 - %global have_spice 1 - %global have_usbredir 1 -%endif + #Versions of various parts: %global requires_all_modules \ @@ -92,13 +83,13 @@ Obsoletes: %1-rhev <= %{epoch}:%{version}-%{release} Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm Version: 6.2.0 -Release: 52%{?rcrel}%{anolis_release}%{?dist} +Release: 53%{?rcrel}%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 15 License: GPLv2 and GPLv2+ and CC-BY Group: Development/Tools URL: http://www.qemu.org/ -ExclusiveArch: x86_64 %{power64} aarch64 s390x loongarch64 +ExclusiveArch: x86_64 %{power64} aarch64 s390x Source0: http://wiki.qemu.org/download/qemu-6.2.0.tar.xz @@ -124,15 +115,13 @@ Source30: kvm-s390x.conf Source31: kvm-x86.conf Source32: qemu-pr-helper.service Source33: qemu-pr-helper.socket -Source34: 81-kvm-anolis.rules +Source34: 81-kvm-rhel.rules Source35: udev-kvm-check.c Source36: README.tests Source37: tests_data_acpi_pc_SSDT.dimmpxm Source38: tests_data_acpi_q35_FACP.slic Source39: tests_data_acpi_q35_SSDT.dimmpxm Source40: tests_data_acpi_virt_SSDT.memhp -Source41: loongarch_bios.bin -Source42: loongarch_vars.bin Patch0001: 0001-redhat-Adding-slirp-to-the-exploded-tree.patch Patch0005: 0005-Initial-redhat-build.patch @@ -890,106 +879,12 @@ Patch358: kvm-nbd-server-CVE-2024-7409-Drop-non-negotiating-client.patch Patch359: kvm-nbd-server-CVE-2024-7409-Close-stray-clients-at-serv.patch # For RHEL-50854 - vnc: increase max display size to 4K Patch360: kvm-vnc-increase-max-display-size.patch - -Patch1000: kvm-virtiofsd-Adjust-limit-for-minor-version.patch - -Patch1001: 0001-Add-Acpi-support.patch -Patch1002: 0002-Support-rtc.patch -Patch1003: 0003-Add-loongarch-machine.patch -Patch1004: 0004-Add-target-loongarch64.patch -Patch1005: 0005-Add-linux-headers-and-linux-user.patch -Patch1006: 0006-Add-disas-gdb.patch -Patch1007: 0007-Modify-kvm-cpu-vga-qapi.patch -Patch1008: 0008-Modify-compile-script.patch -Patch1009: 0009-Add-loongarch64-rh-devices.mak.patch -Patch1010: Modify-smbios-option-lack-and-Modify-the-maximum-num.patch -Patch1011: rename-kvm_msr_buf-with-kvm_csr_buf.patch -Patch1012: code-cleanup-for-loongarch-kvm.patch -Patch1013: Support-TPM.patch -Patch1014: kvm-csr-save-and-restore-optimization.patch -Patch1015: address-space-code-cleanup-on-7A-virt-machine.patch -Patch1016: Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch -Patch1017: Support-vfio-config.patch -Patch1018: pass-to-make-check.patch -Patch1019: fixup-can-t-find-cpu-type.patch -Patch1020: fix-smbios-type4-info-for-numa-support.patch -Patch1021: Fix-smp.cores-value.patch -Patch1022: Add-lbt-support-for-kvm.patch -Patch1023: Modify-the-ioctl-command-of-kvm.patch -Patch1024: Add-usb-storage-config-for-loongarch.patch -Patch1025: Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch -Patch1026: Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch -Patch1027: Fix-LoongArch-KVM-header-macros.patch -Patch1028: Fixed-the-issue-where-qemu-specifies-the-boot-order.patch - -# CSV3 feature on Hygon hardware -Patch1030: 0001-anolis-csv-i386-add-CSV-context.patch -Patch1031: 0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch -Patch1032: 0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch -Patch1033: 0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch -Patch1034: 0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch -Patch1035: 0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch -Patch1036: 0007-anolis-target-i386-csv-load-initial-image-to-private.patch -Patch1037: 0008-anolis-vga-force-full-update-for-CSV-guest.patch -Patch1038: 1038-doc-update-AMD-SEV-to-include-Live-migration-flow.patch -Patch1039: 1039-migration.json-add-AMD-SEV-specific-migration-parame.patch -Patch1040: 1040-confidential-guest-support-introduce-ConfidentialGue.patch -Patch1041: 1041-target-i386-sev-provide-callback-to-setup-outgoing-c.patch -Patch1042: 1042-target-i386-sev-do-not-create-launch-context-for-an-.patch -Patch1043: 1043-target-i386-sev-add-support-to-encrypt-the-outgoing-.patch -Patch1044: 1044-target-i386-sev-add-support-to-load-incoming-encrypt.patch -Patch1045: 1045-kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch -Patch1046: 1046-migration-add-support-to-migrate-shared-regions-list.patch -Patch1047: 1047-migration-ram-add-support-to-send-encrypted-pages.patch -Patch1048: 1048-migration-ram-Force-encrypted-status-for-flash0-flas.patch -Patch1049: 1049-migration-for-SEV-live-migration-bump-downtime-limit.patch -Patch1050: 1050-i386-kvm-Add-support-for-MSR-filtering.patch -Patch1051: 1051-kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch -Patch1052: 1052-anolis-migration-ram-Force-encrypted-status-for-VGA-.patch -Patch1053: 1053-anolis-target-i386-sev-Clear-shared_regions_list-whe.patch -Patch1054: 1054-anolis-migration-ram-Fix-calculation-of-gfn-correpon.patch -Patch1055: 1055-anolis-target-i386-csv-Move-is_hygon_cpu-to-header-f.patch -Patch1056: 1056-anolis-target-i386-csv-Read-cert-chain-from-file-whe.patch -Patch1057: 1057-anolis-target-i386-csv-add-support-to-queue-the-outg.patch -Patch1058: 1058-anolis-target-i386-csv-add-support-to-encrypt-the-ou.patch -Patch1059: 1059-anolis-target-i386-csv-add-support-to-queue-the-inco.patch -Patch1060: 1060-anolis-target-i386-csv-add-support-to-load-incoming-.patch -Patch1061: 1061-anolis-migration-ram-Accelerate-the-transmission-of-.patch -Patch1062: 1062-anolis-migration-ram-Accelerate-the-loading-of-CSV-g.patch -Patch1063: 1063-anolis-target-i386-csv-Add-support-for-migrate-VMSA-.patch -Patch1064: 1064-anolis-target-i386-get-set-migrate-GHCB-state.patch -Patch1065: 1065-anolis-target-i386-kvm-Return-resettable-when-emulat.patch -Patch1066: 1066-anolis-kvm-Add-support-for-CSV2-reboot.patch -Patch1067: 1067-anolis-vfio-only-map-shared-region-for-CSV-virtual-m.patch -Patch1068: 1068-anolis-linux-headers-update-kernel-headers-to-includ.patch -Patch1069: 1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch -Patch1070: 1070-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch -Patch1071: 1071-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch -Patch1072: 1072-anolis-csv-i386-add-support-to-migrate-the-incoming-.patch -Patch1073: 1073-anolis-target-i386-sev-Add-support-for-reuse-ASID-fo.patch -Patch1074: 1074-newfeature-support-vpsp.patch -Patch1075: 1075-target-i386-Add-Hygon-Dhyana-v3-CPU-model.patch -Patch1076: 1076-target-i386-Add-new-Hygon-Dharma-CPU-model.patch -Patch1077: 1077-target-i386-add-FSRM-to-TCG.patch -Patch1078: 1078-target-i386-add-FZRM-FSRS-FSRC.patch -Patch1079: 1079-i386-Add-new-CPU-model-SapphireRapids.patch -Patch1080: 1080-target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch -Patch1081: 1081-target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch -Patch1082: 1082-target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch -Patch1083: 1083-target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch -Patch1084: 1084-target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch -Patch1085: 1085-target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch -Patch1086: 1086-target-i386-Adjust-feature-level-according-to-FEAT_7.patch -Patch1087: 1087-target-i386-Add-new-bit-definitions-of-MSR_IA32_ARCH.patch -Patch1088: 1088-target-i386-Add-support-for-MCDT_NO-in-CPUID-enumera.patch -Patch1089: 1089-target-i386-Add-new-CPU-model-GraniteRapids.patch -Patch1090: 1090-target-i386-Add-support-for-AMX-COMPLEX-in-CPUID-enu.patch -Patch1091: 1091-target-i386-Add-new-CPU-model-SierraForest.patch -Patch1092: 1092-target-i386-Export-RFDS-bit-to-guests.patch -Patch1093: 1093-target-i386-Add-few-security-fix-bits-in-ARCH_CAPABI.patch -Patch1094: 1094-target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch -Patch1095: 1095-ebpf-replace-deprecated-bpf_program__set_socket_filt.patch -Patch1096: 1096-target-i386-Export-MSR_ARCH_CAPABILITIES-bits-to-gue.patch +# For RHEL-52611 - CVE-2024-7409 virt:rhel/qemu-kvm: Denial of Service via Improper Synchronization in QEMU NBD Server During Socket Closure [rhel-8.10.z] +Patch361: kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch +# For RHEL-52611 - CVE-2024-7409 virt:rhel/qemu-kvm: Denial of Service via Improper Synchronization in QEMU NBD Server During Socket Closure [rhel-8.10.z] +Patch362: kvm-iotests-test-NBD-TLS-iothread.patch +# For RHEL-52611 - CVE-2024-7409 virt:rhel/qemu-kvm: Denial of Service via Improper Synchronization in QEMU NBD Server During Socket Closure [rhel-8.10.z] +Patch363: kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch BuildRequires: wget BuildRequires: rpm-build @@ -1099,10 +994,6 @@ BuildRequires: pkgconfig(gbm) BuildRequires: perl-Test-Harness -%if %{user_static} -BuildRequires: glibc-static pcre-static glib2-static zlib-static -%endif - Requires: qemu-kvm-core = %{epoch}:%{version}-%{release} Requires: qemu-kvm-docs = %{epoch}:%{version}-%{release} %rhev_ma_conflicts qemu-kvm @@ -1183,7 +1074,7 @@ Requires(postun): systemd-units Requires: seabios-bin >= 1.10.2-1 Requires: sgabios-bin %endif -%ifnarch aarch64 s390x loongarch64 +%ifnarch aarch64 s390x Requires: seavgabios-bin >= 1.12.0-3 Requires: ipxe-roms-qemu >= 20170123-1 %endif @@ -1315,15 +1206,6 @@ This package provides usbredir support. %endif -%if %{user_static} -%package -n qemu-user-static -Summary: QEMU user mode emulation of qemu targets static build -%description -n qemu-user-static -This package provides the user mode emulation of qemu targets built as -static binaries -%endif - - %prep %setup -q -n qemu-%{version}%{?rcstr} # Remove slirp content in scratchbuilds because it's being applyed as a patch @@ -1331,9 +1213,6 @@ rm -fr slirp mkdir slirp %autopatch -p1 -cp %{SOURCE41} ./pc-bios/ -f -cp %{SOURCE42} ./pc-bios/ -f - %global qemu_kvm_build qemu_kvm_build mkdir -p %{qemu_kvm_build} @@ -1342,9 +1221,6 @@ cp -f %{SOURCE38} tests/data/acpi/q35/FACP.slic cp -f %{SOURCE39} tests/data/acpi/q35/SSDT.dimmpxm cp -f %{SOURCE40} tests/data/acpi/virt/SSDT.memhp -%global static_builddir static_builddir -mkdir -p %{static_builddir} - %build %global buildarch %{kvm_target}-softmmu @@ -1620,25 +1496,6 @@ gcc %{SOURCE35} $RPM_OPT_FLAGS $RPM_LD_FLAGS -o udev-kvm-check popd -%if %{user_static} -pushd %{static_builddir} -# add more targets here when necessary -%define static_targets aarch64-linux-user - -../configure \ - %{disable_everything} \ - --enable-docs \ - --enable-attr \ - --enable-tcg \ - --enable-linux-user \ - --target-list=%{static_targets} \ - --static - -make -j - -popd -%endif - %install pushd %{qemu_kvm_build} %define _udevdir %(pkg-config --variable=udevdir udev) @@ -1825,8 +1682,6 @@ rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/opensbi-riscv64-virt-fw_jump.bin rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/opensbi-riscv64-generic-fw_dynamic.* rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/qemu-nsis.bmp rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/npcm7xx_bootrom.bin -rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/loongarch_bios.bin -rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/loongarch_vars.bin rm -rf ${RPM_BUILD_ROOT}%{_libdir}/qemu-kvm/ui-spice-app.so @@ -1842,11 +1697,6 @@ rm -rf ${RPM_BUILD_ROOT}%{_mandir}/man1/virtfs-proxy-helper* rm -rf ${RPM_BUILD_ROOT}%{_libdir}/qemu-kvm/hw-s390x-virtio-gpu-ccw.so %endif -%ifarch loongarch64 - install -m 0644 pc-bios/loongarch_bios.bin $RPM_BUILD_ROOT%{_datadir}/%{name}/ - install -m 0644 pc-bios/loongarch_vars.bin $RPM_BUILD_ROOT%{_datadir}/%{name}/ -%endif - %ifnarch x86_64 rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/kvmvapic.bin rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/linuxboot.bin @@ -1947,27 +1797,11 @@ rm -rf $RPM_BUILD_ROOT%{qemudocdir}/specs popd -%if %{user_static} -# Install qemu-user-static -mkdir -p $RPM_BUILD_ROOT%{_bindir}/ -pushd %{static_builddir} -for src in qemu-*\.*; do - rm -rf $src -done - -for src in qemu-*; do - mv $src $RPM_BUILD_ROOT%{_bindir}/$(basename $src)-static -done -popd -%endif - %check -%ifnarch loongarch64 pushd %{qemu_kvm_build} echo "Testing qemu-kvm-build" export DIFF=diff; make check V=1 popd -%endif %post -n qemu-kvm-common %systemd_post ksm.service @@ -2062,7 +1896,7 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_unitdir}/ksmtuned.service %{_sbindir}/ksmtuned %{_udevdir}/udev-kvm-check -%{_udevrulesdir}/81-kvm-anolis.rules +%{_udevrulesdir}/81-kvm-rhel.rules %ghost %{_sysconfdir}/kvm %config(noreplace) %{_sysconfdir}/ksmtuned.conf %dir %{_sysconfdir}/%{name} @@ -2088,10 +1922,6 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_datadir}/%{name}/s390-ccw.img %{_datadir}/%{name}/s390-netboot.img %endif -%ifarch loongarch64 - %{_datadir}/%{name}/loongarch_bios.bin - %{_datadir}/%{name}/loongarch_vars.bin -%endif %ifnarch aarch64 s390x %{_datadir}/%{name}/vgabios.bin %{_datadir}/%{name}/vgabios-cirrus.bin @@ -2113,7 +1943,7 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %ifnarch s390x %{_libdir}/%{name}/hw-display-virtio-gpu-pci-gl.so %endif -%ifarch x86_64 %{power64} loongarch64 +%ifarch x86_64 %{power64} %{_libdir}/%{name}/hw-display-virtio-vga-gl.so %endif %{_libdir}/%{name}/accel-qtest-%{kvm_target}.so @@ -2206,7 +2036,7 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_libdir}/qemu-kvm/audio-spice.so %{_libdir}/qemu-kvm/ui-spice-core.so %{_libdir}/qemu-kvm/chardev-spice.so -%ifarch x86_64 loongarch64 +%ifarch x86_64 %{_libdir}/qemu-kvm/hw-display-qxl.so %endif %endif @@ -2222,53 +2052,14 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_libdir}/qemu-kvm/hw-usb-redirect.so %endif -%if %{user_static} -%files -n qemu-user-static -%{_bindir}/qemu-aarch64-static -%endif %changelog -* Wed Sep 11 2024 Quanxian Wang - 6.2.0-52.0.2 -- Intel-SIG: Supprt new SPR models - -* Wed Aug 28 2024 Jacob Wang - 6.2.0-52.0.1 -- Adjust limit for virtiofsd minor version -- Add loongarch supporti (lixianglai@loongson.cn) -- Add package qemu-user-static (fuyuan.wh@alibaba-inc.com) -- Modify-smbios-option-lack-and-Modify-the-maximum-num.patch (lixianglai@loongson.cn) -- rename-kvm_msr_buf-with-kvm_csr_buf.patch (lixianglai@loongson.cn) -- code-cleanup-for-loongarch-kvm.patch (lixianglai@loongson.cn) -- Support-TPM.patch (lixianglai@loongson.cn) -- kvm-csr-save-and-restore-optimization.patch (lixianglai@loongson.cn) -- address-space-code-cleanup-on-7A-virt-machine.patch (lixianglai@loongson.cn) -- Fix-irq-routing-and-fpu-option-to-compat-with-kernel.patch (lixianglai@loongson.cn) -- Support-vfio-config.patch (lixianglai@loongson.cn) -- pass-to-make-check.patch (lixianglai@loongson.cn) -- fixup-can-t-find-cpu-type.patch (lixianglai@loongson.cn) -- fix-smbios-type4-info-for-numa-support.patch (lixianglai@loongson.cn) -- Fix-smp.cores-value.patch (lixianglai@loongson.cn) -- Add-lbt-support-for-kvm.patch (lixianglai@loongson.cn) -- Modify-the-ioctl-command-of-kvm.patch (lixianglai@loongson.cn) -- Add-usb-storage-config-for-loongarch.patch (zhaotianrui@loongson.c) -- Add-loongarch-into-QEMU_ARCH_VIRTIO_PCI-to-support-q.patch (zhaotianrui@loongson.c) -- Fix-host-architecture-macro-of-LoongArch-to-HOST_LOO.patch (zhaotianrui@loongson.c) -- Fix-LoongArch-KVM-header-macros.patch (zhaotianrui@loongson.c) -- loongarch: Fixed the issue where qemu specifies the boot order (lixianglai@loongson.cn) -- 0001-anolis-csv-i386-add-CSV-context.patch (jiangxin@hygon.cn) -- 0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch (jiangxin@hygon.cn) -- 0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch (jiangxin@hygon.cn) -- 0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch (jiangxin@hygon.cn) -- 0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch (jiangxin@hygon.cn) -- 0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch (jiangxin@hygon.cn) -- 0007-anolis-target-i386-csv-load-initial-image-to-private.patch (jiangxin@hygon.cn) -- 0008-anolis-vga-force-full-update-for-CSV-guest.patch (jiangxin@hygon.cn) - (Hygon CSV3 feature) -- Support Hygon CSV/CSV2 live migration, CSV2 reboot (hanliyang@hygon.cn) -- Support CSV3 live migration (jiangxin@hygon.cn) -- Support reuse ASID for CSV guests (hanliyang@hygon.cn) -- Support tkm key isolation (xiongmengbiao@hygon.cn) -- Add Hygon Dhyana-v3 and Dharma CPU model (zhouyanjing@hygon.cn) -- Intel-SIG: Supprt Intel SPR/GNR/SRF new ISAs and cpu models (quanxian.wang@intel.com) +* Thu Sep 05 2024 Miroslav Rezanina - 6.2.0-53.el8 +- kvm-nbd-server-Favor-qemu_aio_context-over-iohandler-con.patch [RHEL-52611] +- kvm-iotests-test-NBD-TLS-iothread.patch [RHEL-52611] +- kvm-nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch [RHEL-52611] +- Resolves: RHEL-52611 + (CVE-2024-7409 virt:rhel/qemu-kvm: Denial of Service via Improper Synchronization in QEMU NBD Server During Socket Closure [rhel-8.10.z]) * Wed Aug 21 2024 Miroslav Rezanina - 6.2.0-52.el8 - kvm-nbd-server-Plumb-in-new-args-to-nbd_client_add.patch [RHEL-52611] diff --git a/rename-kvm_msr_buf-with-kvm_csr_buf.patch b/rename-kvm_msr_buf-with-kvm_csr_buf.patch deleted file mode 100644 index 6d13b6e9eb721d927954fccfb516e9eaec82076f..0000000000000000000000000000000000000000 --- a/rename-kvm_msr_buf-with-kvm_csr_buf.patch +++ /dev/null @@ -1,638 +0,0 @@ -From 25f1ae50858b5c580336321e18ef0029d3dec922 Mon Sep 17 00:00:00 2001 -From: lixianglai -Date: Mon, 29 May 2023 05:57:27 -0400 -Subject: [PATCH 11/28] rename kvm_msr_buf with kvm_csr_buf. - -Signed-off-by: lixianglai ---- - target/loongarch64/cpu.h | 2 +- - target/loongarch64/kvm.c | 564 +++++++++++++++++++-------------------- - 2 files changed, 283 insertions(+), 283 deletions(-) - -diff --git a/target/loongarch64/cpu.h b/target/loongarch64/cpu.h -index 10facb3b7..078556a22 100644 ---- a/target/loongarch64/cpu.h -+++ b/target/loongarch64/cpu.h -@@ -200,7 +200,7 @@ struct LOONGARCHCPU { - VMChangeStateEntry *cpuStateEntry; - int32_t node_id; /* NUMA node this CPU belongs to */ - int32_t core_id; -- struct kvm_msrs *kvm_msr_buf; -+ struct kvm_msrs *kvm_csr_buf; - /* 'compatible' string for this CPU for Linux device trees */ - const char *dtb_compatible; - }; -diff --git a/target/loongarch64/kvm.c b/target/loongarch64/kvm.c -index 404a605eb..b5c655812 100644 ---- a/target/loongarch64/kvm.c -+++ b/target/loongarch64/kvm.c -@@ -31,7 +31,7 @@ - #define DEBUG_KVM 0 - /* A 16384-byte buffer can hold the 8-byte kvm_msrs header, plus - * 2047 kvm_msr_entry structs */ --#define MSR_BUF_SIZE 16384 -+#define CSR_BUF_SIZE 16384 - - #define DPRINTF(fmt, ...) \ - do { if (DEBUG_KVM) { fprintf(stderr, fmt, ## __VA_ARGS__); } } while (0) -@@ -101,7 +101,7 @@ int kvm_arch_init_vcpu(CPUState *cs) - int ret = 0; - - cpu->cpuStateEntry = qemu_add_vm_change_state_handler(kvm_loongarch_update_state, cs); -- cpu->kvm_msr_buf = g_malloc0(MSR_BUF_SIZE); -+ cpu->kvm_csr_buf = g_malloc0(CSR_BUF_SIZE); - DPRINTF("%s\n", __func__); - return ret; - } -@@ -111,15 +111,15 @@ int kvm_arch_destroy_vcpu(CPUState *cs) - return 0; - } - --static void kvm_msr_buf_reset(LOONGARCHCPU *cpu) -+static void kvm_csr_buf_reset(LOONGARCHCPU *cpu) - { -- memset(cpu->kvm_msr_buf, 0, MSR_BUF_SIZE); -+ memset(cpu->kvm_csr_buf, 0, CSR_BUF_SIZE); - } - --static void kvm_msr_entry_add(LOONGARCHCPU *cpu, uint32_t index, uint64_t value) -+static void kvm_csr_entry_add(LOONGARCHCPU *cpu, uint32_t index, uint64_t value) - { -- struct kvm_msrs *msrs = cpu->kvm_msr_buf; -- void *limit = ((void *)msrs) + MSR_BUF_SIZE; -+ struct kvm_msrs *msrs = cpu->kvm_csr_buf; -+ void *limit = ((void *)msrs) + CSR_BUF_SIZE; - struct kvm_csr_entry *entry = &msrs->entries[msrs->ncsrs]; - - assert((void *)(entry + 1) <= limit); -@@ -767,144 +767,144 @@ static int kvm_loongarch_put_csr_registers(CPUState *cs, int level) - - (void)level; - -- kvm_msr_buf_reset(cpu); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CRMD, env->CSR_CRMD); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRMD, env->CSR_PRMD); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_EUEN, env->CSR_EUEN); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MISC, env->CSR_MISC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ECFG, env->CSR_ECFG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ESTAT, env->CSR_ESTAT); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERA, env->CSR_ERA); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADV, env->CSR_BADV); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADI, env->CSR_BADI); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_EEPN, env->CSR_EEPN); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, env->CSR_TLBIDX); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, env->CSR_TLBEHI); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, env->CSR_TLBELO0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, env->CSR_TLBELO1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GTLBC, env->CSR_GTLBC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TRGP, env->CSR_TRGP); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ASID, env->CSR_ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDL, env->CSR_PGDL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDH, env->CSR_PGDH); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGD, env->CSR_PGD); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, env->CSR_PWCTL0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, env->CSR_PWCTL1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, env->CSR_STLBPGSIZE); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_RVACFG, env->CSR_RVACFG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CPUID, env->CSR_CPUID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, env->CSR_PRCFG1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, env->CSR_PRCFG2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, env->CSR_PRCFG3); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS0, env->CSR_KS0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS1, env->CSR_KS1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS2, env->CSR_KS2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS3, env->CSR_KS3); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS4, env->CSR_KS4); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS5, env->CSR_KS5); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS6, env->CSR_KS6); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS7, env->CSR_KS7); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TMID, env->CSR_TMID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CNTC, env->CSR_CNTC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, env->CSR_TINTCLR); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GSTAT, env->CSR_GSTAT); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCFG, env->CSR_GCFG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GINTC, env->CSR_GINTC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCNTC, env->CSR_GCNTC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, env->CSR_LLBCTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, env->CSR_IMPCTL1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, env->CSR_IMPCTL2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GNMI, env->CSR_GNMI); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, env->CSR_TLBRENT); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, env->CSR_TLBRBADV); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, env->CSR_TLBRERA); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, env->CSR_TLBRSAVE); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, env->CSR_TLBRELO0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, env->CSR_TLBRELO1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, env->CSR_TLBREHI); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, env->CSR_TLBRPRMD); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, env->CSR_ERRCTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, env->CSR_ERRINFO); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, env->CSR_ERRINFO1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRENT, env->CSR_ERRENT); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRERA, env->CSR_ERRERA); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, env->CSR_ERRSAVE); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CTAG, env->CSR_CTAG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, env->CSR_DMWIN0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, env->CSR_DMWIN1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, env->CSR_DMWIN2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, env->CSR_DMWIN3); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, env->CSR_PERFCTRL0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, env->CSR_PERFCNTR0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, env->CSR_PERFCTRL1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, env->CSR_PERFCNTR1); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, env->CSR_PERFCTRL2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, env->CSR_PERFCNTR2); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, env->CSR_PERFCTRL3); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, env->CSR_PERFCNTR3); -+ kvm_csr_buf_reset(cpu); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CRMD, env->CSR_CRMD); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRMD, env->CSR_PRMD); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EUEN, env->CSR_EUEN); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MISC, env->CSR_MISC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ECFG, env->CSR_ECFG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ESTAT, env->CSR_ESTAT); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERA, env->CSR_ERA); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADV, env->CSR_BADV); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADI, env->CSR_BADI); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EEPN, env->CSR_EEPN); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, env->CSR_TLBIDX); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, env->CSR_TLBEHI); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, env->CSR_TLBELO0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, env->CSR_TLBELO1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GTLBC, env->CSR_GTLBC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TRGP, env->CSR_TRGP); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ASID, env->CSR_ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDL, env->CSR_PGDL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDH, env->CSR_PGDH); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGD, env->CSR_PGD); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, env->CSR_PWCTL0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, env->CSR_PWCTL1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, env->CSR_STLBPGSIZE); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_RVACFG, env->CSR_RVACFG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CPUID, env->CSR_CPUID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, env->CSR_PRCFG1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, env->CSR_PRCFG2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, env->CSR_PRCFG3); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS0, env->CSR_KS0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS1, env->CSR_KS1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS2, env->CSR_KS2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS3, env->CSR_KS3); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS4, env->CSR_KS4); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS5, env->CSR_KS5); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS6, env->CSR_KS6); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS7, env->CSR_KS7); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TMID, env->CSR_TMID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CNTC, env->CSR_CNTC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, env->CSR_TINTCLR); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GSTAT, env->CSR_GSTAT); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCFG, env->CSR_GCFG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GINTC, env->CSR_GINTC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCNTC, env->CSR_GCNTC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, env->CSR_LLBCTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, env->CSR_IMPCTL1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, env->CSR_IMPCTL2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GNMI, env->CSR_GNMI); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, env->CSR_TLBRENT); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, env->CSR_TLBRBADV); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, env->CSR_TLBRERA); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, env->CSR_TLBRSAVE); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, env->CSR_TLBRELO0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, env->CSR_TLBRELO1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, env->CSR_TLBREHI); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, env->CSR_TLBRPRMD); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, env->CSR_ERRCTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, env->CSR_ERRINFO); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, env->CSR_ERRINFO1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRENT, env->CSR_ERRENT); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRERA, env->CSR_ERRERA); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, env->CSR_ERRSAVE); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CTAG, env->CSR_CTAG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, env->CSR_DMWIN0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, env->CSR_DMWIN1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, env->CSR_DMWIN2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, env->CSR_DMWIN3); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, env->CSR_PERFCTRL0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, env->CSR_PERFCNTR0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, env->CSR_PERFCTRL1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, env->CSR_PERFCNTR1); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, env->CSR_PERFCTRL2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, env->CSR_PERFCNTR2); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, env->CSR_PERFCTRL3); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, env->CSR_PERFCNTR3); - - /* debug */ -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPC, env->CSR_MWPC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPS, env->CSR_MWPS); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, env->CSR_DB0ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, env->CSR_DB0MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, env->CSR_DB0CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, env->CSR_DB0ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, env->CSR_DB1ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, env->CSR_DB1MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, env->CSR_DB1CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, env->CSR_DB1ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, env->CSR_DB2ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, env->CSR_DB2MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, env->CSR_DB2CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, env->CSR_DB2ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, env->CSR_DB3ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, env->CSR_DB3MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, env->CSR_DB3CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, env->CSR_DB3ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPC, env->CSR_FWPC); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPS, env->CSR_FWPS); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, env->CSR_IB0ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, env->CSR_IB0MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, env->CSR_IB0CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, env->CSR_IB0ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, env->CSR_IB1ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, env->CSR_IB1MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, env->CSR_IB1CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, env->CSR_IB1ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, env->CSR_IB2ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, env->CSR_IB2MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, env->CSR_IB2CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, env->CSR_IB2ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, env->CSR_IB3ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, env->CSR_IB3MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, env->CSR_IB3CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, env->CSR_IB3ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, env->CSR_IB4ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, env->CSR_IB4MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, env->CSR_IB4CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, env->CSR_IB4ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, env->CSR_IB5ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, env->CSR_IB5MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, env->CSR_IB5CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, env->CSR_IB5ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, env->CSR_IB6ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, env->CSR_IB6MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, env->CSR_IB6CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, env->CSR_IB6ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, env->CSR_IB7ADDR); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, env->CSR_IB7MASK); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, env->CSR_IB7CTL); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, env->CSR_IB7ASID); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DEBUG, env->CSR_DEBUG); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DERA, env->CSR_DERA); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DESAVE, env->CSR_DESAVE); -- -- ret = kvm_vcpu_ioctl(cs, KVM_SET_MSRS, cpu->kvm_msr_buf); -- if (ret < cpu->kvm_msr_buf->ncsrs) { -- struct kvm_csr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPC, env->CSR_MWPC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPS, env->CSR_MWPS); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, env->CSR_DB0ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, env->CSR_DB0MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, env->CSR_DB0CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, env->CSR_DB0ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, env->CSR_DB1ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, env->CSR_DB1MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, env->CSR_DB1CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, env->CSR_DB1ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, env->CSR_DB2ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, env->CSR_DB2MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, env->CSR_DB2CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, env->CSR_DB2ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, env->CSR_DB3ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, env->CSR_DB3MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, env->CSR_DB3CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, env->CSR_DB3ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPC, env->CSR_FWPC); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPS, env->CSR_FWPS); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, env->CSR_IB0ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, env->CSR_IB0MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, env->CSR_IB0CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, env->CSR_IB0ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, env->CSR_IB1ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, env->CSR_IB1MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, env->CSR_IB1CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, env->CSR_IB1ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, env->CSR_IB2ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, env->CSR_IB2MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, env->CSR_IB2CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, env->CSR_IB2ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, env->CSR_IB3ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, env->CSR_IB3MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, env->CSR_IB3CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, env->CSR_IB3ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, env->CSR_IB4ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, env->CSR_IB4MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, env->CSR_IB4CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, env->CSR_IB4ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, env->CSR_IB5ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, env->CSR_IB5MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, env->CSR_IB5CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, env->CSR_IB5ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, env->CSR_IB6ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, env->CSR_IB6MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, env->CSR_IB6CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, env->CSR_IB6ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, env->CSR_IB7ADDR); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, env->CSR_IB7MASK); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, env->CSR_IB7CTL); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, env->CSR_IB7ASID); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DEBUG, env->CSR_DEBUG); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DERA, env->CSR_DERA); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DESAVE, env->CSR_DESAVE); -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_SET_MSRS, cpu->kvm_csr_buf); -+ if (ret < cpu->kvm_csr_buf->ncsrs) { -+ struct kvm_csr_entry *e = &cpu->kvm_csr_buf->entries[ret]; - printf("error: failed to set CSR 0x%" PRIx32 " to 0x%" PRIx64"\n", - (uint32_t)e->index, (uint64_t)e->data); - } -@@ -935,147 +935,147 @@ static int kvm_loongarch_get_csr_registers(CPUState *cs) - LOONGARCHCPU *cpu = LOONGARCH_CPU(cs); - CPULOONGARCHState *env = &cpu->env; - int ret = 0, i; -- struct kvm_csr_entry *csrs = cpu->kvm_msr_buf->entries; -- -- kvm_msr_buf_reset(cpu); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CRMD, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRMD, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_EUEN, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MISC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ECFG, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ESTAT, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERA, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADV, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_BADI, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_EEPN, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GTLBC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TRGP, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGDH, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PGD, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_RVACFG, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CPUID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS3, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS4, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS5, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS6, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_KS7, 0); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TMID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CNTC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GSTAT, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCFG, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GINTC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GCNTC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_GNMI, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRENT, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRERA, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_CTAG, 0); -- -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, 0); -+ struct kvm_csr_entry *csrs = cpu->kvm_csr_buf->entries; -+ -+ kvm_csr_buf_reset(cpu); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CRMD, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRMD, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EUEN, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MISC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ECFG, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ESTAT, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERA, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADV, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_BADI, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_EEPN, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBIDX, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBEHI, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBELO1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GTLBC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TRGP, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGDH, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PGD, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PWCTL1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_STLBPGSIZE, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_RVACFG, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CPUID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PRCFG3, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS3, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS4, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS5, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS6, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_KS7, 0); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TMID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CNTC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TINTCLR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GSTAT, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCFG, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GINTC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GCNTC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_LLBCTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IMPCTL2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_GNMI, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRENT, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRBADV, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRERA, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRSAVE, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRELO1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBREHI, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_TLBRPRMD, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRCTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRINFO1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRENT, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRERA, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_ERRSAVE, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_CTAG, 0); -+ -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DMWIN3, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR0, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR1, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR2, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCTRL3, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_PERFCNTR3, 0); - - /* debug */ -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_MWPS, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPC, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_FWPS, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DEBUG, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DERA, 0); -- kvm_msr_entry_add(cpu, LOONGARCH_CSR_DESAVE, 0); -- -- ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, cpu->kvm_msr_buf); -- if (ret < cpu->kvm_msr_buf->ncsrs) { -- struct kvm_csr_entry *e = &cpu->kvm_msr_buf->entries[ret]; -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_MWPS, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB0ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB1ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB2ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DB3ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPC, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_FWPS, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB0ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB1ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB2ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB3ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB4ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB5ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB6ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ADDR, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7MASK, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7CTL, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_IB7ASID, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DEBUG, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DERA, 0); -+ kvm_csr_entry_add(cpu, LOONGARCH_CSR_DESAVE, 0); -+ -+ ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, cpu->kvm_csr_buf); -+ if (ret < cpu->kvm_csr_buf->ncsrs) { -+ struct kvm_csr_entry *e = &cpu->kvm_csr_buf->entries[ret]; - printf("error: failed to get CSR 0x%" PRIx32"\n", - (uint32_t)e->index); - } --- -2.43.5 -