diff --git a/accel-kvm-Extract-common-KVM-vCPU-creation-parking-c-sync-upstream.patch b/accel-kvm-Extract-common-KVM-vCPU-creation-parking-c-sync-upstream.patch new file mode 100644 index 0000000000000000000000000000000000000000..43c53ab4029646ebc22ab7e7d511a263d101c25c --- /dev/null +++ b/accel-kvm-Extract-common-KVM-vCPU-creation-parking-c-sync-upstream.patch @@ -0,0 +1,236 @@ +From 2464d0d6115e1794468ff455e3acdb98e0d71a31 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:56 +0100 +Subject: [PATCH 62/78] accel/kvm: Extract common KVM vCPU {creation,parking} + code + +KVM vCPU creation is done once during the vCPU realization when Qemu vCPU thread +is spawned. This is common to all the architectures as of now. + +Hot-unplug of vCPU results in destruction of the vCPU object in QOM but the +corresponding KVM vCPU object in the Host KVM is not destroyed as KVM doesn't +support vCPU removal. Therefore, its representative KVM vCPU object/context in +Qemu is parked. + +Refactor architecture common logic so that some APIs could be reused by vCPU +Hotplug code of some architectures likes ARM, Loongson etc. Update new/old APIs +with trace events. New APIs qemu_{create,park,unpark}_vcpu() can be externally +called. No functional change is intended here. + +Signed-off-by: Salil Mehta +Reviewed-by: Gavin Shan +Tested-by: Vishnu Pajjuri +Reviewed-by: Jonathan Cameron +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Shaoqin Huang +Reviewed-by: Vishnu Pajjuri +Reviewed-by: Nicholas Piggin +Tested-by: Zhao Liu +Reviewed-by: Zhao Liu +Reviewed-by: Harsh Prateek Bora +Reviewed-by: Igor Mammedov +Message-Id: <20240716111502.202344-2-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + accel/kvm/kvm-all.c | 71 +++++++++++++++++++++--------------------- + accel/kvm/trace-events | 11 +++++++ + include/sysemu/kvm.h | 27 ++++++++++++++-- + 3 files changed, 71 insertions(+), 38 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 8077630825..8dea8f98bb 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -141,7 +141,6 @@ static QemuMutex kml_slots_lock; + #define kvm_slots_unlock() qemu_mutex_unlock(&kml_slots_lock) + + static void kvm_slot_init_dirty_bitmap(KVMSlot *mem); +-static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id); + + static inline void kvm_resample_fd_remove(int gsi) + { +@@ -334,39 +333,57 @@ void kvm_park_vcpu(CPUState *cpu) + { + struct KVMParkedVcpu *vcpu; + ++ trace_kvm_park_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); ++ + vcpu = g_malloc0(sizeof(*vcpu)); + vcpu->vcpu_id = kvm_arch_vcpu_id(cpu); + vcpu->kvm_fd = cpu->kvm_fd; + QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node); + } + ++int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id) ++{ ++ struct KVMParkedVcpu *cpu; ++ int kvm_fd = -ENOENT; ++ ++ QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) { ++ if (cpu->vcpu_id == vcpu_id) { ++ QLIST_REMOVE(cpu, node); ++ kvm_fd = cpu->kvm_fd; ++ g_free(cpu); ++ } ++ } ++ ++ trace_kvm_unpark_vcpu(vcpu_id, kvm_fd > 0 ? "unparked" : "!found parked"); ++ ++ return kvm_fd; ++} ++ + int kvm_create_vcpu(CPUState *cpu) + { +- unsigned long vcpu_id = cpu->cpu_index; ++ unsigned long vcpu_id = kvm_arch_vcpu_id(cpu); + KVMState *s = kvm_state; +- int ret; +- +- DPRINTF("kvm_create_vcpu\n"); ++ int kvm_fd; + + /* check if the KVM vCPU already exist but is parked */ +- ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu)); +- if (ret > 0) { +- goto found; +- } +- +- /* create a new KVM vcpu */ +- ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id); +- if (ret < 0) { +- return ret; ++ kvm_fd = kvm_unpark_vcpu(s, vcpu_id); ++ if (kvm_fd < 0) { ++ /* vCPU not parked: create a new KVM vCPU */ ++ kvm_fd = kvm_vm_ioctl(s, KVM_CREATE_VCPU, vcpu_id); ++ if (kvm_fd < 0) { ++ error_report("KVM_CREATE_VCPU IOCTL failed for vCPU %lu", vcpu_id); ++ return kvm_fd; ++ } + } + +-found: +- cpu->vcpu_dirty = true; +- cpu->kvm_fd = ret; ++ cpu->kvm_fd = kvm_fd; + cpu->kvm_state = s; ++ cpu->vcpu_dirty = true; + cpu->dirty_pages = 0; + cpu->throttle_us_per_full = 0; + ++ trace_kvm_create_vcpu(cpu->cpu_index, vcpu_id, kvm_fd); ++ + return 0; + } + +@@ -376,7 +393,7 @@ static int do_kvm_destroy_vcpu(CPUState *cpu) + long mmap_size; + int ret = 0; + +- DPRINTF("kvm_destroy_vcpu\n"); ++ trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); + + ret = kvm_arch_destroy_vcpu(cpu); + if (ret < 0) { +@@ -415,24 +432,6 @@ void kvm_destroy_vcpu(CPUState *cpu) + } + } + +-static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id) +-{ +- struct KVMParkedVcpu *cpu; +- +- QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) { +- if (cpu->vcpu_id == vcpu_id) { +- int kvm_fd; +- +- QLIST_REMOVE(cpu, node); +- kvm_fd = cpu->kvm_fd; +- g_free(cpu); +- return kvm_fd; +- } +- } +- +- return -1; +-} +- + int kvm_init_vcpu(CPUState *cpu, Error **errp) + { + KVMState *s = kvm_state; +diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events +index 399aaeb0ec..9c880fdcf4 100644 +--- a/accel/kvm/trace-events ++++ b/accel/kvm/trace-events +@@ -9,6 +9,10 @@ kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p" + kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s" + kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s" + kvm_init_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu" ++kvm_create_vcpu(int cpu_index, unsigned long arch_cpu_id, int kvm_fd) "index: %d, id: %lu, kvm fd: %d" ++kvm_destroy_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu" ++kvm_park_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu" ++kvm_unpark_vcpu(unsigned long arch_cpu_id, const char *msg) "id: %lu %s" + kvm_irqchip_commit_routes(void) "" + kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d" + kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d" +@@ -26,3 +30,10 @@ kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"P + kvm_dirty_ring_reaper_kick(const char *reason) "%s" + kvm_dirty_ring_flush(int finished) "%d" + ++kvm_failed_get_vcpu_mmap_size(void) "" ++kvm_cpu_exec(void) "" ++kvm_interrupt_exit_request(void) "" ++kvm_io_window_exit(void) "" ++kvm_run_exit_system_event(int cpu_index, uint32_t event_type) "cpu_index %d, system_even_type %"PRIu32 ++kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s" ++kvm_memory_fault(uint64_t start, uint64_t size, uint64_t flags) "start 0x%" PRIx64 " size 0x%" PRIx64 " flags 0x%" PRIx64 +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 31af5f0e24..7ffb5e4992 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -319,6 +319,31 @@ int kvm_create_device(KVMState *s, uint64_t type, bool test); + */ + bool kvm_device_supported(int vmfd, uint64_t type); + ++/** ++ * kvm_create_vcpu - Gets a parked KVM vCPU or creates a KVM vCPU ++ * @cpu: QOM CPUState object for which KVM vCPU has to be fetched/created. ++ * ++ * @returns: 0 when success, errno (<0) when failed. ++ */ ++int kvm_create_vcpu(CPUState *cpu); ++ ++/** ++ * kvm_park_vcpu - Park QEMU KVM vCPU context ++ * @cpu: QOM CPUState object for which QEMU KVM vCPU context has to be parked. ++ * ++ * @returns: none ++ */ ++void kvm_park_vcpu(CPUState *cpu); ++ ++/** ++ * kvm_unpark_vcpu - unpark QEMU KVM vCPU context ++ * @s: KVM State ++ * @vcpu_id: Architecture vCPU ID of the parked vCPU ++ * ++ * @returns: KVM fd ++ */ ++int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id); ++ + /* Arch specific hooks */ + + extern const KVMCapabilityInfo kvm_arch_required_capabilities[]; +@@ -440,8 +465,6 @@ void kvm_set_sigmask_len(KVMState *s, unsigned int sigmask_len); + + int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr, + hwaddr *phys_addr); +-int kvm_create_vcpu(CPUState *cpu); +-void kvm_park_vcpu(CPUState *cpu); + + #endif /* NEED_CPU_H */ + +-- +2.39.1 + diff --git a/accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch b/accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c138ff4e199aa774f4dbf83548874606165d6cc --- /dev/null +++ b/accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch @@ -0,0 +1,46 @@ +From 9bbc73e18d36d75c5dd842e478ed1f1b47ed4222 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 1 Aug 2024 10:15:03 +0100 +Subject: [PATCH 68/78] accel/kvm/kvm-all: Fixes the missing break in vCPU + unpark logic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Loop should exit prematurely on successfully finding out the parked vCPU (struct +KVMParkedVcpu) in the 'struct KVMState' maintained 'kvm_parked_vcpus' list of +parked vCPUs. + +Fixes: Coverity CID 1558552 +Fixes: 08c3286822 ("accel/kvm: Extract common KVM vCPU {creation,parking} code") +Reported-by: Peter Maydell +Signed-off-by: Salil Mehta +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Gavin Shan +Reviewed-by: Zhao Liu +Reviewed-by: Igor Mammedov +Message-id: 20240725145132.99355-1-salil.mehta@huawei.com +Suggested-by: Peter Maydell +Message-ID: +Signed-off-by: Salil Mehta +Signed-off-by: Peter Maydell +Signed-off-by: Xianglai Li +--- + accel/kvm/kvm-all.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 8dea8f98bb..79d5671841 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -351,6 +351,7 @@ int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id) + QLIST_REMOVE(cpu, node); + kvm_fd = cpu->kvm_fd; + g_free(cpu); ++ break; + } + } + +-- +2.39.1 + diff --git a/fix-compile-error-on-loongarch.patch b/fix-compile-error-on-loongarch.patch new file mode 100644 index 0000000000000000000000000000000000000000..62a75f8bdfc19697b4126611b17af573b6f81936 --- /dev/null +++ b/fix-compile-error-on-loongarch.patch @@ -0,0 +1,27 @@ +From 0826efefea34a6fb6e17502f3a293572f109a261 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Thu, 5 Dec 2024 14:18:01 +0800 +Subject: [PATCH] fix compile error on loongarch + +add cpu.h in loongarch_ipi.c + +Signed-off-by: Xianglai Li +--- + hw/intc/loongarch_ipi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c +index e228669aa5..630bcb14ea 100644 +--- a/hw/intc/loongarch_ipi.c ++++ b/hw/intc/loongarch_ipi.c +@@ -15,6 +15,7 @@ + #include "exec/address-spaces.h" + #include "hw/loongarch/virt.h" + #include "migration/vmstate.h" ++#include "target/loongarch/cpu.h" + #include "target/loongarch/internals.h" + #include "trace.h" + +-- +2.39.1 + diff --git a/gdbstub-Add-helper-function-to-unregister-GDB-regist.patch b/gdbstub-Add-helper-function-to-unregister-GDB-regist.patch new file mode 100644 index 0000000000000000000000000000000000000000..395816ac61816a72f887e1cbcc45e39092053613 --- /dev/null +++ b/gdbstub-Add-helper-function-to-unregister-GDB-regist.patch @@ -0,0 +1,87 @@ +From 7754cf384417295dc74add4e774c506d751671a9 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:15:02 +0100 +Subject: [PATCH 67/78] gdbstub: Add helper function to unregister GDB register + space + +Add common function to help unregister the GDB register space. This shall be +done in context to the CPU unrealization. + +Note: These are common functions exported to arch specific code. For example, +for ARM this code is being referred in associated arch specific patch-set: + +Link: https://lore.kernel.org/qemu-devel/20230926103654.34424-1-salil.mehta@huawei.com/ + +Signed-off-by: Salil Mehta +Tested-by: Vishnu Pajjuri +Reviewed-by: Gavin Shan +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Shaoqin Huang +Reviewed-by: Vishnu Pajjuri +Tested-by: Zhao Liu +Acked-by: Igor Mammedov +Message-Id: <20240716111502.202344-8-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + gdbstub/gdbstub.c | 7 +++++++ + hw/core/cpu-common.c | 4 ++++ + include/exec/gdbstub.h | 5 +++++ + 3 files changed, 16 insertions(+) + +diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c +index f16006d2a8..31c3dae525 100644 +--- a/gdbstub/gdbstub.c ++++ b/gdbstub/gdbstub.c +@@ -584,8 +584,15 @@ void gdb_register_coprocessor(CPUState *cpu, + + void gdb_unregister_coprocessor_all(CPUState *cpu) + { ++ /* ++ * Safe to nuke everything. GDBRegisterState::xml is static const char so ++ * it won't be freed ++ */ + g_array_free(cpu->gdb_regs, true); ++ + cpu->gdb_regs = NULL; ++ cpu->gdb_num_regs = 0; ++ cpu->gdb_num_g_regs = 0; + } + + static void gdb_process_breakpoint_remove_all(GDBProcess *p) +diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c +index 82dae51a55..e36ca2c207 100644 +--- a/hw/core/cpu-common.c ++++ b/hw/core/cpu-common.c +@@ -262,6 +262,10 @@ static void cpu_common_finalize(Object *obj) + { + CPUState *cpu = CPU(obj); + ++ /* If cleanup didn't happen in context to gdb_unregister_coprocessor_all */ ++ if (cpu->gdb_regs) { ++ g_array_free(cpu->gdb_regs, TRUE); ++ } + qemu_lockcnt_destroy(&cpu->in_ioctl_lock); + qemu_mutex_destroy(&cpu->work_mutex); + } +diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h +index d123b838c2..e2e8dff051 100644 +--- a/include/exec/gdbstub.h ++++ b/include/exec/gdbstub.h +@@ -39,6 +39,11 @@ typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg); + void gdb_register_coprocessor(CPUState *cpu, + gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg, + int num_regs, const char *xml, int g_pos); ++ ++/** ++ * gdb_unregister_coprocessor_all() - unregisters supplemental set of registers ++ * @cpu - the CPU associated with registers ++ */ + void gdb_unregister_coprocessor_all(CPUState *cpu); + + /** +-- +2.39.1 + diff --git a/hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c-sync-upstream.patch b/hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c-sync-upstream.patch new file mode 100644 index 0000000000000000000000000000000000000000..a81b5f1806e515000954cc8b82632ad2ef52ffeb --- /dev/null +++ b/hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c-sync-upstream.patch @@ -0,0 +1,49 @@ +From a8416845f721aa5ba03446b3ccf83b096b7a0d77 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:57 +0100 +Subject: [PATCH 63/78] hw/acpi: Move CPU ctrl-dev MMIO region len macro to + common header file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +CPU ctrl-dev MMIO region length could be used in ACPI GED and various other +architecture specific places. Move ACPI_CPU_HOTPLUG_REG_LEN macro to more +appropriate common header file. + +Signed-off-by: Salil Mehta +Reviewed-by: Alex Bennée +Reviewed-by: Jonathan Cameron +Reviewed-by: Gavin Shan +Reviewed-by: David Hildenbrand +Reviewed-by: Shaoqin Huang +Tested-by: Vishnu Pajjuri +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Tested-by: Zhao Liu +Reviewed-by: Zhao Liu +Reviewed-by: Igor Mammedov +Message-Id: <20240716111502.202344-3-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + include/hw/acpi/cpu.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h +index fced952152..fa5b5e5f01 100644 +--- a/include/hw/acpi/cpu.h ++++ b/include/hw/acpi/cpu.h +@@ -18,6 +18,8 @@ + #include "hw/boards.h" + #include "hw/hotplug.h" + ++#define ACPI_CPU_HOTPLUG_REG_LEN 12 ++ + typedef struct AcpiCpuStatus { + CPUState *cpu; + uint64_t arch_id; +-- +2.39.1 + diff --git a/hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho-sync-upstream.patch b/hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho-sync-upstream.patch new file mode 100644 index 0000000000000000000000000000000000000000..41bb4e97dabd2fb0c66f448cb2362301a271f883 --- /dev/null +++ b/hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho-sync-upstream.patch @@ -0,0 +1,128 @@ +From ac96f216155002d0c874ff88e301e83495093085 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:58 +0100 +Subject: [PATCH 64/78] hw/acpi: Update ACPI GED framework to support vCPU + Hotplug + +ACPI GED (as described in the ACPI 6.4 spec) uses an interrupt listed in the +_CRS object of GED to intimate OSPM about an event. Later then demultiplexes the +notified event by evaluating ACPI _EVT method to know the type of event. Use +ACPI GED to also notify the guest kernel about any CPU hot(un)plug events. + +Note, GED interface is used by many hotplug events like memory hotplug, NVDIMM +hotplug and non-hotplug events like system power down event. Each of these can +be selected using a bit in the 32 bit GED IO interface. A bit has been reserved +for the CPU hotplug event. + +ACPI CPU hotplug related initialization should only happen if ACPI_CPU_HOTPLUG +support has been enabled for particular architecture. Add cpu_hotplug_hw_init() +stub to avoid compilation break. + +Co-developed-by: Keqian Zhu +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +Reviewed-by: Jonathan Cameron +Reviewed-by: Gavin Shan +Reviewed-by: David Hildenbrand +Reviewed-by: Shaoqin Huang +Tested-by: Vishnu Pajjuri +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Vishnu Pajjuri +Tested-by: Zhao Liu +Reviewed-by: Zhao Liu +Message-Id: <20240716111502.202344-4-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Igor Mammedov +Signed-off-by: Xianglai Li +--- + docs/specs/acpi_hw_reduced_hotplug.rst | 3 ++- + hw/acpi/generic_event_device.c | 37 ++++++++++++++++++++++++++ + include/hw/acpi/generic_event_device.h | 1 + + 3 files changed, 40 insertions(+), 1 deletion(-) + +diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst +index 0bd3f9399f..3acd6fcd8b 100644 +--- a/docs/specs/acpi_hw_reduced_hotplug.rst ++++ b/docs/specs/acpi_hw_reduced_hotplug.rst +@@ -64,7 +64,8 @@ GED IO interface (4 byte access) + 0: Memory hotplug event + 1: System power down event + 2: NVDIMM hotplug event +- 3-31: Reserved ++ 3: CPU hotplug event ++ 4-31: Reserved + + **write_access:** + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 2ce7031f1a..755653dc26 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -397,6 +397,42 @@ static const VMStateDescription vmstate_acpi_ged = { + } + }; + ++static void acpi_ged_realize(DeviceState *dev, Error **errp) ++{ ++ SysBusDevice *sbd = SYS_BUS_DEVICE(dev); ++ AcpiGedState *s = ACPI_GED(dev); ++ uint32_t ged_events; ++ int i; ++ ++ ged_events = ctpop32(s->ged_event_bitmap); ++ ++ for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) { ++ uint32_t event = s->ged_event_bitmap & ged_supported_events[i]; ++ ++ if (!event) { ++ continue; ++ } ++ ++ switch (event) { ++ case ACPI_GED_CPU_HOTPLUG_EVT: ++ /* initialize CPU Hotplug related regions */ ++ memory_region_init(&s->container_cpuhp, OBJECT(dev), ++ "cpuhp container", ++ ACPI_CPU_HOTPLUG_REG_LEN); ++ sysbus_init_mmio(sbd, &s->container_cpuhp); ++ cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev), ++ &s->cpuhp_state, 0); ++ break; ++ } ++ ged_events--; ++ } ++ ++ if (ged_events) { ++ error_report("Unsupported events specified"); ++ abort(); ++ } ++} ++ + static void acpi_ged_initfn(Object *obj) + { + DeviceState *dev = DEVICE(obj); +@@ -447,6 +483,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) + dc->desc = "ACPI Generic Event Device"; + device_class_set_props(dc, acpi_ged_properties); + dc->vmsd = &vmstate_acpi_ged; ++ dc->realize = acpi_ged_realize; + + hc->plug = acpi_ged_device_plug_cb; + hc->unplug_request = acpi_ged_unplug_request_cb; +diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h +index 8ed9534c57..d1df3c12e5 100644 +--- a/include/hw/acpi/generic_event_device.h ++++ b/include/hw/acpi/generic_event_device.h +@@ -63,6 +63,7 @@ + #include "hw/acpi/cpu_hotplug.h" + #include "hw/acpi/memory_hotplug.h" + #include "hw/acpi/ghes.h" ++#include "hw/acpi/cpu.h" + #include "qom/object.h" + + #define ACPI_POWER_BUTTON_DEVICE "PWRB" +-- +2.39.1 + diff --git a/hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change-sync-upstream.patch b/hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change-sync-upstream.patch new file mode 100644 index 0000000000000000000000000000000000000000..ec7cc8f38408f8e9f3a7808ce1cd700f0822ed64 --- /dev/null +++ b/hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change-sync-upstream.patch @@ -0,0 +1,54 @@ +From 16d44ddb63becd559cc2185549c4b18d26feab60 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:15:00 +0100 +Subject: [PATCH 65/78] hw/acpi: Update CPUs AML with cpu-(ctrl)dev change + +CPUs Control device(\\_SB.PCI0) register interface for the x86 arch is IO port +based and existing CPUs AML code assumes _CRS objects would evaluate to a system +resource which describes IO Port address. But on ARM arch CPUs control +device(\\_SB.PRES) register interface is memory-mapped hence _CRS object should +evaluate to system resource which describes memory-mapped base address. Update +build CPUs AML function to accept both IO/MEMORY region spaces and accordingly +update the _CRS object. + +Co-developed-by: Keqian Zhu +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +Reviewed-by: Gavin Shan +Tested-by: Vishnu Pajjuri +Reviewed-by: Jonathan Cameron +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Shaoqin Huang +Tested-by: Zhao Liu +Reviewed-by: Igor Mammedov +Message-Id: <20240716111502.202344-6-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + hw/acpi/cpu.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index 292e1daca2..5e9093991e 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -392,11 +392,13 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + aml_name_decl("_UID", aml_string("CPU Hotplug resources"))); + aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0)); + ++ assert((rs == AML_SYSTEM_IO) || (rs == AML_SYSTEM_MEMORY)); ++ + crs = aml_resource_template(); + if (rs == AML_SYSTEM_IO) { + aml_append(crs, aml_io(AML_DECODE16, base_addr, base_addr, 1, + ACPI_CPU_HOTPLUG_REG_LEN)); +- } else { ++ } else if (rs == AML_SYSTEM_MEMORY) { + aml_append(crs, aml_memory32_fixed(base_addr, + ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE)); + } +-- +2.39.1 + diff --git a/hw-arm-virt-acpi-build.c-Migrate-SPCR-creation-to-co.patch b/hw-arm-virt-acpi-build.c-Migrate-SPCR-creation-to-co.patch new file mode 100644 index 0000000000000000000000000000000000000000..3a6851ede8c527ef3ff589c1eadd2c25d4b26dd8 --- /dev/null +++ b/hw-arm-virt-acpi-build.c-Migrate-SPCR-creation-to-co.patch @@ -0,0 +1,237 @@ +From f6b4a18ba78b1daa2a69fccfb768ec2bdcafb1d4 Mon Sep 17 00:00:00 2001 +From: Sia Jee Heng +Date: Sun, 28 Jan 2024 18:14:39 -0800 +Subject: [PATCH] hw/arm/virt-acpi-build.c: Migrate SPCR creation to common + location + +RISC-V should also generate the SPCR in a manner similar to ARM. +Therefore, instead of replicating the code, relocate this function +to the common AML build. + +Signed-off-by: Sia Jee Heng +Reviewed-by: Alistair Francis +Message-ID: <20240129021440.17640-2-jeeheng.sia@starfivetech.com> +[ Changes by AF: + - Add missing Language SPCR entry +] +Signed-off-by: Alistair Francis +Signed-off-by: Xianglai Li +--- + hw/acpi/aml-build.c | 53 +++++++++++++++++++++++++++++ + hw/arm/virt-acpi-build.c | 68 +++++++++++++++---------------------- + include/hw/acpi/acpi-defs.h | 33 ++++++++++++++++++ + include/hw/acpi/aml-build.h | 4 +++ + 4 files changed, 117 insertions(+), 41 deletions(-) + +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index 0d4994baf..3fb996c03 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -2016,6 +2016,59 @@ void build_processor_hierarchy_node(GArray *tbl, uint32_t flags, + } + } + ++void build_spcr(GArray *table_data, BIOSLinker *linker, ++ const AcpiSpcrData *f, const uint8_t rev, ++ const char *oem_id, const char *oem_table_id) ++{ ++ AcpiTable table = { .sig = "SPCR", .rev = rev, .oem_id = oem_id, ++ .oem_table_id = oem_table_id }; ++ ++ acpi_table_begin(&table, table_data); ++ /* Interface type */ ++ build_append_int_noprefix(table_data, f->interface_type, 1); ++ /* Reserved */ ++ build_append_int_noprefix(table_data, 0, 3); ++ /* Base Address */ ++ build_append_gas(table_data, f->base_addr.id, f->base_addr.width, ++ f->base_addr.offset, f->base_addr.size, ++ f->base_addr.addr); ++ /* Interrupt type */ ++ build_append_int_noprefix(table_data, f->interrupt_type, 1); ++ /* IRQ */ ++ build_append_int_noprefix(table_data, f->pc_interrupt, 1); ++ /* Global System Interrupt */ ++ build_append_int_noprefix(table_data, f->interrupt, 4); ++ /* Baud Rate */ ++ build_append_int_noprefix(table_data, f->baud_rate, 1); ++ /* Parity */ ++ build_append_int_noprefix(table_data, f->parity, 1); ++ /* Stop Bits */ ++ build_append_int_noprefix(table_data, f->stop_bits, 1); ++ /* Flow Control */ ++ build_append_int_noprefix(table_data, f->flow_control, 1); ++ /* Language */ ++ build_append_int_noprefix(table_data, f->language, 1); ++ /* Terminal Type */ ++ build_append_int_noprefix(table_data, f->terminal_type, 1); ++ /* PCI Device ID */ ++ build_append_int_noprefix(table_data, f->pci_device_id, 2); ++ /* PCI Vendor ID */ ++ build_append_int_noprefix(table_data, f->pci_vendor_id, 2); ++ /* PCI Bus Number */ ++ build_append_int_noprefix(table_data, f->pci_bus, 1); ++ /* PCI Device Number */ ++ build_append_int_noprefix(table_data, f->pci_device, 1); ++ /* PCI Function Number */ ++ build_append_int_noprefix(table_data, f->pci_function, 1); ++ /* PCI Flags */ ++ build_append_int_noprefix(table_data, f->pci_flags, 4); ++ /* PCI Segment */ ++ build_append_int_noprefix(table_data, f->pci_segment, 1); ++ /* Reserved */ ++ build_append_int_noprefix(table_data, 0, 4); ++ ++ acpi_table_end(linker, &table); ++} + /* + * ACPI spec, Revision 6.3 + * 5.2.29 Processor Properties Topology Table (PPTT) +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 86984b716..076781423 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -717,48 +717,34 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + * Rev: 1.07 + */ + static void +-build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) ++spcr_setup(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + { +- AcpiTable table = { .sig = "SPCR", .rev = 2, .oem_id = vms->oem_id, +- .oem_table_id = vms->oem_table_id }; +- +- acpi_table_begin(&table, table_data); +- +- /* Interface Type */ +- build_append_int_noprefix(table_data, 3, 1); /* ARM PL011 UART */ +- build_append_int_noprefix(table_data, 0, 3); /* Reserved */ +- /* Base Address */ +- build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 32, 0, 3, +- vms->memmap[VIRT_UART].base); +- /* Interrupt Type */ +- build_append_int_noprefix(table_data, +- (1 << 3) /* Bit[3] ARMH GIC interrupt */, 1); +- build_append_int_noprefix(table_data, 0, 1); /* IRQ */ +- /* Global System Interrupt */ +- build_append_int_noprefix(table_data, +- vms->irqmap[VIRT_UART] + ARM_SPI_BASE, 4); +- build_append_int_noprefix(table_data, 3 /* 9600 */, 1); /* Baud Rate */ +- build_append_int_noprefix(table_data, 0 /* No Parity */, 1); /* Parity */ +- /* Stop Bits */ +- build_append_int_noprefix(table_data, 1 /* 1 Stop bit */, 1); +- /* Flow Control */ +- build_append_int_noprefix(table_data, +- (1 << 1) /* RTS/CTS hardware flow control */, 1); +- /* Terminal Type */ +- build_append_int_noprefix(table_data, 0 /* VT100 */, 1); +- build_append_int_noprefix(table_data, 0, 1); /* Language */ +- /* PCI Device ID */ +- build_append_int_noprefix(table_data, 0xffff /* not a PCI device*/, 2); +- /* PCI Vendor ID */ +- build_append_int_noprefix(table_data, 0xffff /* not a PCI device*/, 2); +- build_append_int_noprefix(table_data, 0, 1); /* PCI Bus Number */ +- build_append_int_noprefix(table_data, 0, 1); /* PCI Device Number */ +- build_append_int_noprefix(table_data, 0, 1); /* PCI Function Number */ +- build_append_int_noprefix(table_data, 0, 4); /* PCI Flags */ +- build_append_int_noprefix(table_data, 0, 1); /* PCI Segment */ +- build_append_int_noprefix(table_data, 0, 4); /* Reserved */ ++ AcpiSpcrData serial = { ++ .interface_type = 3, /* ARM PL011 UART */ ++ .base_addr.id = AML_AS_SYSTEM_MEMORY, ++ .base_addr.width = 32, ++ .base_addr.offset = 0, ++ .base_addr.size = 3, ++ .base_addr.addr = vms->memmap[VIRT_UART].base, ++ .interrupt_type = (1 << 3),/* Bit[3] ARMH GIC interrupt*/ ++ .pc_interrupt = 0, /* IRQ */ ++ .interrupt = (vms->irqmap[VIRT_UART] + ARM_SPI_BASE), ++ .baud_rate = 3, /* 9600 */ ++ .parity = 0, /* No Parity */ ++ .stop_bits = 1, /* 1 Stop bit */ ++ .flow_control = 1 << 1, /* RTS/CTS hardware flow control */ ++ .terminal_type = 0, /* VT100 */ ++ .language = 0, /* Language */ ++ .pci_device_id = 0xffff, /* not a PCI device*/ ++ .pci_vendor_id = 0xffff, /* not a PCI device*/ ++ .pci_bus = 0, ++ .pci_device = 0, ++ .pci_function = 0, ++ .pci_flags = 0, ++ .pci_segment = 0, ++ }; + +- acpi_table_end(linker, &table); ++ build_spcr(table_data, linker, &serial, 2, vms->oem_id, vms->oem_table_id); + } + + /* +@@ -1316,7 +1302,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) + } + + acpi_add_table(table_offsets, tables_blob); +- build_spcr(tables_blob, tables->linker, vms); ++ spcr_setup(tables_blob, tables->linker, vms); + + acpi_add_table(table_offsets, tables_blob); + build_dbg2(tables_blob, tables->linker, vms); +diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h +index b1f389fb4..7a8b708cd 100644 +--- a/include/hw/acpi/acpi-defs.h ++++ b/include/hw/acpi/acpi-defs.h +@@ -90,6 +90,39 @@ typedef struct AcpiFadtData { + unsigned *xdsdt_tbl_offset; + } AcpiFadtData; + ++typedef struct AcpiGas { ++ uint8_t id; /* Address space ID */ ++ uint8_t width; /* Register bit width */ ++ uint8_t offset; /* Register bit offset */ ++ uint8_t size; /* Access size */ ++ uint64_t addr; /* Address */ ++} AcpiGas; ++ ++/* SPCR (Serial Port Console Redirection table) */ ++typedef struct AcpiSpcrData { ++ uint8_t interface_type; ++ uint8_t reserved[3]; ++ struct AcpiGas base_addr; ++ uint8_t interrupt_type; ++ uint8_t pc_interrupt; ++ uint32_t interrupt; /* Global system interrupt */ ++ uint8_t baud_rate; ++ uint8_t parity; ++ uint8_t stop_bits; ++ uint8_t flow_control; ++ uint8_t terminal_type; ++ uint8_t language; ++ uint8_t reserved1; ++ uint16_t pci_device_id; /* Must be 0xffff if not PCI device */ ++ uint16_t pci_vendor_id; /* Must be 0xffff if not PCI device */ ++ uint8_t pci_bus; ++ uint8_t pci_device; ++ uint8_t pci_function; ++ uint32_t pci_flags; ++ uint8_t pci_segment; ++ uint32_t reserved2; ++} AcpiSpcrData; ++ + #define ACPI_FADT_ARM_PSCI_COMPLIANT (1 << 0) + #define ACPI_FADT_ARM_PSCI_USE_HVC (1 << 1) + +diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h +index 91f9cbf4f..381ad4a8a 100644 +--- a/include/hw/acpi/aml-build.h ++++ b/include/hw/acpi/aml-build.h +@@ -506,4 +506,8 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, + + void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog, + const char *oem_id, const char *oem_table_id); ++ ++void build_spcr(GArray *table_data, BIOSLinker *linker, ++ const AcpiSpcrData *f, const uint8_t rev, ++ const char *oem_id, const char *oem_table_id); + #endif +-- +2.43.0 + diff --git a/hw-loongarch-Add-KVM-IPI-device-support.patch b/hw-loongarch-Add-KVM-IPI-device-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..fea48930cd127ad8258231feb971a9da8e53bbe5 --- /dev/null +++ b/hw-loongarch-Add-KVM-IPI-device-support.patch @@ -0,0 +1,400 @@ +From 24e4e6742bdc8d804760e84f4e4bde5460e1e024 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 09:29:00 +0800 +Subject: [PATCH 72/78] hw/loongarch: Add KVM IPI device support + +Added ipi interrupt controller for kvm emulation. +The main process is to send the command word for +creating an ipi device to the kernel. +When the VM is saved, the ioctl obtains the ipi +interrupt controller data in the kernel and saves it. +When the VM is recovered, the saved data is sent to the kernel. + +Signed-off-by: gaosong +Signed-off-by: Xianglai Li +--- + hw/intc/Kconfig | 3 + + hw/intc/loongarch_ipi_kvm.c | 207 ++++++++++++++++++++++++++++++++ + hw/intc/meson.build | 1 + + hw/loongarch/Kconfig | 1 + + hw/loongarch/virt.c | 35 ++++-- + include/hw/intc/loongarch_ipi.h | 23 ++++ + linux-headers/linux/kvm.h | 2 + + target/loongarch/kvm/kvm.c | 4 + + 8 files changed, 263 insertions(+), 13 deletions(-) + create mode 100644 hw/intc/loongarch_ipi_kvm.c + +diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig +index 97d550b06b..cbba74c22e 100644 +--- a/hw/intc/Kconfig ++++ b/hw/intc/Kconfig +@@ -93,6 +93,9 @@ config NIOS2_VIC + config LOONGARCH_IPI + bool + ++config LOONGARCH_IPI_KVM ++ bool ++ + config LOONGARCH_PCH_PIC + bool + select UNIMP +diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c +new file mode 100644 +index 0000000000..fd308eb0c0 +--- /dev/null ++++ b/hw/intc/loongarch_ipi_kvm.c +@@ -0,0 +1,207 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch kvm ipi interrupt support ++ * ++ * Copyright (C) 2024 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "qemu/typedefs.h" ++#include "hw/intc/loongarch_ipi.h" ++#include "hw/sysbus.h" ++#include "linux/kvm.h" ++#include "migration/vmstate.h" ++#include "qapi/error.h" ++#include "sysemu/kvm.h" ++ ++#define IPI_DEV_FD_UNDEF -1 ++ ++static void kvm_ipi_access_regs(int fd, uint64_t addr, ++ uint32_t *val, int is_write) ++{ ++ kvm_device_access(fd, KVM_DEV_LOONGARCH_IPI_GRP_REGS, ++ addr, val, is_write, &error_abort); ++} ++ ++static int kvm_loongarch_ipi_pre_save(void *opaque) ++{ ++ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque; ++ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi); ++ IPICore *cpu; ++ uint64_t attr; ++ int cpu_id = 0; ++ int fd = ipi_class->dev_fd; ++ ++ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) { ++ cpu = &ipi->cpu[cpu_id]; ++ attr = (cpu_id << 16) | CORE_STATUS_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->status, false); ++ ++ attr = (cpu_id << 16) | CORE_EN_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->en, false); ++ ++ attr = (cpu_id << 16) | CORE_SET_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->set, false); ++ ++ attr = (cpu_id << 16) | CORE_CLEAR_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->clear, false); ++ ++ attr = (cpu_id << 16) | CORE_BUF_20; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], false); ++ ++ attr = (cpu_id << 16) | CORE_BUF_28; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], false); ++ ++ attr = (cpu_id << 16) | CORE_BUF_30; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], false); ++ ++ attr = (cpu_id << 16) | CORE_BUF_38; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], false); ++ } ++ ++ return 0; ++} ++ ++static int kvm_loongarch_ipi_post_load(void *opaque, int version_id) ++{ ++ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque; ++ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi); ++ IPICore *cpu; ++ uint64_t attr; ++ int cpu_id = 0; ++ int fd = ipi_class->dev_fd; ++ ++ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) { ++ cpu = &ipi->cpu[cpu_id]; ++ attr = (cpu_id << 16) | CORE_STATUS_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->status, true); ++ ++ attr = (cpu_id << 16) | CORE_EN_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->en, true); ++ ++ attr = (cpu_id << 16) | CORE_SET_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->set, true); ++ ++ attr = (cpu_id << 16) | CORE_CLEAR_OFF; ++ kvm_ipi_access_regs(fd, attr, &cpu->clear, true); ++ ++ attr = (cpu_id << 16) | CORE_BUF_20; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], true); ++ ++ attr = (cpu_id << 16) | CORE_BUF_28; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], true); ++ ++ attr = (cpu_id << 16) | CORE_BUF_30; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], true); ++ ++ attr = (cpu_id << 16) | CORE_BUF_38; ++ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], true); ++ } ++ ++ return 0; ++} ++ ++static void kvm_loongarch_ipi_realize(DeviceState *dev, Error **errp) ++{ ++ KVMLoongArchIPI *ipi = KVM_LOONGARCH_IPI(dev); ++ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(dev); ++ struct kvm_create_device cd = {0}; ++ Error *err = NULL; ++ int ret; ++ ++ if (ipi->num_cpu == 0) { ++ error_setg(errp, "num-cpu must be at least 1"); ++ return; ++ } ++ ++ ipi_class->parent_realize(dev, &err); ++ if (err) { ++ error_propagate(errp, err); ++ return; ++ } ++ ++ ipi->cpu = g_new0(IPICore, ipi->num_cpu); ++ if (ipi->cpu == NULL) { ++ error_setg(errp, "Memory allocation for ExtIOICore faile"); ++ return; ++ } ++ ++ if (!ipi_class->is_created) { ++ cd.type = KVM_DEV_TYPE_LA_IPI; ++ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); ++ if (ret < 0) { ++ error_setg_errno(errp, errno, "Creating the KVM device failed"); ++ return; ++ } ++ ipi_class->is_created = true; ++ ipi_class->dev_fd = cd.fd; ++ fprintf(stdout, "Create LoongArch IPI irqchip in KVM done!\n"); ++ } ++ ++ assert(ipi_class->dev_fd != IPI_DEV_FD_UNDEF); ++} ++ ++static Property kvm_loongarch_ipi_properties[] = { ++ DEFINE_PROP_UINT32("num-cpu", KVMLoongArchIPI, num_cpu, 1), ++ DEFINE_PROP_END_OF_LIST() ++}; ++ ++static const VMStateDescription vmstate_kvm_ipi_core = { ++ .name = "kvm-ipi-single", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32(status, IPICore), ++ VMSTATE_UINT32(en, IPICore), ++ VMSTATE_UINT32(set, IPICore), ++ VMSTATE_UINT32(clear, IPICore), ++ VMSTATE_UINT32_ARRAY(buf, IPICore, 8), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static const VMStateDescription vmstate_kvm_loongarch_ipi = { ++ .name = TYPE_KVM_LOONGARCH_IPI, ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = kvm_loongarch_ipi_pre_save, ++ .post_load = kvm_loongarch_ipi_post_load, ++ .fields = (VMStateField[]) { ++ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, KVMLoongArchIPI, num_cpu, ++ vmstate_kvm_ipi_core, IPICore), ++ ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void kvm_loongarch_ipi_class_init(ObjectClass *oc, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(oc); ++ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_CLASS(oc); ++ ++ ipi_class->parent_realize = dc->realize; ++ dc->realize = kvm_loongarch_ipi_realize; ++ ++ ipi_class->is_created = false; ++ ipi_class->dev_fd = IPI_DEV_FD_UNDEF; ++ ++ device_class_set_props(dc, kvm_loongarch_ipi_properties); ++ ++ dc->vmsd = &vmstate_kvm_loongarch_ipi; ++} ++ ++static const TypeInfo kvm_loongarch_ipi_info = { ++ .name = TYPE_KVM_LOONGARCH_IPI, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(KVMLoongArchIPI), ++ .class_size = sizeof(KVMLoongArchIPIClass), ++ .class_init = kvm_loongarch_ipi_class_init, ++}; ++ ++static void kvm_loongarch_ipi_register_types(void) ++{ ++ type_register_static(&kvm_loongarch_ipi_info); ++} ++ ++type_init(kvm_loongarch_ipi_register_types) +diff --git a/hw/intc/meson.build b/hw/intc/meson.build +index ed355941d1..9deeeb51bb 100644 +--- a/hw/intc/meson.build ++++ b/hw/intc/meson.build +@@ -70,6 +70,7 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'], + specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) + specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) ++specific_ss.add(when: 'CONFIG_LOONGARCH_IPI_KVM', if_true: files('loongarch_ipi_kvm.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c')) +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index b42a8573d4..1e761624c6 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -14,6 +14,7 @@ config LOONGARCH_VIRT + select LOONGARCH_PCH_PIC + select LOONGARCH_PCH_MSI + select LOONGARCH_EXTIOI ++ select LOONGARCH_IPI_KVM if KVM + select LS7A_RTC + select SMBIOS + select ACPI_CPU_HOTPLUG +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 6159fd9470..f065eb75f8 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -829,16 +829,28 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + * +--------+ +---------+ +---------+ + */ + +- /* Create IPI device */ +- ipi = qdev_new(TYPE_LOONGARCH_IPI); +- qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus); +- sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); +- +- /* IPI iocsr memory region */ +- memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0)); +- memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1)); ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ ipi = qdev_new(TYPE_KVM_LOONGARCH_IPI); ++ qdev_prop_set_int32(ipi, "num-cpu", ms->smp.max_cpus); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); ++ } else { ++ ipi = qdev_new(TYPE_LOONGARCH_IPI); ++ qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); ++ ++ /* IPI iocsr memory region */ ++ memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0)); ++ memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1)); ++ for (cpu = 0; cpu < ms->smp.cpus; cpu++) { ++ cpu_state = qemu_get_cpu(cpu); ++ cpudev = DEVICE(cpu_state); ++ ++ /* connect ipi irq to cpu irq */ ++ qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); ++ } ++ } + + /* Add cpu interrupt-controller */ + fdt_add_cpuic_node(lvms, &cpuintc_phandle); +@@ -849,9 +861,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + lacpu = LOONGARCH_CPU(cpu_state); + env = &(lacpu->env); + env->address_space_iocsr = &lvms->as_iocsr; +- +- /* connect ipi irq to cpu irq */ +- qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); + env->ipistate = ipi; + } + +diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h +index 1c1e834849..601b4f18a7 100644 +--- a/include/hw/intc/loongarch_ipi.h ++++ b/include/hw/intc/loongarch_ipi.h +@@ -32,6 +32,7 @@ + + #define TYPE_LOONGARCH_IPI "loongarch_ipi" + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI) ++#define TYPE_KVM_LOONGARCH_IPI "loongarch-ipi-kvm" + + typedef struct IPICore { + uint32_t status; +@@ -51,4 +52,26 @@ struct LoongArchIPI { + IPICore *cpu; + }; + ++struct KVMLoongArchIPI { ++ SysBusDevice parent_obj; ++ uint32_t num_cpu; ++ IPICore *cpu; ++}; ++typedef struct KVMLoongArchIPI KVMLoongArchIPI; ++DECLARE_INSTANCE_CHECKER(KVMLoongArchIPI, KVM_LOONGARCH_IPI, ++ TYPE_KVM_LOONGARCH_IPI) ++ ++struct KVMLoongArchIPIClass { ++ SysBusDeviceClass parent_class; ++ DeviceRealize parent_realize; ++ ++ bool is_created; ++ int dev_fd; ++ ++}; ++typedef struct KVMLoongArchIPIClass KVMLoongArchIPIClass; ++DECLARE_CLASS_CHECKERS(KVMLoongArchIPIClass, KVM_LOONGARCH_IPI, ++ TYPE_KVM_LOONGARCH_IPI) ++ ++ + #endif +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index eb30402c2d..ea1f821a9f 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1470,6 +1470,8 @@ enum kvm_device_type { + #define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME + KVM_DEV_TYPE_RISCV_AIA, + #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA ++ KVM_DEV_TYPE_LA_IPI, ++#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI + KVM_DEV_TYPE_MAX, + }; + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 550f14269e..ab1ea3d4fd 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -1066,6 +1066,10 @@ int kvm_arch_get_default_type(MachineState *ms) + int kvm_arch_init(MachineState *ms, KVMState *s) + { + cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); ++ if(!kvm_vm_check_attr(kvm_state, KVM_LOONGARCH_VM_HAVE_IRQCHIP, KVM_LOONGARCH_VM_HAVE_IRQCHIP)) { ++ s->kernel_irqchip_allowed = false; ++ } ++ + return 0; + } + +-- +2.39.1 + diff --git a/hw-loongarch-Add-KVM-extioi-device-support.patch b/hw-loongarch-Add-KVM-extioi-device-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..58abefd4afa5307722157e4c72761b59727d714b --- /dev/null +++ b/hw-loongarch-Add-KVM-extioi-device-support.patch @@ -0,0 +1,384 @@ +From 833cdea8037d9124cd2e0328739de1b85aaec2a2 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 09:50:50 +0800 +Subject: [PATCH 73/78] hw/loongarch: Add KVM extioi device support + +Added extioi interrupt controller for kvm emulation. +The main process is to send the command word for +creating an extioi device to the kernel. +When the VM is saved, the ioctl obtains the related +data of the extioi interrupt controller in the kernel +and saves it. When the VM is recovered, the saved data +is sent to the kernel. + +Signed-off-by: gaosong +Signed-off-by: Xianglai Li +--- + hw/intc/Kconfig | 3 + + hw/intc/loongarch_extioi_kvm.c | 150 +++++++++++++++++++++++++++++ + hw/intc/meson.build | 1 + + hw/loongarch/Kconfig | 1 + + hw/loongarch/virt.c | 50 +++++----- + include/hw/intc/loongarch_extioi.h | 36 ++++++- + include/hw/loongarch/virt.h | 15 +++ + linux-headers/linux/kvm.h | 2 + + 8 files changed, 232 insertions(+), 26 deletions(-) + create mode 100644 hw/intc/loongarch_extioi_kvm.c + +diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig +index cbba74c22e..f1e8bd2fc9 100644 +--- a/hw/intc/Kconfig ++++ b/hw/intc/Kconfig +@@ -107,3 +107,6 @@ config LOONGARCH_PCH_MSI + + config LOONGARCH_EXTIOI + bool ++ ++config LOONGARCH_EXTIOI_KVM ++ bool +diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c +new file mode 100644 +index 0000000000..f5bbc33255 +--- /dev/null ++++ b/hw/intc/loongarch_extioi_kvm.c +@@ -0,0 +1,150 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch kvm extioi interrupt support ++ * ++ * Copyright (C) 2024 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "qemu/typedefs.h" ++#include "hw/intc/loongarch_extioi.h" ++#include "hw/sysbus.h" ++#include "linux/kvm.h" ++#include "migration/vmstate.h" ++#include "qapi/error.h" ++#include "sysemu/kvm.h" ++ ++static void kvm_extioi_access_regs(int fd, uint64_t addr, ++ void *val, int is_write) ++{ ++ kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS, ++ addr, val, is_write, &error_abort); ++} ++ ++static int kvm_loongarch_extioi_pre_save(void *opaque) ++{ ++ KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque; ++ KVMLoongArchExtIOIClass *class = KVM_LOONGARCH_EXTIOI_GET_CLASS(s); ++ int fd = class->dev_fd; ++ ++ kvm_extioi_access_regs(fd, EXTIOI_NODETYPE_START, ++ (void *)s->nodetype, false); ++ kvm_extioi_access_regs(fd, EXTIOI_IPMAP_START, (void *)s->ipmap, false); ++ kvm_extioi_access_regs(fd, EXTIOI_ENABLE_START, (void *)s->enable, false); ++ kvm_extioi_access_regs(fd, EXTIOI_BOUNCE_START, (void *)s->bounce, false); ++ kvm_extioi_access_regs(fd, EXTIOI_ISR_START, (void *)s->isr, false); ++ kvm_extioi_access_regs(fd, EXTIOI_COREMAP_START, ++ (void *)s->coremap, false); ++ kvm_extioi_access_regs(fd, EXTIOI_SW_COREMAP_FLAG, ++ (void *)s->sw_coremap, false); ++ kvm_extioi_access_regs(fd, EXTIOI_COREISR_START, ++ (void *)s->coreisr, false); ++ ++ return 0; ++} ++ ++static int kvm_loongarch_extioi_post_load(void *opaque, int version_id) ++{ ++ KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque; ++ KVMLoongArchExtIOIClass *class = KVM_LOONGARCH_EXTIOI_GET_CLASS(s); ++ int fd = class->dev_fd; ++ ++ kvm_extioi_access_regs(fd, EXTIOI_NODETYPE_START, ++ (void *)s->nodetype, true); ++ kvm_extioi_access_regs(fd, EXTIOI_IPMAP_START, (void *)s->ipmap, true); ++ kvm_extioi_access_regs(fd, EXTIOI_ENABLE_START, (void *)s->enable, true); ++ kvm_extioi_access_regs(fd, EXTIOI_BOUNCE_START, (void *)s->bounce, true); ++ kvm_extioi_access_regs(fd, EXTIOI_ISR_START, (void *)s->isr, true); ++ kvm_extioi_access_regs(fd, EXTIOI_COREMAP_START, (void *)s->coremap, true); ++ kvm_extioi_access_regs(fd, EXTIOI_SW_COREMAP_FLAG, ++ (void *)s->sw_coremap, true); ++ kvm_extioi_access_regs(fd, EXTIOI_COREISR_START, (void *)s->coreisr, true); ++ ++ return 0; ++} ++ ++static void kvm_loongarch_extioi_realize(DeviceState *dev, Error **errp) ++{ ++ KVMLoongArchExtIOIClass *extioi_class = KVM_LOONGARCH_EXTIOI_GET_CLASS(dev); ++ struct kvm_create_device cd = {0}; ++ Error *err = NULL; ++ int ret,i; ++ ++ extioi_class->parent_realize(dev, &err); ++ if (err) { ++ error_propagate(errp, err); ++ return; ++ } ++ ++ if (!extioi_class->is_created) { ++ cd.type = KVM_DEV_TYPE_LA_EXTIOI; ++ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); ++ if (ret < 0) { ++ error_setg_errno(errp, errno, ++ "Creating the KVM extioi device failed"); ++ return; ++ } ++ extioi_class->is_created = true; ++ extioi_class->dev_fd = cd.fd; ++ fprintf(stdout, "Create LoongArch extioi irqchip in KVM done!\n"); ++ } ++ ++ kvm_async_interrupts_allowed = true; ++ kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); ++ if (kvm_has_gsi_routing()) { ++ for (i = 0; i < 64; ++i) { ++ kvm_irqchip_add_irq_route(kvm_state, i, 0, i); ++ } ++ kvm_gsi_routing_allowed = true; ++ } ++} ++ ++static const VMStateDescription vmstate_kvm_extioi_core = { ++ .name = "kvm-extioi-single", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = kvm_loongarch_extioi_pre_save, ++ .post_load = kvm_loongarch_extioi_post_load, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32_ARRAY(nodetype, KVMLoongArchExtIOI, ++ EXTIOI_IRQS_NODETYPE_COUNT / 2), ++ VMSTATE_UINT32_ARRAY(bounce, KVMLoongArchExtIOI, ++ EXTIOI_IRQS_GROUP_COUNT), ++ VMSTATE_UINT32_ARRAY(isr, KVMLoongArchExtIOI, EXTIOI_IRQS / 32), ++ VMSTATE_UINT32_2DARRAY(coreisr, KVMLoongArchExtIOI, EXTIOI_CPUS, ++ EXTIOI_IRQS_GROUP_COUNT), ++ VMSTATE_UINT32_ARRAY(enable, KVMLoongArchExtIOI, EXTIOI_IRQS / 32), ++ VMSTATE_UINT32_ARRAY(ipmap, KVMLoongArchExtIOI, ++ EXTIOI_IRQS_IPMAP_SIZE / 4), ++ VMSTATE_UINT32_ARRAY(coremap, KVMLoongArchExtIOI, EXTIOI_IRQS / 4), ++ VMSTATE_UINT8_ARRAY(sw_coremap, KVMLoongArchExtIOI, EXTIOI_IRQS), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void kvm_loongarch_extioi_class_init(ObjectClass *oc, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(oc); ++ KVMLoongArchExtIOIClass *extioi_class = KVM_LOONGARCH_EXTIOI_CLASS(oc); ++ ++ extioi_class->parent_realize = dc->realize; ++ dc->realize = kvm_loongarch_extioi_realize; ++ extioi_class->is_created = false; ++ dc->vmsd = &vmstate_kvm_extioi_core; ++} ++ ++static const TypeInfo kvm_loongarch_extioi_info = { ++ .name = TYPE_KVM_LOONGARCH_EXTIOI, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(KVMLoongArchExtIOI), ++ .class_size = sizeof(KVMLoongArchExtIOIClass), ++ .class_init = kvm_loongarch_extioi_class_init, ++}; ++ ++static void kvm_loongarch_extioi_register_types(void) ++{ ++ type_register_static(&kvm_loongarch_extioi_info); ++} ++ ++type_init(kvm_loongarch_extioi_register_types) +diff --git a/hw/intc/meson.build b/hw/intc/meson.build +index 9deeeb51bb..a37d7da8aa 100644 +--- a/hw/intc/meson.build ++++ b/hw/intc/meson.build +@@ -74,3 +74,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_IPI_KVM', if_true: files('loongarch_ipi_ + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c')) ++specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI_KVM', if_true: files('loongarch_extioi_kvm.c')) +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index 1e761624c6..1a47d44a64 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -15,6 +15,7 @@ config LOONGARCH_VIRT + select LOONGARCH_PCH_MSI + select LOONGARCH_EXTIOI + select LOONGARCH_IPI_KVM if KVM ++ select LOONGARCH_EXTIOI_KVM if KVM + select LS7A_RTC + select SMBIOS + select ACPI_CPU_HOTPLUG +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index f065eb75f8..71e2a3735c 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -867,31 +867,33 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + lvms->ipi = ipi; + + /* Create EXTIOI device */ +- extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); +- qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.max_cpus); +- if (virt_is_veiointc_enabled(lvms)) { +- qdev_prop_set_bit(extioi, "has-virtualization-extension", true); +- } +- sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); +- +- memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0)); +- if (virt_is_veiointc_enabled(lvms)) { +- memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE, +- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1)); +- } +- lvms->extioi = extioi; +- +- /* +- * connect ext irq to the cpu irq +- * cpu_pin[9:2] <= intc_pin[7:0] +- */ +- for (cpu = 0; cpu < ms->smp.cpus; cpu++) { +- cpudev = DEVICE(qemu_get_cpu(cpu)); +- for (pin = 0; pin < LS3A_INTC_IP; pin++) { +- qdev_connect_gpio_out(extioi, (cpu * 8 + pin), +- qdev_get_gpio_in(cpudev, pin + 2)); ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ extioi = qdev_new(TYPE_KVM_LOONGARCH_EXTIOI); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); ++ } else { ++ extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); ++ qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.max_cpus); ++ if (virt_is_veiointc_enabled(lvms)) { ++ qdev_prop_set_bit(extioi, "has-virtualization-extension", true); + } ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); ++ memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0)); ++ if (virt_is_veiointc_enabled(lvms)) { ++ memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE, ++ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1)); ++ } ++ /* ++ * connect ext irq to the cpu irq ++ * cpu_pin[9:2] <= intc_pin[7:0] ++ */ ++ for (cpu = 0; cpu < ms->smp.cpus; cpu++) { ++ cpudev = DEVICE(qemu_get_cpu(cpu)); ++ for (pin = 0; pin < LS3A_INTC_IP; pin++) { ++ qdev_connect_gpio_out(extioi, (cpu * 8 + pin), ++ qdev_get_gpio_in(cpudev, pin + 2)); ++ } ++ } + } + + lvms->extioi = extioi; +diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h +index 722ffee1bc..9966cd98d3 100644 +--- a/include/hw/intc/loongarch_extioi.h ++++ b/include/hw/intc/loongarch_extioi.h +@@ -15,7 +15,7 @@ + #define EXTIOI_IRQS (256) + #define EXTIOI_IRQS_BITMAP_SIZE (256 / 8) + /* irq from EXTIOI is routed to no more than 4 cpus */ +-#define EXTIOI_CPUS (4) ++#define EXTIOI_CPUS (256) + /* map to ipnum per 32 irqs */ + #define EXTIOI_IRQS_IPMAP_SIZE (256 / 32) + #define EXTIOI_IRQS_COREMAP_SIZE 256 +@@ -59,13 +59,17 @@ + #define EXTIOI_VIRT_COREMAP_START (0x40) + #define EXTIOI_VIRT_COREMAP_END (0x240) + ++#define EXTIOI_SW_COREMAP_FLAG (1 << 0) ++ + typedef struct ExtIOICore { + uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT]; + DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS); + qemu_irq parent_irq[LS3A_INTC_IP]; + } ExtIOICore; + +-#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi" ++#define TYPE_LOONGARCH_EXTIOI "loongarch-extioi" ++#define TYPE_KVM_LOONGARCH_EXTIOI "loongarch-kvm-extioi" ++ + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI) + struct LoongArchExtIOI { + SysBusDevice parent_obj; +@@ -87,4 +91,32 @@ struct LoongArchExtIOI { + MemoryRegion extioi_system_mem; + MemoryRegion virt_extend; + }; ++ ++struct KVMLoongArchExtIOI { ++ SysBusDevice parent_obj; ++ /* hardware state */ ++ uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2]; ++ uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT]; ++ uint32_t isr[EXTIOI_IRQS / 32]; ++ uint32_t coreisr[EXTIOI_CPUS][EXTIOI_IRQS_GROUP_COUNT]; ++ uint32_t enable[EXTIOI_IRQS / 32]; ++ uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4]; ++ uint32_t coremap[EXTIOI_IRQS / 4]; ++ uint8_t sw_coremap[EXTIOI_IRQS]; ++}; ++typedef struct KVMLoongArchExtIOI KVMLoongArchExtIOI; ++DECLARE_INSTANCE_CHECKER(KVMLoongArchExtIOI, KVM_LOONGARCH_EXTIOI, ++ TYPE_KVM_LOONGARCH_EXTIOI) ++ ++struct KVMLoongArchExtIOIClass { ++ SysBusDeviceClass parent_class; ++ DeviceRealize parent_realize; ++ ++ bool is_created; ++ int dev_fd; ++}; ++typedef struct KVMLoongArchExtIOIClass KVMLoongArchExtIOIClass; ++DECLARE_CLASS_CHECKERS(KVMLoongArchExtIOIClass, KVM_LOONGARCH_EXTIOI, ++ TYPE_KVM_LOONGARCH_EXTIOI) ++ + #endif /* LOONGARCH_EXTIOI_H */ +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 98c990327b..168b40c31b 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -38,6 +38,21 @@ + + #define FDT_BASE 0x100000 + ++/* 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 ++ + struct LoongArchVirtMachineState { + /*< private >*/ + MachineState parent_obj; +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index ea1f821a9f..0c0b82d1ef 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1472,6 +1472,8 @@ enum kvm_device_type { + #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA + KVM_DEV_TYPE_LA_IPI, + #define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI ++ KVM_DEV_TYPE_LA_EXTIOI, ++#define KVM_DEV_TYPE_LA_EXTIOI KVM_DEV_TYPE_LA_EXTIOI + KVM_DEV_TYPE_MAX, + }; + +-- +2.39.1 + diff --git a/hw-loongarch-Add-KVM-pch-msi-device-support.patch b/hw-loongarch-Add-KVM-pch-msi-device-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..e488337a436f6c4b205a4f5886fa435280f94ff5 --- /dev/null +++ b/hw-loongarch-Add-KVM-pch-msi-device-support.patch @@ -0,0 +1,136 @@ +From 24bd774f8146247c7ac6071492f6016140a97267 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 22:18:50 +0800 +Subject: [PATCH 75/78] hw/loongarch: Add KVM pch msi device support + +Added pch_msi interrupt controller handling +during kernel emulation of irq chip. + +Signed-off-by: gaosong +Signed-off-by: Xianglai Li +--- + hw/intc/loongarch_pch_msi.c | 39 ++++++++++++++++++++++------- + hw/loongarch/virt.c | 22 +++++++++------- + include/hw/intc/loongarch_pch_msi.h | 2 +- + 3 files changed, 44 insertions(+), 19 deletions(-) + +diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c +index ecf3ed0267..901c2c21be 100644 +--- a/hw/intc/loongarch_pch_msi.c ++++ b/hw/intc/loongarch_pch_msi.c +@@ -14,6 +14,8 @@ + #include "hw/misc/unimp.h" + #include "migration/vmstate.h" + #include "trace.h" ++#include "sysemu/kvm.h" ++#include "hw/loongarch/virt.h" + + static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size) + { +@@ -26,14 +28,24 @@ static void loongarch_msi_mem_write(void *opaque, hwaddr addr, + LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque; + int irq_num; + +- /* +- * vector number is irq number from upper extioi intc +- * need subtract irq base to get msi vector offset +- */ +- irq_num = (val & 0xff) - s->irq_base; +- trace_loongarch_msi_set_irq(irq_num); +- assert(irq_num < s->irq_num); +- qemu_set_irq(s->pch_msi_irq[irq_num], 1); ++ MSIMessage msg = { ++ .address = addr, ++ .data = val, ++ }; ++ ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ kvm_irqchip_send_msi(kvm_state, msg); ++ } else { ++ /* ++ * vector number is irq number from upper extioi intc ++ * need subtract irq base to get msi vector offset ++ */ ++ irq_num = (val & 0xff) - s->irq_base; ++ trace_loongarch_msi_set_irq(irq_num); ++ assert(irq_num < s->irq_num); ++ ++ qemu_set_irq(s->pch_msi_irq[irq_num], 1); ++ } + } + + static const MemoryRegionOps loongarch_pch_msi_ops = { +@@ -46,7 +58,16 @@ static void pch_msi_irq_handler(void *opaque, int irq, int level) + { + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque); + +- qemu_set_irq(s->pch_msi_irq[irq], level); ++ MSIMessage msg = { ++ .address = 0, ++ .data = irq, ++ }; ++ ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ kvm_irqchip_send_msi(kvm_state, msg); ++ } else { ++ qemu_set_irq(s->pch_msi_irq[irq], level); ++ } + } + + static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp) +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 270dcfd38f..5b0468f6cb 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -928,22 +928,26 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + for (i = 0; i < num; i++) { + qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); + } ++ } + +- pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); +- start = num; +- num = EXTIOI_IRQS - start; +- qdev_prop_set_uint32(pch_msi, "msi_irq_base", start); +- qdev_prop_set_uint32(pch_msi, "msi_irq_num", num); +- d = SYS_BUS_DEVICE(pch_msi); +- sysbus_realize_and_unref(d, &error_fatal); +- sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); ++ pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); ++ num = VIRT_PCH_PIC_IRQ_NUM; ++ start = num; ++ num = EXTIOI_IRQS - start; ++ qdev_prop_set_uint32(pch_msi, "msi_irq_base", start); ++ qdev_prop_set_uint32(pch_msi, "msi_irq_num", num); ++ d = SYS_BUS_DEVICE(pch_msi); ++ sysbus_realize_and_unref(d, &error_fatal); ++ ++ if (!(kvm_enabled() && kvm_irqchip_in_kernel())) { ++ /* Connect pch_msi irqs to extioi */ + for (i = 0; i < num; i++) { +- /* Connect pch_msi irqs to extioi */ + qdev_connect_gpio_out(DEVICE(d), i, + qdev_get_gpio_in(extioi, i + start)); + } + } + ++ sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); + virt_devices_init(pch_pic, lvms, &pch_pic_phandle, &pch_msi_phandle); + } + +diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h +index b8586fb3b6..fd4ea97a83 100644 +--- a/include/hw/intc/loongarch_pch_msi.h ++++ b/include/hw/intc/loongarch_pch_msi.h +@@ -7,7 +7,7 @@ + + #include "hw/sysbus.h" + +-#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi" ++#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi" + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHMSI, LOONGARCH_PCH_MSI) + + /* MSI irq start from 32 to 255 */ +-- +2.39.1 + diff --git a/hw-loongarch-Add-KVM-pch-pic-device-support.patch b/hw-loongarch-Add-KVM-pch-pic-device-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e0e1ba1b296bf7d6c09968fd62dad61367ba233 --- /dev/null +++ b/hw-loongarch-Add-KVM-pch-pic-device-support.patch @@ -0,0 +1,487 @@ +From 30f88e80a47d9bcde08c44c0d752c22c11f2224c Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 10:13:29 +0800 +Subject: [PATCH 74/78] hw/loongarch: Add KVM pch pic device support + +Added pch_pic interrupt controller for kvm emulation. +The main process is to send the command word for +creating an pch_pic device to the kernel, +Delivers the pch pic interrupt controller configuration +register base address to the kernel. +When the VM is saved, the ioctl obtains the pch_pic +interrupt controller data in the kernel and saves it. +When the VM is recovered, the saved data is sent to the kernel. + +Signed-off-by: gaosong +Signed-off-by: Xianglai Li +--- + hw/intc/Kconfig | 3 + + hw/intc/loongarch_pch_pic.c | 24 +++- + hw/intc/loongarch_pch_pic_kvm.c | 189 ++++++++++++++++++++++++++++ + hw/intc/meson.build | 1 + + hw/loongarch/Kconfig | 1 + + hw/loongarch/virt.c | 70 ++++++----- + include/hw/intc/loongarch_pch_pic.h | 51 +++++++- + linux-headers/linux/kvm.h | 2 + + 8 files changed, 303 insertions(+), 38 deletions(-) + create mode 100644 hw/intc/loongarch_pch_pic_kvm.c + +diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig +index f1e8bd2fc9..91c7aa668e 100644 +--- a/hw/intc/Kconfig ++++ b/hw/intc/Kconfig +@@ -100,6 +100,9 @@ config LOONGARCH_PCH_PIC + bool + select UNIMP + ++config LOONGARCH_PCH_PIC_KVM ++ bool ++ + config LOONGARCH_PCH_MSI + select MSI_NONBROKEN + bool +diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c +index 6aa4cadfa4..beb4ac188d 100644 +--- a/hw/intc/loongarch_pch_pic.c ++++ b/hw/intc/loongarch_pch_pic.c +@@ -16,19 +16,28 @@ + #include "migration/vmstate.h" + #include "trace.h" + #include "qapi/error.h" ++#include "sysemu/kvm.h" + + static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level) + { + uint64_t val; + int irq; ++ int kvm_irq; + + if (level) { + val = mask & s->intirr & ~s->int_mask; + if (val) { + irq = ctz64(val); + s->intisr |= MAKE_64BIT_MASK(irq, 1); +- qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); +- } ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ kvm_irq = ( ++ KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT) ++ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | s->htmsi_vector[irq]; ++ kvm_set_irq(kvm_state, kvm_irq, !!level); ++ } else { ++ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); ++ } ++ } + } else { + /* + * intirr means requested pending irq +@@ -38,8 +47,15 @@ static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level) + if (val) { + irq = ctz64(val); + s->intisr &= ~MAKE_64BIT_MASK(irq, 1); +- qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); +- } ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ kvm_irq = ( ++ KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT) ++ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | s->htmsi_vector[irq]; ++ kvm_set_irq(kvm_state, kvm_irq, !!level); ++ } else { ++ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); ++ } ++ } + } + } + +diff --git a/hw/intc/loongarch_pch_pic_kvm.c b/hw/intc/loongarch_pch_pic_kvm.c +new file mode 100644 +index 0000000000..8f66d9a01f +--- /dev/null ++++ b/hw/intc/loongarch_pch_pic_kvm.c +@@ -0,0 +1,189 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch kvm pch pic interrupt support ++ * ++ * Copyright (C) 2024 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "qemu/typedefs.h" ++#include "hw/intc/loongarch_pch_pic.h" ++#include "hw/sysbus.h" ++#include "linux/kvm.h" ++#include "migration/vmstate.h" ++#include "qapi/error.h" ++#include "sysemu/kvm.h" ++#include "hw/loongarch/virt.h" ++#include "hw/pci-host/ls7a.h" ++#include "qemu/error-report.h" ++ ++static void kvm_pch_pic_access_regs(int fd, uint64_t addr, ++ void *val, int is_write) ++{ ++ kvm_device_access(fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS, ++ addr, val, is_write, &error_abort); ++} ++ ++static int kvm_loongarch_pch_pic_pre_save(void *opaque) ++{ ++ KVMLoongArchPCHPIC *s = (KVMLoongArchPCHPIC *)opaque; ++ KVMLoongArchPCHPICClass *class = KVM_LOONGARCH_PCH_PIC_GET_CLASS(s); ++ int fd = class->dev_fd; ++ ++ kvm_pch_pic_access_regs(fd, PCH_PIC_MASK_START, ++ (void *)&s->int_mask, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_EN_START, ++ (void *)&s->htmsi_en, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_EDGE_START, ++ (void *)&s->intedge, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL0_START, ++ (void *)&s->auto_crtl0, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL1_START, ++ (void *)&s->auto_crtl1, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_ROUTE_ENTRY_START, ++ (void *)s->route_entry, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_VEC_START, ++ (void *)s->htmsi_vector, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_IRR_START, ++ (void *)&s->intirr, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_ISR_START, ++ (void *)&s->intisr, false); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_POLARITY_START, ++ (void *)&s->int_polarity, false); ++ ++ return 0; ++} ++ ++static int kvm_loongarch_pch_pic_post_load(void *opaque, int version_id) ++{ ++ KVMLoongArchPCHPIC *s = (KVMLoongArchPCHPIC *)opaque; ++ KVMLoongArchPCHPICClass *class = KVM_LOONGARCH_PCH_PIC_GET_CLASS(s); ++ int fd = class->dev_fd; ++ ++ kvm_pch_pic_access_regs(fd, PCH_PIC_MASK_START, ++ (void *)&s->int_mask, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_EN_START, ++ (void *)&s->htmsi_en, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_EDGE_START, ++ (void *)&s->intedge, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL0_START, ++ (void *)&s->auto_crtl0, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL1_START, ++ (void *)&s->auto_crtl1, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_ROUTE_ENTRY_START, ++ (void *)s->route_entry, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_VEC_START, ++ (void *)s->htmsi_vector, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_IRR_START, ++ (void *)&s->intirr, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_ISR_START, ++ (void *)&s->intisr, true); ++ kvm_pch_pic_access_regs(fd, PCH_PIC_POLARITY_START, ++ (void *)&s->int_polarity, true); ++ ++ return 0; ++} ++ ++static void kvm_pch_pic_handler(void *opaque, int irq, int level) ++{ ++ int kvm_irq; ++ ++ if (kvm_enabled()) { ++ 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); ++ } ++} ++ ++static void kvm_loongarch_pch_pic_realize(DeviceState *dev, Error **errp) ++{ ++ KVMLoongArchPCHPICClass *pch_pic_class = ++ KVM_LOONGARCH_PCH_PIC_GET_CLASS(dev); ++ struct kvm_create_device cd = {0}; ++ uint64_t pch_pic_base = VIRT_PCH_REG_BASE; ++ Error *err = NULL; ++ int ret; ++ ++ pch_pic_class->parent_realize(dev, &err); ++ if (err) { ++ error_propagate(errp, err); ++ return; ++ } ++ ++ if (!pch_pic_class->is_created) { ++ cd.type = KVM_DEV_TYPE_LA_PCH_PIC; ++ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); ++ if (ret < 0) { ++ error_setg_errno(errp, errno, ++ "Creating the KVM pch pic device failed"); ++ return; ++ } ++ pch_pic_class->is_created = true; ++ pch_pic_class->dev_fd = cd.fd; ++ fprintf(stdout, "Create LoongArch pch pic irqchip in KVM done!\n"); ++ ++ ret = kvm_device_access(cd.fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL, ++ KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT, ++ &pch_pic_base, true, NULL); ++ if (ret < 0) { ++ error_report( ++ "KVM EXTIOI: failed to set the base address of EXTIOI"); ++ exit(1); ++ } ++ ++ qdev_init_gpio_in(dev, kvm_pch_pic_handler, VIRT_PCH_PIC_IRQ_NUM); ++ } ++} ++ ++static const VMStateDescription vmstate_kvm_loongarch_pch_pic = { ++ .name = TYPE_LOONGARCH_PCH_PIC, ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = kvm_loongarch_pch_pic_pre_save, ++ .post_load = kvm_loongarch_pch_pic_post_load, ++ .fields = (const VMStateField[]) { ++ VMSTATE_UINT64(int_mask, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(htmsi_en, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(intedge, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(intclr, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(auto_crtl0, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(auto_crtl1, KVMLoongArchPCHPIC), ++ VMSTATE_UINT8_ARRAY(route_entry, KVMLoongArchPCHPIC, 64), ++ VMSTATE_UINT8_ARRAY(htmsi_vector, KVMLoongArchPCHPIC, 64), ++ VMSTATE_UINT64(last_intirr, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(intirr, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(intisr, KVMLoongArchPCHPIC), ++ VMSTATE_UINT64(int_polarity, KVMLoongArchPCHPIC), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++static void kvm_loongarch_pch_pic_class_init(ObjectClass *oc, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(oc); ++ KVMLoongArchPCHPICClass *pch_pic_class = KVM_LOONGARCH_PCH_PIC_CLASS(oc); ++ ++ pch_pic_class->parent_realize = dc->realize; ++ dc->realize = kvm_loongarch_pch_pic_realize; ++ pch_pic_class->is_created = false; ++ dc->vmsd = &vmstate_kvm_loongarch_pch_pic; ++ ++} ++ ++static const TypeInfo kvm_loongarch_pch_pic_info = { ++ .name = TYPE_KVM_LOONGARCH_PCH_PIC, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(KVMLoongArchPCHPIC), ++ .class_size = sizeof(KVMLoongArchPCHPICClass), ++ .class_init = kvm_loongarch_pch_pic_class_init, ++}; ++ ++static void kvm_loongarch_pch_pic_register_types(void) ++{ ++ type_register_static(&kvm_loongarch_pch_pic_info); ++} ++ ++type_init(kvm_loongarch_pch_pic_register_types) +diff --git a/hw/intc/meson.build b/hw/intc/meson.build +index a37d7da8aa..49b4501315 100644 +--- a/hw/intc/meson.build ++++ b/hw/intc/meson.build +@@ -75,3 +75,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_ + specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c')) + specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI_KVM', if_true: files('loongarch_extioi_kvm.c')) ++specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC_KVM', if_true: files('loongarch_pch_pic_kvm.c')) +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index 1a47d44a64..16c854c0d5 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -15,6 +15,7 @@ config LOONGARCH_VIRT + select LOONGARCH_PCH_MSI + select LOONGARCH_EXTIOI + select LOONGARCH_IPI_KVM if KVM ++ select LOONGARCH_PCH_PIC_KVM if KVM + select LOONGARCH_EXTIOI_KVM if KVM + select LS7A_RTC + select SMBIOS +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 71e2a3735c..270dcfd38f 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -901,45 +901,49 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + /* Add Extend I/O Interrupt Controller node */ + fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle); + +- pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); +- num = VIRT_PCH_PIC_IRQ_NUM; +- qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num); +- d = SYS_BUS_DEVICE(pch_pic); +- sysbus_realize_and_unref(d, &error_fatal); +- memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, +- sysbus_mmio_get_region(d, 0)); +- memory_region_add_subregion(get_system_memory(), +- VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, +- sysbus_mmio_get_region(d, 1)); +- memory_region_add_subregion(get_system_memory(), +- VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, +- sysbus_mmio_get_region(d, 2)); +- +- /* Connect pch_pic irqs to extioi */ +- for (i = 0; i < num; i++) { +- qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); +- } +- + /* Add PCH PIC node */ + fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle); + +- pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); +- start = num; +- num = EXTIOI_IRQS - start; +- qdev_prop_set_uint32(pch_msi, "msi_irq_base", start); +- qdev_prop_set_uint32(pch_msi, "msi_irq_num", num); +- d = SYS_BUS_DEVICE(pch_msi); +- sysbus_realize_and_unref(d, &error_fatal); +- sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); +- for (i = 0; i < num; i++) { +- /* Connect pch_msi irqs to extioi */ +- qdev_connect_gpio_out(DEVICE(d), i, +- qdev_get_gpio_in(extioi, i + start)); +- } +- + /* Add PCH MSI node */ + fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle); + ++ if (kvm_enabled() && kvm_irqchip_in_kernel()) { ++ pch_pic = qdev_new(TYPE_KVM_LOONGARCH_PCH_PIC); ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(pch_pic), &error_fatal); ++ } else { ++ pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); ++ num = VIRT_PCH_PIC_IRQ_NUM; ++ qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num); ++ d = SYS_BUS_DEVICE(pch_pic); ++ sysbus_realize_and_unref(d, &error_fatal); ++ memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, ++ sysbus_mmio_get_region(d, 0)); ++ memory_region_add_subregion(get_system_memory(), ++ VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, ++ sysbus_mmio_get_region(d, 1)); ++ memory_region_add_subregion(get_system_memory(), ++ VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, ++ sysbus_mmio_get_region(d, 2)); ++ /* Connect pch_pic irqs to extioi */ ++ for (i = 0; i < num; i++) { ++ qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); ++ } ++ ++ pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); ++ start = num; ++ num = EXTIOI_IRQS - start; ++ qdev_prop_set_uint32(pch_msi, "msi_irq_base", start); ++ qdev_prop_set_uint32(pch_msi, "msi_irq_num", num); ++ d = SYS_BUS_DEVICE(pch_msi); ++ sysbus_realize_and_unref(d, &error_fatal); ++ sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); ++ for (i = 0; i < num; i++) { ++ /* Connect pch_msi irqs to extioi */ ++ qdev_connect_gpio_out(DEVICE(d), i, ++ qdev_get_gpio_in(extioi, i + start)); ++ } ++ } ++ + virt_devices_init(pch_pic, lvms, &pch_pic_phandle, &pch_msi_phandle); + } + +diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h +index d5437e88f2..77f4cd74a1 100644 +--- a/include/hw/intc/loongarch_pch_pic.h ++++ b/include/hw/intc/loongarch_pch_pic.h +@@ -7,7 +7,8 @@ + + #include "hw/sysbus.h" + +-#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic" ++#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic" ++#define TYPE_KVM_LOONGARCH_PCH_PIC "loongarch_kvm_pch_pic" + #define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC) + +@@ -37,6 +38,19 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC) + #define PCH_PIC_INT_POL_LO 0x3e0 + #define PCH_PIC_INT_POL_HI 0x3e4 + ++#define PCH_PIC_INT_ID_START PCH_PIC_INT_ID_LO ++#define PCH_PIC_MASK_START PCH_PIC_INT_MASK_LO ++#define PCH_PIC_HTMSI_EN_START PCH_PIC_HTMSI_EN_LO ++#define PCH_PIC_EDGE_START PCH_PIC_INT_EDGE_LO ++#define PCH_PIC_CLEAR_START PCH_PIC_INT_CLEAR_LO ++#define PCH_PIC_AUTO_CTRL0_START PCH_PIC_AUTO_CTRL0_LO ++#define PCH_PIC_AUTO_CTRL1_START PCH_PIC_AUTO_CTRL1_LO ++#define PCH_PIC_ROUTE_ENTRY_START PCH_PIC_ROUTE_ENTRY_OFFSET ++#define PCH_PIC_HTMSI_VEC_START PCH_PIC_HTMSI_VEC_OFFSET ++#define PCH_PIC_INT_IRR_START 0x380 ++#define PCH_PIC_INT_ISR_START PCH_PIC_INT_STATUS_LO ++#define PCH_PIC_POLARITY_START PCH_PIC_INT_POL_LO ++ + #define STATUS_LO_START 0 + #define STATUS_HI_START 0x4 + #define POL_LO_START 0x40 +@@ -67,3 +81,38 @@ struct LoongArchPCHPIC { + MemoryRegion iomem8; + unsigned int irq_num; + }; ++ ++struct KVMLoongArchPCHPIC { ++ SysBusDevice parent_obj; ++ 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*/ ++ uint64_t last_intirr; /* edge detection */ ++ uint64_t intirr; /* 0x380 interrupt request register */ ++ uint64_t intisr; /* 0x3a0 interrupt service register */ ++ /* ++ * 0x3e0 interrupt level polarity selection ++ * register 0 for high level trigger ++ */ ++ uint64_t int_polarity; ++ ++ uint8_t route_entry[64]; /*0x100 - 0x138*/ ++ uint8_t htmsi_vector[64]; /*0x200 - 0x238*/ ++}; ++typedef struct KVMLoongArchPCHPIC KVMLoongArchPCHPIC; ++DECLARE_INSTANCE_CHECKER(KVMLoongArchPCHPIC, KVM_LOONGARCH_PCH_PIC, ++ TYPE_KVM_LOONGARCH_PCH_PIC) ++ ++struct KVMLoongArchPCHPICClass { ++ SysBusDeviceClass parent_class; ++ DeviceRealize parent_realize; ++ ++ bool is_created; ++ int dev_fd; ++}; ++typedef struct KVMLoongArchPCHPICClass KVMLoongArchPCHPICClass; ++DECLARE_CLASS_CHECKERS(KVMLoongArchPCHPICClass, KVM_LOONGARCH_PCH_PIC, ++ TYPE_KVM_LOONGARCH_PCH_PIC) +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 0c0b82d1ef..887f8268e7 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1470,6 +1470,8 @@ enum kvm_device_type { + #define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME + KVM_DEV_TYPE_RISCV_AIA, + #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA ++ KVM_DEV_TYPE_LA_PCH_PIC = 0x100, ++#define KVM_DEV_TYPE_LA_PCH_PIC KVM_DEV_TYPE_LA_PCH_PIC + KVM_DEV_TYPE_LA_IPI, + #define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI + KVM_DEV_TYPE_LA_EXTIOI, +-- +2.39.1 + diff --git a/hw-loongarch-Add-VM-mode-in-IOCSR-feature-register-i.patch b/hw-loongarch-Add-VM-mode-in-IOCSR-feature-register-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..83747a78ed933e050ab7441b40082cb4bb608087 --- /dev/null +++ b/hw-loongarch-Add-VM-mode-in-IOCSR-feature-register-i.patch @@ -0,0 +1,49 @@ +From 0437c11a20b3c66882770e468518d33ff71a932a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 14 May 2024 10:51:09 +0800 +Subject: [PATCH 22/78] hw/loongarch: Add VM mode in IOCSR feature register in + kvm mode + +If VM runs in kvm mode, VM mode is added in IOCSR feature register. +So guest can detect kvm hypervisor type and enable possible pv functions. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240514025109.3238398-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index e82e3b6792..c3514f9293 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -10,6 +10,7 @@ + #include "qapi/error.h" + #include "hw/boards.h" + #include "hw/char/serial.h" ++#include "sysemu/kvm.h" + #include "sysemu/sysemu.h" + #include "sysemu/qtest.h" + #include "sysemu/runstate.h" +@@ -914,12 +915,11 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, + ret = 0x11ULL; + break; + case FEATURE_REG: +- ret = 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI | +- 1ULL << IOCSRF_CSRIPI; ++ ret = BIT(IOCSRF_MSI) | BIT(IOCSRF_EXTIOI) | BIT(IOCSRF_CSRIPI); + if (kvm_enabled()) { +- ret |= 1ULL << IOCSRF_VM; ++ ret |= BIT(IOCSRF_VM); + } +- break; ++ return ret; + case VENDOR_REG: + ret = 0x6e6f73676e6f6f4cULL; /* "Loongson" */ + break; +-- +2.39.1 + diff --git a/hw-loongarch-Add-acpi-SPCR-table-support.patch b/hw-loongarch-Add-acpi-SPCR-table-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..0bb637abeedce204b04806a1ac946f4cedb3351f --- /dev/null +++ b/hw-loongarch-Add-acpi-SPCR-table-support.patch @@ -0,0 +1,82 @@ +From fe22e0efe4c1c99fc876a42446cb2c87f9457afb Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sat, 7 Sep 2024 15:30:37 +0800 +Subject: [PATCH 37/78] hw/loongarch: Add acpi SPCR table support + +Serial port console redirection table can be used for default serial +port selection, like chosen stdout-path selection with FDT method. + +With acpi SPCR table added, early debug console can be parsed from +SPCR table with simple kernel parameter earlycon rather than +earlycon=uart,mmio,0x1fe001e0 + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240907073037.243353-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/acpi-build.c | 40 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index 33a92223d8..bcdec2e1cb 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -242,6 +242,44 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + acpi_table_end(linker, &table); + } + ++/* ++ * Serial Port Console Redirection Table (SPCR) ++ * https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table ++ */ ++static void ++spcr_setup(GArray *table_data, BIOSLinker *linker, MachineState *machine) ++{ ++ LoongArchVirtMachineState *lvms; ++ AcpiSpcrData serial = { ++ .interface_type = 0, /* 16550 compatible */ ++ .base_addr.id = AML_AS_SYSTEM_MEMORY, ++ .base_addr.width = 32, ++ .base_addr.offset = 0, ++ .base_addr.size = 1, ++ .base_addr.addr = VIRT_UART_BASE, ++ .interrupt_type = 0, /* Interrupt not supported */ ++ .pc_interrupt = 0, ++ .interrupt = VIRT_UART_IRQ, ++ .baud_rate = 7, /* 115200 */ ++ .parity = 0, ++ .stop_bits = 1, ++ .flow_control = 0, ++ .terminal_type = 3, /* ANSI */ ++ .language = 0, /* Language */ ++ .pci_device_id = 0xffff, /* not a PCI device*/ ++ .pci_vendor_id = 0xffff, /* not a PCI device*/ ++ .pci_bus = 0, ++ .pci_device = 0, ++ .pci_function = 0, ++ .pci_flags = 0, ++ .pci_segment = 0, ++ }; ++ ++ lvms = LOONGARCH_VIRT_MACHINE(machine); ++ build_spcr(table_data, linker, &serial, 2, lvms->oem_id, ++ lvms->oem_table_id); ++} ++ + typedef + struct AcpiBuildState { + /* Copy of table in RAM (for patching). */ +@@ -484,6 +522,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + + acpi_add_table(table_offsets, tables_blob); + build_srat(tables_blob, tables->linker, machine); ++ acpi_add_table(table_offsets, tables_blob); ++ spcr_setup(tables_blob, tables->linker, machine); + + if (machine->numa_state->num_nodes) { + if (machine->numa_state->have_numa_distance) { +-- +2.39.1 + diff --git a/hw-loongarch-Add-cells-missing-from-rtc-node.patch b/hw-loongarch-Add-cells-missing-from-rtc-node.patch new file mode 100644 index 0000000000000000000000000000000000000000..371b2d3a66c4cc81ebb60a1b8290a74a3db3f9b1 --- /dev/null +++ b/hw-loongarch-Add-cells-missing-from-rtc-node.patch @@ -0,0 +1,56 @@ +From 7266141c658cd00426922534a7de4dd5d89486b2 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:51 +0800 +Subject: [PATCH 16/78] hw/loongarch: Add cells missing from rtc node + +rtc node need interrupts and interrupt-parent cells. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-18-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index a6aea52ebb..0972ebd150 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -258,7 +258,8 @@ static void fdt_add_flash_node(LoongArchMachineState *lams) + g_free(nodename); + } + +-static void fdt_add_rtc_node(LoongArchMachineState *lams) ++static void fdt_add_rtc_node(LoongArchMachineState *lams, ++ uint32_t *pch_pic_phandle) + { + char *nodename; + hwaddr base = VIRT_RTC_REG_BASE; +@@ -267,8 +268,13 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams) + + nodename = g_strdup_printf("/rtc@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); +- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "loongson,ls7a-rtc"); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,ls7a-rtc"); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", ++ VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *pch_pic_phandle); + g_free(nodename); + } + +@@ -677,7 +683,7 @@ static void loongarch_devices_init(DeviceState *pch_pic, + sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE, + qdev_get_gpio_in(pch_pic, + VIRT_RTC_IRQ - VIRT_GSI_BASE)); +- fdt_add_rtc_node(lams); ++ fdt_add_rtc_node(lams, pch_pic_phandle); + + /* acpi ged */ + lams->acpi_ged = create_acpi_ged(pch_pic, lams); +-- +2.39.1 + diff --git a/hw-loongarch-Add-cells-missing-from-uart-node.patch b/hw-loongarch-Add-cells-missing-from-uart-node.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c20bb3c79c2cc5024225de154e7a5276ce36122 --- /dev/null +++ b/hw-loongarch-Add-cells-missing-from-uart-node.patch @@ -0,0 +1,52 @@ +From 33994eff45e75e91acf0a4753fec77ad0027e4dd Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:50 +0800 +Subject: [PATCH 15/78] hw/loongarch: Add cells missing from uart node + +uart node need interrupts and interrupt-parent cells. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-17-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index ff9513034b..a6aea52ebb 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -272,7 +272,8 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams) + g_free(nodename); + } + +-static void fdt_add_uart_node(LoongArchMachineState *lams) ++static void fdt_add_uart_node(LoongArchMachineState *lams, ++ uint32_t *pch_pic_phandle) + { + char *nodename; + hwaddr base = VIRT_UART_BASE; +@@ -285,6 +286,10 @@ static void fdt_add_uart_node(LoongArchMachineState *lams) + qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size); + qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000); + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", ++ VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *pch_pic_phandle); + g_free(nodename); + } + +@@ -657,7 +662,7 @@ static void loongarch_devices_init(DeviceState *pch_pic, + qdev_get_gpio_in(pch_pic, + VIRT_UART_IRQ - VIRT_GSI_BASE), + 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); +- fdt_add_uart_node(lams); ++ fdt_add_uart_node(lams, pch_pic_phandle); + + /* Network init */ + for (i = 0; i < nb_nics; i++) { +-- +2.39.1 + diff --git a/hw-loongarch-Add-init_cmdline.patch b/hw-loongarch-Add-init_cmdline.patch new file mode 100644 index 0000000000000000000000000000000000000000..ba6e03e9512cb3e0532490180e032b28105d7cb1 --- /dev/null +++ b/hw-loongarch-Add-init_cmdline.patch @@ -0,0 +1,117 @@ +From 206b799cb8c218c744f4dcdaf161d11f14c21e0f Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:38 +0800 +Subject: [PATCH 04/78] hw/loongarch: Add init_cmdline + +Add init_cmline and set boot_info->a0, a1 + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-5-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 30 ++++++++++++++++++++++++++++++ + include/hw/loongarch/virt.h | 2 ++ + target/loongarch/cpu.h | 2 ++ + 3 files changed, 34 insertions(+) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index fb6effbaff..127085bcc4 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -63,6 +63,16 @@ static const unsigned int slave_boot_code[] = { + 0x4c000020, /* jirl $zero, $ra,0 */ + }; + ++static void init_cmdline(struct loongarch_boot_info *info, void *p, void *start) ++{ ++ hwaddr cmdline_addr = p - start; ++ ++ info->a0 = 1; ++ info->a1 = cmdline_addr; ++ ++ memcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE); ++} ++ + static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) + { + return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); +@@ -121,6 +131,10 @@ static void reset_load_elf(void *opaque) + + cpu_reset(CPU(cpu)); + if (env->load_elf) { ++ if (cpu == LOONGARCH_CPU(first_cpu)) { ++ env->gpr[4] = env->boot_info->a0; ++ env->gpr[5] = env->boot_info->a1; ++ } + cpu_set_pc(CPU(cpu), env->elf_address); + } + } +@@ -158,8 +172,17 @@ static void loongarch_firmware_boot(LoongArchMachineState *lams, + fw_cfg_add_kernel_info(info, lams->fw_cfg); + } + ++static void init_boot_rom(struct loongarch_boot_info *info, void *p) ++{ ++ void *start = p; ++ ++ init_cmdline(info, p, start); ++ p += COMMAND_LINE_SIZE; ++} ++ + static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + { ++ void *p, *bp; + int64_t kernel_addr = 0; + LoongArchCPU *lacpu; + CPUState *cs; +@@ -173,6 +196,12 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + } + } + ++ /* Load cmdline and system tables at [0 - 1 MiB] */ ++ p = g_malloc0(1 * MiB); ++ bp = p; ++ init_boot_rom(info, p); ++ rom_add_blob_fixed_as("boot_info", bp, 1 * MiB, 0, &address_space_memory); ++ + /* Load slave boot code at pflash0 . */ + void *boot_code = g_malloc0(VIRT_FLASH0_SIZE); + memcpy(boot_code, &slave_boot_code, sizeof(slave_boot_code)); +@@ -190,6 +219,7 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + } + + g_free(boot_code); ++ g_free(bp); + } + + void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info) +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 02c8234b8d..ffff075f63 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -33,6 +33,8 @@ + #define VIRT_GED_MEM_ADDR (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN) + #define VIRT_GED_REG_ADDR (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN) + ++#define COMMAND_LINE_SIZE 512 ++ + struct LoongArchMachineState { + /*< private >*/ + MachineState parent_obj; +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 0ed24051af..e3a15c593f 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -364,6 +364,8 @@ typedef struct CPUArchState { + uint32_t mp_state; + /* Store ipistate to access from this struct */ + DeviceState *ipistate; ++ ++ struct loongarch_boot_info *boot_info; + #endif + struct { + uint64_t guest_addr; +-- +2.39.1 + diff --git a/hw-loongarch-Add-load-initrd.patch b/hw-loongarch-Add-load-initrd.patch new file mode 100644 index 0000000000000000000000000000000000000000..8714697780f0778debf62d9d4b6fdf40cf915318 --- /dev/null +++ b/hw-loongarch-Add-load-initrd.patch @@ -0,0 +1,64 @@ +From 02c5f52da7f9458c0fc41e43f181f6e9b7101b57 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:36 +0800 +Subject: [PATCH 02/78] hw/loongarch: Add load initrd + +we load initrd ramdisk after kernel_high address + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-3-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 28 +++++++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index 9feed17db3..a5135fe542 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -22,7 +22,8 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) + + static int64_t load_kernel_info(struct loongarch_boot_info *info) + { +- uint64_t kernel_entry, kernel_low, kernel_high; ++ uint64_t kernel_entry, kernel_low, kernel_high, initrd_size; ++ ram_addr_t initrd_offset; + ssize_t kernel_size; + + kernel_size = load_elf(info->kernel_filename, NULL, +@@ -37,6 +38,31 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) + load_elf_strerror(kernel_size)); + exit(1); + } ++ ++ if (info->initrd_filename) { ++ initrd_size = get_image_size(info->initrd_filename); ++ if (initrd_size > 0) { ++ initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB); ++ ++ if (initrd_offset + initrd_size > info->ram_size) { ++ error_report("memory too small for initial ram disk '%s'", ++ info->initrd_filename); ++ exit(1); ++ } ++ ++ initrd_size = load_image_targphys(info->initrd_filename, initrd_offset, ++ info->ram_size - initrd_offset); ++ } ++ ++ if (initrd_size == (target_ulong)-1) { ++ error_report("could not load initial ram disk '%s'", ++ info->initrd_filename); ++ exit(1); ++ } ++ } else { ++ initrd_size = 0; ++ } ++ + return kernel_entry; + } + +-- +2.39.1 + diff --git a/hw-loongarch-Add-slave-cpu-boot_code.patch b/hw-loongarch-Add-slave-cpu-boot_code.patch new file mode 100644 index 0000000000000000000000000000000000000000..39e1c24fd7521d35780091da6734fa2456a83223 --- /dev/null +++ b/hw-loongarch-Add-slave-cpu-boot_code.patch @@ -0,0 +1,103 @@ +From 2e3e7bcf92284f41c08fce29f6c6d45849721e71 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:37 +0800 +Subject: [PATCH 03/78] hw/loongarch: Add slave cpu boot_code + +Load the slave CPU boot code at pflash0 and set +the slave CPU elf_address to VIRT_FLASH0_BASE. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-4-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 62 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 61 insertions(+), 1 deletion(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index a5135fe542..fb6effbaff 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -15,6 +15,54 @@ + #include "sysemu/reset.h" + #include "sysemu/qtest.h" + ++static const unsigned int slave_boot_code[] = { ++ /* Configure reset ebase. */ ++ 0x0400302c, /* csrwr $t0, LOONGARCH_CSR_EENTRY */ ++ ++ /* Disable interrupt. */ ++ 0x0380100c, /* ori $t0, $zero,0x4 */ ++ 0x04000180, /* csrxchg $zero, $t0, LOONGARCH_CSR_CRMD */ ++ ++ /* Clear mailbox. */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038081ad, /* ori $t1, $t1, CORE_BUF_20 */ ++ 0x06481da0, /* iocsrwr.d $zero, $t1 */ ++ ++ /* Enable IPI interrupt. */ ++ 0x1400002c, /* lu12i.w $t0, 1(0x1) */ ++ 0x0400118c, /* csrxchg $t0, $t0, LOONGARCH_CSR_ECFG */ ++ 0x02fffc0c, /* addi.d $t0, $r0,-1(0xfff) */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038011ad, /* ori $t1, $t1, CORE_EN_OFF */ ++ 0x064819ac, /* iocsrwr.w $t0, $t1 */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038081ad, /* ori $t1, $t1, CORE_BUF_20 */ ++ ++ /* Wait for wakeup <.L11>: */ ++ 0x06488000, /* idle 0x0 */ ++ 0x03400000, /* andi $zero, $zero, 0x0 */ ++ 0x064809ac, /* iocsrrd.w $t0, $t1 */ ++ 0x43fff59f, /* beqz $t0, -12(0x7ffff4) # 48 <.L11> */ ++ ++ /* Read and clear IPI interrupt. */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x064809ac, /* iocsrrd.w $t0, $t1 */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038031ad, /* ori $t1, $t1, CORE_CLEAR_OFF */ ++ 0x064819ac, /* iocsrwr.w $t0, $t1 */ ++ ++ /* Disable IPI interrupt. */ ++ 0x1400002c, /* lu12i.w $t0, 1(0x1) */ ++ 0x04001180, /* csrxchg $zero, $t0, LOONGARCH_CSR_ECFG */ ++ ++ /* Read mail buf and jump to specified entry */ ++ 0x1400002d, /* lu12i.w $t1, 1(0x1) */ ++ 0x038081ad, /* ori $t1, $t1, CORE_BUF_20 */ ++ 0x06480dac, /* iocsrrd.d $t0, $t1 */ ++ 0x00150181, /* move $ra, $t0 */ ++ 0x4c000020, /* jirl $zero, $ra,0 */ ++}; ++ + static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) + { + return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); +@@ -125,11 +173,23 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + } + } + ++ /* Load slave boot code at pflash0 . */ ++ void *boot_code = g_malloc0(VIRT_FLASH0_SIZE); ++ memcpy(boot_code, &slave_boot_code, sizeof(slave_boot_code)); ++ rom_add_blob_fixed("boot_code", boot_code, VIRT_FLASH0_SIZE, VIRT_FLASH0_BASE); ++ + CPU_FOREACH(cs) { + lacpu = LOONGARCH_CPU(cs); + lacpu->env.load_elf = true; +- lacpu->env.elf_address = kernel_addr; ++ if (cs == first_cpu) { ++ lacpu->env.elf_address = kernel_addr; ++ } else { ++ lacpu->env.elf_address = VIRT_FLASH0_BASE; ++ } ++ lacpu->env.boot_info = info; + } ++ ++ g_free(boot_code); + } + + void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info) +-- +2.39.1 + diff --git a/hw-loongarch-Change-the-tpm-support-by-default.patch b/hw-loongarch-Change-the-tpm-support-by-default.patch new file mode 100644 index 0000000000000000000000000000000000000000..11ae7455681fc2b37829ac7de30805751a90123d --- /dev/null +++ b/hw-loongarch-Change-the-tpm-support-by-default.patch @@ -0,0 +1,46 @@ +From 67c68371e457a85e460221a8c56d8dc93186f79f Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Mon, 24 Jun 2024 11:23:00 +0800 +Subject: [PATCH 31/78] hw/loongarch: Change the tpm support by default + +Add devices that support tpm by default, +Fixed incomplete tpm acpi table information. + +Signed-off-by: Xianglai Li +Reviewed-by: Song Gao +Message-Id: <20240624032300.999157-1-lixianglai@loongson.cn> +Signed-off-by: Song Gao +--- + hw/loongarch/Kconfig | 1 + + hw/loongarch/acpi-build.c | 3 +++ + 2 files changed, 4 insertions(+) + +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index 7864050563..b2a3adb7dc 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -7,6 +7,7 @@ config LOONGARCH_VIRT + imply VIRTIO_VGA + imply PCI_DEVICES + imply NVDIMM ++ imply TPM_TIS_SYSBUS + select SERIAL + select VIRTIO_PCI + select PLATFORM_BUS +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index 2555c6763c..6593476409 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -646,6 +646,9 @@ void loongarch_acpi_setup(LoongArchVirtMachineState *lvms) + build_state, tables.rsdp, + ACPI_BUILD_RSDP_FILE); + ++ fw_cfg_add_file(lvms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, ++ acpi_data_len(tables.tcpalog)); ++ + qemu_register_reset(acpi_build_reset, build_state); + acpi_build_reset(build_state); + vmstate_register(NULL, 0, &vmstate_acpi_build, build_state); +-- +2.39.1 + diff --git a/hw-loongarch-Fix-length-for-lowram-in-ACPI-SRAT.patch b/hw-loongarch-Fix-length-for-lowram-in-ACPI-SRAT.patch new file mode 100644 index 0000000000000000000000000000000000000000..c4413facfbe8db368ad24f9a40fccabd8c601aff --- /dev/null +++ b/hw-loongarch-Fix-length-for-lowram-in-ACPI-SRAT.patch @@ -0,0 +1,39 @@ +From 087201cd62e71801855775c3aa6395c7e1c00cee Mon Sep 17 00:00:00 2001 +From: Jiaxun Yang +Date: Tue, 20 Aug 2024 19:42:33 +0100 +Subject: [PATCH 33/78] hw/loongarch: Fix length for lowram in ACPI SRAT + +The size of lowram should be "gap" instead of the whole node. + +This is failing kernel's sanity check: + +[ 0.000000] ACPI: SRAT: Node 0 PXM 0 [mem 0x00000000-0xffffffff] +[ 0.000000] ACPI: SRAT: Node 0 PXM 0 [mem 0x80000000-0x16fffffff] +[ 0.000000] ACPI: SRAT: Node 1 PXM 1 [mem 0x170000000-0x26fffffff] +[ 0.000000] Warning: node 0 [mem 0x00000000-0xffffffff] overlaps with itself [mem 0x80000000-0x16fffffff] + +Fixes: fc100011f38d ("hw/loongarch: Refine acpi srat table for numa memory") +Signed-off-by: Jiaxun Yang +Reviewed-by: Bibo Mao +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/acpi-build.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index 6593476409..1a9d25fc51 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -218,7 +218,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + * highram: [VIRT_HIGHMEM_BASE, +(len - gap)) + */ + if (len >= gap) { +- build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED); ++ build_srat_memory(table_data, base, gap, i, MEM_AFFINITY_ENABLED); + len -= gap; + base = VIRT_HIGHMEM_BASE; + gap = machine->ram_size - VIRT_LOWMEM_SIZE; +-- +2.39.1 + diff --git a/hw-loongarch-Init-efi_boot_memmap-table.patch b/hw-loongarch-Init-efi_boot_memmap-table.patch new file mode 100644 index 0000000000000000000000000000000000000000..092667720a6ee1dc2626e738c8f96667985b0f42 --- /dev/null +++ b/hw-loongarch-Init-efi_boot_memmap-table.patch @@ -0,0 +1,169 @@ +From 0245881108803abedf50e954d34ebcfff294d1c3 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:40 +0800 +Subject: [PATCH 06/78] hw/loongarch: Init efi_boot_memmap table + +The efi_system_table adds a efi_boot_memmap configuration table. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-7-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 40 +++++++++++++++++++++++++++++++++++++ + hw/loongarch/virt.c | 11 ++-------- + include/hw/loongarch/boot.h | 27 +++++++++++++++++++++++++ + include/hw/loongarch/virt.h | 10 ++++++++++ + 4 files changed, 79 insertions(+), 9 deletions(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index 59889dbc90..527fc9c0be 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -63,8 +63,41 @@ static const unsigned int slave_boot_code[] = { + 0x4c000020, /* jirl $zero, $ra,0 */ + }; + ++static inline void *guidcpy(void *dst, const void *src) ++{ ++ return memcpy(dst, src, sizeof(efi_guid_t)); ++} ++ ++static void init_efi_boot_memmap(struct efi_system_table *systab, ++ void *p, void *start) ++{ ++ unsigned i; ++ struct efi_boot_memmap *boot_memmap = p; ++ efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID; ++ ++ /* efi_configuration_table 1 */ ++ guidcpy(&systab->tables[0].guid, &tbl_guid); ++ systab->tables[0].table = (struct efi_configuration_table *)(p - start); ++ systab->nr_tables = 1; ++ ++ boot_memmap->desc_size = sizeof(efi_memory_desc_t); ++ boot_memmap->desc_ver = 1; ++ boot_memmap->map_size = 0; ++ ++ efi_memory_desc_t *map = p + sizeof(struct efi_boot_memmap); ++ for (i = 0; i < memmap_entries; i++) { ++ map = (void *)boot_memmap + sizeof(*map); ++ map[i].type = memmap_table[i].type; ++ map[i].phys_addr = ROUND_UP(memmap_table[i].address, 64 * KiB); ++ map[i].num_pages = ROUND_DOWN(memmap_table[i].address + ++ memmap_table[i].length - map[i].phys_addr, 64 * KiB); ++ p += sizeof(efi_memory_desc_t); ++ } ++} ++ + static void init_systab(struct loongarch_boot_info *info, void *p, void *start) + { ++ void *bp_tables_start; + struct efi_system_table *systab = p; + + info->a2 = p - start; +@@ -80,6 +113,13 @@ static void init_systab(struct loongarch_boot_info *info, void *p, void *start) + p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB); + + systab->tables = p; ++ bp_tables_start = p; ++ ++ init_efi_boot_memmap(systab, p, start); ++ p += ROUND_UP(sizeof(struct efi_boot_memmap) + ++ sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB); ++ ++ systab->tables = (struct efi_configuration_table *)(bp_tables_start - start); + } + + static void init_cmdline(struct loongarch_boot_info *info, void *p, void *start) +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index a0aee28f41..028356acf5 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -405,15 +405,8 @@ static void virt_powerdown_req(Notifier *notifier, void *opaque) + acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS); + } + +-struct memmap_entry { +- uint64_t address; +- uint64_t length; +- uint32_t type; +- uint32_t reserved; +-}; +- +-static struct memmap_entry *memmap_table; +-static unsigned memmap_entries; ++struct memmap_entry *memmap_table; ++unsigned memmap_entries; + + static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) + { +diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h +index cf0e4d4f91..76622af2e2 100644 +--- a/include/hw/loongarch/boot.h ++++ b/include/hw/loongarch/boot.h +@@ -21,6 +21,15 @@ typedef struct { + uint8_t b[16]; + } efi_guid_t QEMU_ALIGNED(8); + ++#define EFI_GUID(a, b, c, d...) (efi_guid_t){ { \ ++ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ ++ (b) & 0xff, ((b) >> 8) & 0xff, \ ++ (c) & 0xff, ((c) >> 8) & 0xff, d } } ++ ++#define LINUX_EFI_BOOT_MEMMAP_GUID \ ++ EFI_GUID(0x800f683f, 0xd08b, 0x423a, 0xa2, 0x93, \ ++ 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4) ++ + struct efi_config_table { + efi_guid_t guid; + uint64_t *ptr; +@@ -56,6 +65,24 @@ struct efi_system_table { + struct efi_configuration_table *tables; + }; + ++typedef struct { ++ uint32_t type; ++ uint32_t pad; ++ uint64_t phys_addr; ++ uint64_t virt_addr; ++ uint64_t num_pages; ++ uint64_t attribute; ++} efi_memory_desc_t; ++ ++struct efi_boot_memmap { ++ uint64_t map_size; ++ uint64_t desc_size; ++ uint32_t desc_ver; ++ uint64_t map_key; ++ uint64_t buff_size; ++ efi_memory_desc_t map[32]; ++}; ++ + struct loongarch_boot_info { + uint64_t ram_size; + const char *kernel_filename; +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index ffff075f63..2f9eaf4b0e 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -35,6 +35,16 @@ + + #define COMMAND_LINE_SIZE 512 + ++extern struct memmap_entry *memmap_table; ++extern unsigned memmap_entries; ++ ++struct memmap_entry { ++ uint64_t address; ++ uint64_t length; ++ uint32_t type; ++ uint32_t reserved; ++}; ++ + struct LoongArchMachineState { + /*< private >*/ + MachineState parent_obj; +-- +2.39.1 + diff --git a/hw-loongarch-Init-efi_fdt-table.patch b/hw-loongarch-Init-efi_fdt-table.patch new file mode 100644 index 0000000000000000000000000000000000000000..545da6489517f72cf0194fda693664a91921461c --- /dev/null +++ b/hw-loongarch-Init-efi_fdt-table.patch @@ -0,0 +1,105 @@ +From 605b2b372f972fffa2d198d8dee4cf37f335559d Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:42 +0800 +Subject: [PATCH 08/78] hw/loongarch: Init efi_fdt table + +The efi_system_table adds a efi_fdt configuration table. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-9-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 11 +++++++++++ + hw/loongarch/virt.c | 6 ++---- + include/hw/loongarch/boot.h | 4 ++++ + include/hw/loongarch/virt.h | 2 ++ + 4 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index c8b3e742b4..7d1630b2e7 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -113,6 +113,16 @@ static void init_efi_initrd_table(struct efi_system_table *systab, + initrd_table->size = initrd_size; + } + ++static void init_efi_fdt_table(struct efi_system_table *systab) ++{ ++ efi_guid_t tbl_guid = DEVICE_TREE_GUID; ++ ++ /* efi_configuration_table 3 */ ++ guidcpy(&systab->tables[2].guid, &tbl_guid); ++ systab->tables[2].table = (void *)FDT_BASE; ++ systab->nr_tables = 3; ++} ++ + static void init_systab(struct loongarch_boot_info *info, void *p, void *start) + { + void *bp_tables_start; +@@ -138,6 +148,7 @@ static void init_systab(struct loongarch_boot_info *info, void *p, void *start) + sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB); + init_efi_initrd_table(systab, p, start); + p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB); ++ init_efi_fdt_table(systab); + + systab->tables = (struct efi_configuration_table *)(bp_tables_start - start); + } +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 028356acf5..99a3dc8696 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -820,7 +820,6 @@ static void loongarch_init(MachineState *machine) + int nb_numa_nodes = machine->numa_state->num_nodes; + NodeInfo *numa_info = machine->numa_state->nodes; + int i; +- hwaddr fdt_base; + const CPUArchIdList *possible_cpus; + MachineClass *mc = MACHINE_GET_CLASS(machine); + CPUState *cpu; +@@ -949,12 +948,11 @@ static void loongarch_init(MachineState *machine) + * Put the FDT into the memory map as a ROM image: this will ensure + * the FDT is copied again upon reset, even if addr points into RAM. + */ +- fdt_base = 1 * MiB; + qemu_fdt_dumpdtb(machine->fdt, lams->fdt_size); +- rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, fdt_base, ++ rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, FDT_BASE, + &address_space_memory); + qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, +- rom_ptr_for_as(&address_space_memory, fdt_base, lams->fdt_size)); ++ rom_ptr_for_as(&address_space_memory, FDT_BASE, lams->fdt_size)); + + lams->bootinfo.ram_size = ram_size; + loongarch_load_kernel(machine, &lams->bootinfo); +diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h +index 42d1ee3663..4ebcc89dcf 100644 +--- a/include/hw/loongarch/boot.h ++++ b/include/hw/loongarch/boot.h +@@ -34,6 +34,10 @@ typedef struct { + EFI_GUID(0x5568e427, 0x68fc, 0x4f3d, 0xac, 0x74, \ + 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68) + ++#define DEVICE_TREE_GUID \ ++ EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, \ ++ 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) ++ + struct efi_config_table { + efi_guid_t guid; + uint64_t *ptr; +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 2f9eaf4b0e..673b57aa2b 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -35,6 +35,8 @@ + + #define COMMAND_LINE_SIZE 512 + ++#define FDT_BASE 0x100000 ++ + extern struct memmap_entry *memmap_table; + extern unsigned memmap_entries; + +-- +2.39.1 + diff --git a/hw-loongarch-Init-efi_initrd-table.patch b/hw-loongarch-Init-efi_initrd-table.patch new file mode 100644 index 0000000000000000000000000000000000000000..13adbf41f41cd076eb3cdee2383565eabc16a0d2 --- /dev/null +++ b/hw-loongarch-Init-efi_initrd-table.patch @@ -0,0 +1,101 @@ +From ad674827da4ab972a30d51818f7768de47336984 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:41 +0800 +Subject: [PATCH 07/78] hw/loongarch: Init efi_initrd table + +The efi_system_table adds a efi_initrd configuration table. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-8-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 23 +++++++++++++++++++++-- + include/hw/loongarch/boot.h | 9 +++++++++ + 2 files changed, 30 insertions(+), 2 deletions(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index 527fc9c0be..c8b3e742b4 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -15,6 +15,9 @@ + #include "sysemu/reset.h" + #include "sysemu/qtest.h" + ++ram_addr_t initrd_offset; ++uint64_t initrd_size; ++ + static const unsigned int slave_boot_code[] = { + /* Configure reset ebase. */ + 0x0400302c, /* csrwr $t0, LOONGARCH_CSR_EENTRY */ +@@ -95,6 +98,21 @@ static void init_efi_boot_memmap(struct efi_system_table *systab, + } + } + ++static void init_efi_initrd_table(struct efi_system_table *systab, ++ void *p, void *start) ++{ ++ efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID; ++ struct efi_initrd *initrd_table = p; ++ ++ /* efi_configuration_table 2 */ ++ guidcpy(&systab->tables[1].guid, &tbl_guid); ++ systab->tables[1].table = (struct efi_configuration_table *)(p - start); ++ systab->nr_tables = 2; ++ ++ initrd_table->base = initrd_offset; ++ initrd_table->size = initrd_size; ++} ++ + static void init_systab(struct loongarch_boot_info *info, void *p, void *start) + { + void *bp_tables_start; +@@ -118,6 +136,8 @@ static void init_systab(struct loongarch_boot_info *info, void *p, void *start) + init_efi_boot_memmap(systab, p, start); + p += ROUND_UP(sizeof(struct efi_boot_memmap) + + sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB); ++ init_efi_initrd_table(systab, p, start); ++ p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB); + + systab->tables = (struct efi_configuration_table *)(bp_tables_start - start); + } +@@ -139,8 +159,7 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) + + static int64_t load_kernel_info(struct loongarch_boot_info *info) + { +- uint64_t kernel_entry, kernel_low, kernel_high, initrd_size; +- ram_addr_t initrd_offset; ++ uint64_t kernel_entry, kernel_low, kernel_high; + ssize_t kernel_size; + + kernel_size = load_elf(info->kernel_filename, NULL, +diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h +index 76622af2e2..42d1ee3663 100644 +--- a/include/hw/loongarch/boot.h ++++ b/include/hw/loongarch/boot.h +@@ -30,6 +30,10 @@ typedef struct { + EFI_GUID(0x800f683f, 0xd08b, 0x423a, 0xa2, 0x93, \ + 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4) + ++#define LINUX_EFI_INITRD_MEDIA_GUID \ ++ EFI_GUID(0x5568e427, 0x68fc, 0x4f3d, 0xac, 0x74, \ ++ 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68) ++ + struct efi_config_table { + efi_guid_t guid; + uint64_t *ptr; +@@ -83,6 +87,11 @@ struct efi_boot_memmap { + efi_memory_desc_t map[32]; + }; + ++struct efi_initrd { ++ uint64_t base; ++ uint64_t size; ++}; ++ + struct loongarch_boot_info { + uint64_t ram_size; + const char *kernel_filename; +-- +2.39.1 + diff --git a/hw-loongarch-Init-efi_system_table.patch b/hw-loongarch-Init-efi_system_table.patch new file mode 100644 index 0000000000000000000000000000000000000000..fa4158770bc4067e87881bcfb941763c7314d4b5 --- /dev/null +++ b/hw-loongarch-Init-efi_system_table.patch @@ -0,0 +1,125 @@ +From 65ae44689bfa6a1b697fea6ec0e72027fdddee95 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:39 +0800 +Subject: [PATCH 05/78] hw/loongarch: Init efi_system_table + +Add init_systab and set boot_info->a2 + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-6-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 22 +++++++++++++++++ + include/hw/loongarch/boot.h | 48 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 70 insertions(+) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index 127085bcc4..59889dbc90 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -63,6 +63,25 @@ static const unsigned int slave_boot_code[] = { + 0x4c000020, /* jirl $zero, $ra,0 */ + }; + ++static void init_systab(struct loongarch_boot_info *info, void *p, void *start) ++{ ++ struct efi_system_table *systab = p; ++ ++ info->a2 = p - start; ++ ++ systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; ++ systab->hdr.revision = EFI_SPECIFICATION_VERSION; ++ systab->hdr.revision = sizeof(struct efi_system_table), ++ systab->fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8; ++ systab->runtime = 0; ++ systab->boottime = 0; ++ systab->nr_tables = 0; ++ ++ p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB); ++ ++ systab->tables = p; ++} ++ + static void init_cmdline(struct loongarch_boot_info *info, void *p, void *start) + { + hwaddr cmdline_addr = p - start; +@@ -134,6 +153,7 @@ static void reset_load_elf(void *opaque) + if (cpu == LOONGARCH_CPU(first_cpu)) { + env->gpr[4] = env->boot_info->a0; + env->gpr[5] = env->boot_info->a1; ++ env->gpr[6] = env->boot_info->a2; + } + cpu_set_pc(CPU(cpu), env->elf_address); + } +@@ -178,6 +198,8 @@ static void init_boot_rom(struct loongarch_boot_info *info, void *p) + + init_cmdline(info, p, start); + p += COMMAND_LINE_SIZE; ++ ++ init_systab(info, p, start); + } + + static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) +diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h +index 3275c1e295..cf0e4d4f91 100644 +--- a/include/hw/loongarch/boot.h ++++ b/include/hw/loongarch/boot.h +@@ -8,6 +8,54 @@ + #ifndef HW_LOONGARCH_BOOT_H + #define HW_LOONGARCH_BOOT_H + ++/* UEFI 2.10 */ ++#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 ++#define EFI_2_100_SYSTEM_TABLE_REVISION ((2<<16) | (100)) ++#define EFI_SPECIFICATION_VERSION EFI_SYSTEM_TABLE_REVISION ++#define EFI_SYSTEM_TABLE_REVISION EFI_2_100_SYSTEM_TABLE_REVISION ++ ++#define FW_VERSION 0x1 ++#define FW_PATCHLEVEL 0x0 ++ ++typedef struct { ++ uint8_t b[16]; ++} efi_guid_t QEMU_ALIGNED(8); ++ ++struct efi_config_table { ++ efi_guid_t guid; ++ uint64_t *ptr; ++ const char name[16]; ++}; ++ ++typedef struct { ++ uint64_t signature; ++ uint32_t revision; ++ uint32_t headersize; ++ uint32_t crc32; ++ uint32_t reserved; ++} efi_table_hdr_t; ++ ++struct efi_configuration_table { ++ efi_guid_t guid; ++ void *table; ++}; ++ ++struct efi_system_table { ++ efi_table_hdr_t hdr; ++ uint64_t fw_vendor; /* physical addr of CHAR16 vendor string */ ++ uint32_t fw_revision; ++ uint64_t con_in_handle; ++ uint64_t *con_in; ++ uint64_t con_out_handle; ++ uint64_t *con_out; ++ uint64_t stderr_handle; ++ uint64_t stderr_placeholder; ++ uint64_t *runtime; ++ uint64_t *boottime; ++ uint64_t nr_tables; ++ struct efi_configuration_table *tables; ++}; ++ + struct loongarch_boot_info { + uint64_t ram_size; + const char *kernel_filename; +-- +2.39.1 + diff --git a/hw-loongarch-Move-boot-functions-to-boot.c.patch b/hw-loongarch-Move-boot-functions-to-boot.c.patch new file mode 100644 index 0000000000000000000000000000000000000000..08e73981bba586f419807c7d48113962da7c7c69 --- /dev/null +++ b/hw-loongarch-Move-boot-functions-to-boot.c.patch @@ -0,0 +1,390 @@ +From 2414b74bec88f4db58040a683191d3c3828f81ab Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:35 +0800 +Subject: [PATCH 01/78] hw/loongarch: Move boot functions to boot.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Move some boot functions to boot.c and struct +loongarch_boot_info into struct LoongArchMachineState. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20240426091551.2397867-2-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 128 ++++++++++++++++++++++++++++++++++++ + hw/loongarch/meson.build | 1 + + hw/loongarch/virt.c | 121 +++------------------------------- + include/hw/loongarch/boot.h | 21 ++++++ + include/hw/loongarch/virt.h | 2 + + 5 files changed, 160 insertions(+), 113 deletions(-) + create mode 100644 hw/loongarch/boot.c + create mode 100644 include/hw/loongarch/boot.h + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +new file mode 100644 +index 0000000000..9feed17db3 +--- /dev/null ++++ b/hw/loongarch/boot.c +@@ -0,0 +1,128 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * LoongArch boot helper functions. ++ * ++ * Copyright (c) 2023 Loongson Technology Corporation Limited ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/units.h" ++#include "target/loongarch/cpu.h" ++#include "hw/loongarch/virt.h" ++#include "hw/loader.h" ++#include "elf.h" ++#include "qemu/error-report.h" ++#include "sysemu/reset.h" ++#include "sysemu/qtest.h" ++ ++static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) ++{ ++ return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); ++} ++ ++static int64_t load_kernel_info(struct loongarch_boot_info *info) ++{ ++ uint64_t kernel_entry, kernel_low, kernel_high; ++ ssize_t kernel_size; ++ ++ kernel_size = load_elf(info->kernel_filename, NULL, ++ cpu_loongarch_virt_to_phys, NULL, ++ &kernel_entry, &kernel_low, ++ &kernel_high, NULL, 0, ++ EM_LOONGARCH, 1, 0); ++ ++ if (kernel_size < 0) { ++ error_report("could not load kernel '%s': %s", ++ info->kernel_filename, ++ load_elf_strerror(kernel_size)); ++ exit(1); ++ } ++ return kernel_entry; ++} ++ ++static void reset_load_elf(void *opaque) ++{ ++ LoongArchCPU *cpu = opaque; ++ CPULoongArchState *env = &cpu->env; ++ ++ cpu_reset(CPU(cpu)); ++ if (env->load_elf) { ++ cpu_set_pc(CPU(cpu), env->elf_address); ++ } ++} ++ ++static void fw_cfg_add_kernel_info(struct loongarch_boot_info *info, ++ FWCfgState *fw_cfg) ++{ ++ /* ++ * Expose the kernel, the command line, and the initrd in fw_cfg. ++ * We don't process them here at all, it's all left to the ++ * firmware. ++ */ ++ load_image_to_fw_cfg(fw_cfg, ++ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, ++ info->kernel_filename, ++ false); ++ ++ if (info->initrd_filename) { ++ load_image_to_fw_cfg(fw_cfg, ++ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, ++ info->initrd_filename, false); ++ } ++ ++ if (info->kernel_cmdline) { ++ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, ++ strlen(info->kernel_cmdline) + 1); ++ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, ++ info->kernel_cmdline); ++ } ++} ++ ++static void loongarch_firmware_boot(LoongArchMachineState *lams, ++ struct loongarch_boot_info *info) ++{ ++ fw_cfg_add_kernel_info(info, lams->fw_cfg); ++} ++ ++static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) ++{ ++ int64_t kernel_addr = 0; ++ LoongArchCPU *lacpu; ++ CPUState *cs; ++ ++ if (info->kernel_filename) { ++ kernel_addr = load_kernel_info(info); ++ } else { ++ if(!qtest_enabled()) { ++ error_report("Need kernel filename\n"); ++ exit(1); ++ } ++ } ++ ++ CPU_FOREACH(cs) { ++ lacpu = LOONGARCH_CPU(cs); ++ lacpu->env.load_elf = true; ++ lacpu->env.elf_address = kernel_addr; ++ } ++} ++ ++void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info) ++{ ++ LoongArchMachineState *lams = LOONGARCH_MACHINE(ms); ++ int i; ++ ++ /* register reset function */ ++ for (i = 0; i < ms->smp.cpus; i++) { ++ qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(i))); ++ } ++ ++ info->kernel_filename = ms->kernel_filename; ++ info->kernel_cmdline = ms->kernel_cmdline; ++ info->initrd_filename = ms->initrd_filename; ++ ++ if (lams->bios_loaded) { ++ loongarch_firmware_boot(lams, info); ++ } else { ++ loongarch_direct_kernel_boot(info); ++ } ++} +diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build +index c0421502ab..d306d82c2e 100644 +--- a/hw/loongarch/meson.build ++++ b/hw/loongarch/meson.build +@@ -1,6 +1,7 @@ + loongarch_ss = ss.source_set() + loongarch_ss.add(files( + 'fw_cfg.c', ++ 'boot.c', + )) + loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: [files('virt.c'), fdt]) + loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c')) +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index eca3b94581..a0aee28f41 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -48,14 +48,6 @@ + #include "hw/block/flash.h" + #include "qemu/error-report.h" + +- +-struct loaderparams { +- uint64_t ram_size; +- const char *kernel_filename; +- const char *kernel_cmdline; +- const char *initrd_filename; +-}; +- + static bool virt_is_veiointc_enabled(LoongArchMachineState *lams) + { + if (lams->veiointc == ON_OFF_AUTO_OFF) { +@@ -439,31 +431,6 @@ static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) + memmap_entries++; + } + +-static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) +-{ +- return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); +-} +- +-static int64_t load_kernel_info(const struct loaderparams *loaderparams) +-{ +- uint64_t kernel_entry, kernel_low, kernel_high; +- ssize_t kernel_size; +- +- kernel_size = load_elf(loaderparams->kernel_filename, NULL, +- cpu_loongarch_virt_to_phys, NULL, +- &kernel_entry, &kernel_low, +- &kernel_high, NULL, 0, +- EM_LOONGARCH, 1, 0); +- +- if (kernel_size < 0) { +- error_report("could not load kernel '%s': %s", +- loaderparams->kernel_filename, +- load_elf_strerror(kernel_size)); +- exit(1); +- } +- return kernel_entry; +-} +- + static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState *lams) + { + DeviceState *dev; +@@ -755,67 +722,6 @@ static void loongarch_firmware_init(LoongArchMachineState *lams) + } + } + +-static void reset_load_elf(void *opaque) +-{ +- LoongArchCPU *cpu = opaque; +- CPULoongArchState *env = &cpu->env; +- +- cpu_reset(CPU(cpu)); +- if (env->load_elf) { +- cpu_set_pc(CPU(cpu), env->elf_address); +- } +-} +- +-static void fw_cfg_add_kernel_info(const struct loaderparams *loaderparams, +- FWCfgState *fw_cfg) +-{ +- /* +- * Expose the kernel, the command line, and the initrd in fw_cfg. +- * We don't process them here at all, it's all left to the +- * firmware. +- */ +- load_image_to_fw_cfg(fw_cfg, +- FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, +- loaderparams->kernel_filename, +- false); +- +- if (loaderparams->initrd_filename) { +- load_image_to_fw_cfg(fw_cfg, +- FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, +- loaderparams->initrd_filename, false); +- } +- +- if (loaderparams->kernel_cmdline) { +- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, +- strlen(loaderparams->kernel_cmdline) + 1); +- fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, +- loaderparams->kernel_cmdline); +- } +-} +- +-static void loongarch_firmware_boot(LoongArchMachineState *lams, +- const struct loaderparams *loaderparams) +-{ +- fw_cfg_add_kernel_info(loaderparams, lams->fw_cfg); +-} +- +-static void loongarch_direct_kernel_boot(LoongArchMachineState *lams, +- const struct loaderparams *loaderparams) +-{ +- MachineState *machine = MACHINE(lams); +- int64_t kernel_addr = 0; +- LoongArchCPU *lacpu; +- int i; +- +- kernel_addr = load_kernel_info(loaderparams); +- if (!machine->firmware) { +- for (i = 0; i < machine->smp.cpus; i++) { +- lacpu = LOONGARCH_CPU(qemu_get_cpu(i)); +- lacpu->env.load_elf = true; +- lacpu->env.elf_address = kernel_addr; +- } +- } +-} + + static MemTxResult loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size, MemTxAttrs attrs) +@@ -925,7 +831,6 @@ static void loongarch_init(MachineState *machine) + const CPUArchIdList *possible_cpus; + MachineClass *mc = MACHINE_GET_CLASS(machine); + CPUState *cpu; +- struct loaderparams loaderparams = { }; + + if (!cpu_model) { + cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); +@@ -1028,24 +933,8 @@ static void loongarch_init(MachineState *machine) + sizeof(struct memmap_entry) * (memmap_entries)); + } + fdt_add_fw_cfg_node(lams); +- loaderparams.ram_size = ram_size; +- loaderparams.kernel_filename = machine->kernel_filename; +- loaderparams.kernel_cmdline = machine->kernel_cmdline; +- loaderparams.initrd_filename = machine->initrd_filename; +- /* load the kernel. */ +- if (loaderparams.kernel_filename) { +- if (lams->bios_loaded) { +- loongarch_firmware_boot(lams, &loaderparams); +- } else { +- loongarch_direct_kernel_boot(lams, &loaderparams); +- } +- } + fdt_add_flash_node(lams); +- /* register reset function */ +- for (i = 0; i < machine->smp.cpus; i++) { +- lacpu = LOONGARCH_CPU(qemu_get_cpu(i)); +- qemu_register_reset(reset_load_elf, lacpu); +- } ++ + /* Initialize the IO interrupt subsystem */ + loongarch_irq_init(lams); + fdt_add_irqchip_node(lams); +@@ -1069,7 +958,13 @@ static void loongarch_init(MachineState *machine) + */ + fdt_base = 1 * MiB; + qemu_fdt_dumpdtb(machine->fdt, lams->fdt_size); +- rom_add_blob_fixed("fdt", machine->fdt, lams->fdt_size, fdt_base); ++ rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, fdt_base, ++ &address_space_memory); ++ qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, ++ rom_ptr_for_as(&address_space_memory, fdt_base, lams->fdt_size)); ++ ++ lams->bootinfo.ram_size = ram_size; ++ loongarch_load_kernel(machine, &lams->bootinfo); + } + + bool loongarch_is_acpi_enabled(LoongArchMachineState *lams) +diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h +new file mode 100644 +index 0000000000..3275c1e295 +--- /dev/null ++++ b/include/hw/loongarch/boot.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Definitions for LoongArch boot. ++ * ++ * Copyright (C) 2023 Loongson Technology Corporation Limited ++ */ ++ ++#ifndef HW_LOONGARCH_BOOT_H ++#define HW_LOONGARCH_BOOT_H ++ ++struct loongarch_boot_info { ++ uint64_t ram_size; ++ const char *kernel_filename; ++ const char *kernel_cmdline; ++ const char *initrd_filename; ++ uint64_t a0, a1, a2; ++}; ++ ++void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info); ++ ++#endif /* HW_LOONGARCH_BOOT_H */ +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 99447fd1d6..02c8234b8d 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -13,6 +13,7 @@ + #include "qemu/queue.h" + #include "hw/intc/loongarch_ipi.h" + #include "hw/block/flash.h" ++#include "hw/loongarch/boot.h" + + #define LOONGARCH_MAX_CPUS 256 + +@@ -58,6 +59,7 @@ struct LoongArchMachineState { + MemoryRegion iocsr_mem; + AddressSpace as_iocsr; + int features; ++ struct loongarch_boot_info bootinfo; + }; + + #define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") +-- +2.39.1 + diff --git a/hw-loongarch-Refine-acpi-srat-table-for-numa-memory.patch b/hw-loongarch-Refine-acpi-srat-table-for-numa-memory.patch new file mode 100644 index 0000000000000000000000000000000000000000..330846cdc21e858d69781050c8737701fec5d8a9 --- /dev/null +++ b/hw-loongarch-Refine-acpi-srat-table-for-numa-memory.patch @@ -0,0 +1,108 @@ +From 1c9b7b7e76a63738721ac1092fdfff12ae87993a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:22 +0800 +Subject: [PATCH 23/78] hw/loongarch: Refine acpi srat table for numa memory + +One LoongArch virt machine platform, there is limitation for memory +map information. The minimum memory size is 256M and minimum memory +size for numa node0 is 256M also. With qemu numa qtest, it is possible +that memory size of numa node0 is 128M. + +Limitations for minimum memory size for both total memory and numa +node0 is removed for acpi srat table creation. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240515093927.3453674-2-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/acpi-build.c | 58 +++++++++++++++++++++++---------------- + 1 file changed, 34 insertions(+), 24 deletions(-) + +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index 2b4e09bf37..2555c6763c 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -166,8 +166,9 @@ static void + build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + { + int i, arch_id, node_id; +- uint64_t mem_len, mem_base; +- int nb_numa_nodes = machine->numa_state->num_nodes; ++ hwaddr len, base, gap; ++ NodeInfo *numa_info; ++ int nodes, nb_numa_nodes = machine->numa_state->num_nodes; + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + MachineClass *mc = MACHINE_GET_CLASS(lvms); + const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine); +@@ -196,35 +197,44 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + } + +- /* Node0 */ +- build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, +- 0, MEM_AFFINITY_ENABLED); +- mem_base = VIRT_HIGHMEM_BASE; +- if (!nb_numa_nodes) { +- mem_len = machine->ram_size - VIRT_LOWMEM_SIZE; +- } else { +- mem_len = machine->numa_state->nodes[0].node_mem - VIRT_LOWMEM_SIZE; ++ base = VIRT_LOWMEM_BASE; ++ gap = VIRT_LOWMEM_SIZE; ++ numa_info = machine->numa_state->nodes; ++ nodes = nb_numa_nodes; ++ if (!nodes) { ++ nodes = 1; + } +- if (mem_len) +- build_srat_memory(table_data, mem_base, mem_len, 0, MEM_AFFINITY_ENABLED); +- +- /* Node1 - Nodemax */ +- if (nb_numa_nodes) { +- mem_base += mem_len; +- for (i = 1; i < nb_numa_nodes; ++i) { +- if (machine->numa_state->nodes[i].node_mem > 0) { +- build_srat_memory(table_data, mem_base, +- machine->numa_state->nodes[i].node_mem, i, +- MEM_AFFINITY_ENABLED); +- mem_base += machine->numa_state->nodes[i].node_mem; +- } ++ ++ for (i = 0; i < nodes; i++) { ++ if (nb_numa_nodes) { ++ len = numa_info[i].node_mem; ++ } else { ++ len = machine->ram_size; ++ } ++ ++ /* ++ * memory for the node splited into two part ++ * lowram: [base, +gap) ++ * highram: [VIRT_HIGHMEM_BASE, +(len - gap)) ++ */ ++ if (len >= gap) { ++ build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED); ++ len -= gap; ++ base = VIRT_HIGHMEM_BASE; ++ gap = machine->ram_size - VIRT_LOWMEM_SIZE; ++ } ++ ++ if (len) { ++ build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED); ++ base += len; ++ gap -= len; + } + } + + if (machine->device_memory) { + build_srat_memory(table_data, machine->device_memory->base, + memory_region_size(&machine->device_memory->mr), +- nb_numa_nodes - 1, ++ nodes - 1, + MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); + } + +-- +2.39.1 + diff --git a/hw-loongarch-Refine-default-numa-id-calculation.patch b/hw-loongarch-Refine-default-numa-id-calculation.patch new file mode 100644 index 0000000000000000000000000000000000000000..e53da7176eb216b8a6fa854354451f331f362509 --- /dev/null +++ b/hw-loongarch-Refine-default-numa-id-calculation.patch @@ -0,0 +1,57 @@ +From a9f9a4a0a60596f2e738e6e434c20a3f5266fa17 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 19 Mar 2024 10:26:06 +0800 +Subject: [PATCH 21/78] hw/loongarch: Refine default numa id calculation + +With numa_test test case, there is subcase named test_def_cpu_split(), +there are 8 sockets and 2 numa nodes. Here is command line: +"-machine smp.cpus=8,smp.sockets=8 -numa node,memdev=ram -numa node" + +The required result is: + node 0 cpus: 0 2 4 6 + node 1 cpus: 1 3 5 7 +Test case numa_test fails on LoongArch, since the actual result is: + node 0 cpus: 0 1 2 3 + node 1 cpus: 4 5 6 7 + +It will be better if all the cpus in one socket share the same numa +node. Here socket id is used to calculate numa id in function +virt_get_default_cpu_node_id(). + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240319022606.2994565-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index e39989193e..e82e3b6792 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -1278,15 +1278,14 @@ static CpuInstanceProperties virt_cpu_index_to_props(MachineState *ms, + + static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx) + { +- int64_t nidx = 0; ++ int64_t socket_id; + + if (ms->numa_state->num_nodes) { +- nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes); +- if (ms->numa_state->num_nodes <= nidx) { +- nidx = ms->numa_state->num_nodes - 1; +- } ++ socket_id = ms->possible_cpus->cpus[idx].props.socket_id; ++ return socket_id % ms->numa_state->num_nodes; ++ } else { ++ return 0; + } +- return nidx; + } + + static void virt_class_init(ObjectClass *oc, void *data) +-- +2.39.1 + diff --git a/hw-loongarch-Refine-fadt-memory-table-for-numa-memor.patch b/hw-loongarch-Refine-fadt-memory-table-for-numa-memor.patch new file mode 100644 index 0000000000000000000000000000000000000000..df9e4b4f52b7261f12198a8a841dafb6966b0d91 --- /dev/null +++ b/hw-loongarch-Refine-fadt-memory-table-for-numa-memor.patch @@ -0,0 +1,106 @@ +From d39247ec5d4ef52a4b9422aaecccc284cbd1a5dd Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:23 +0800 +Subject: [PATCH 24/78] hw/loongarch: Refine fadt memory table for numa memory + +One LoongArch virt machine platform, there is limitation for memory +map information. The minimum memory size is 256M and minimum memory +size for numa node0 is 256M also. With qemu numa qtest, it is possible +that memory size of numa node0 is 128M. + +Limitations for minimum memory size for both total memory and numa +node0 is removed for fadt numa memory table creation. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240515093927.3453674-3-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 46 ++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 43 insertions(+), 3 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index c3514f9293..31a2598e7c 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -502,6 +502,48 @@ static void fdt_add_memory_node(MachineState *ms, + g_free(nodename); + } + ++static void fdt_add_memory_nodes(MachineState *ms) ++{ ++ hwaddr base, size, ram_size, gap; ++ int i, nb_numa_nodes, nodes; ++ NodeInfo *numa_info; ++ ++ ram_size = ms->ram_size; ++ base = VIRT_LOWMEM_BASE; ++ gap = VIRT_LOWMEM_SIZE; ++ nodes = nb_numa_nodes = ms->numa_state->num_nodes; ++ numa_info = ms->numa_state->nodes; ++ if (!nodes) { ++ nodes = 1; ++ } ++ ++ for (i = 0; i < nodes; i++) { ++ if (nb_numa_nodes) { ++ size = numa_info[i].node_mem; ++ } else { ++ size = ram_size; ++ } ++ ++ /* ++ * memory for the node splited into two part ++ * lowram: [base, +gap) ++ * highram: [VIRT_HIGHMEM_BASE, +(len - gap)) ++ */ ++ if (size >= gap) { ++ fdt_add_memory_node(ms, base, gap, i); ++ size -= gap; ++ base = VIRT_HIGHMEM_BASE; ++ gap = ram_size - VIRT_LOWMEM_SIZE; ++ } ++ ++ if (size) { ++ fdt_add_memory_node(ms, base, size, i); ++ base += size; ++ gap -= size; ++ } ++ } ++} ++ + static void virt_build_smbios(LoongArchVirtMachineState *lvms) + { + MachineState *ms = MACHINE(lvms); +@@ -1008,10 +1050,10 @@ static void virt_init(MachineState *machine) + lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id; + } + fdt_add_cpu_nodes(lvms); ++ fdt_add_memory_nodes(machine); + + /* Node0 memory */ + memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1); +- fdt_add_memory_node(machine, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 0); + memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.node0.lowram", + machine->ram, offset, VIRT_LOWMEM_SIZE); + memory_region_add_subregion(address_space_mem, phyAddr, &lvms->lowmem); +@@ -1025,7 +1067,6 @@ static void virt_init(MachineState *machine) + } + phyAddr = VIRT_HIGHMEM_BASE; + memmap_add_entry(phyAddr, highram_size, 1); +- fdt_add_memory_node(machine, phyAddr, highram_size, 0); + memory_region_init_alias(&lvms->highmem, NULL, "loongarch.node0.highram", + machine->ram, offset, highram_size); + memory_region_add_subregion(address_space_mem, phyAddr, &lvms->highmem); +@@ -1041,7 +1082,6 @@ static void virt_init(MachineState *machine) + offset, numa_info[i].node_mem); + memory_region_add_subregion(address_space_mem, phyAddr, nodemem); + memmap_add_entry(phyAddr, numa_info[i].node_mem, 1); +- fdt_add_memory_node(machine, phyAddr, numa_info[i].node_mem, i); + offset += numa_info[i].node_mem; + phyAddr += numa_info[i].node_mem; + } +-- +2.39.1 + diff --git a/hw-loongarch-Refine-fwcfg-memory-map.patch b/hw-loongarch-Refine-fwcfg-memory-map.patch new file mode 100644 index 0000000000000000000000000000000000000000..38df11db93419eefc9656a954beeede6ba88ce33 --- /dev/null +++ b/hw-loongarch-Refine-fwcfg-memory-map.patch @@ -0,0 +1,120 @@ +From 88b12e40d6a479dfb376fb6a91ef24e07a59d33a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:24 +0800 +Subject: [PATCH 25/78] hw/loongarch: Refine fwcfg memory map + +Memory map table for fwcfg is used for UEFI BIOS, UEFI BIOS uses the first +entry from fwcfg memory map as the first memory HOB, the second memory HOB +will be used if the first memory HOB is used up. + +Memory map table for fwcfg does not care about numa node, however in +generic the first memory HOB is part of numa node0, so that runtime +memory of UEFI which is allocated from the first memory HOB is located +at numa node0. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240515093927.3453674-4-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 60 ++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 57 insertions(+), 3 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 31a2598e7c..7e89921431 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -1005,6 +1005,62 @@ static const MemoryRegionOps virt_iocsr_misc_ops = { + }, + }; + ++static void fw_cfg_add_memory(MachineState *ms) ++{ ++ hwaddr base, size, ram_size, gap; ++ int nb_numa_nodes, nodes; ++ NodeInfo *numa_info; ++ ++ ram_size = ms->ram_size; ++ base = VIRT_LOWMEM_BASE; ++ gap = VIRT_LOWMEM_SIZE; ++ nodes = nb_numa_nodes = ms->numa_state->num_nodes; ++ numa_info = ms->numa_state->nodes; ++ if (!nodes) { ++ nodes = 1; ++ } ++ ++ /* add fw_cfg memory map of node0 */ ++ if (nb_numa_nodes) { ++ size = numa_info[0].node_mem; ++ } else { ++ size = ram_size; ++ } ++ ++ if (size >= gap) { ++ memmap_add_entry(base, gap, 1); ++ size -= gap; ++ base = VIRT_HIGHMEM_BASE; ++ gap = ram_size - VIRT_LOWMEM_SIZE; ++ } ++ ++ if (size) { ++ memmap_add_entry(base, size, 1); ++ base += size; ++ } ++ ++ if (nodes < 2) { ++ return; ++ } ++ ++ /* add fw_cfg memory map of other nodes */ ++ size = ram_size - numa_info[0].node_mem; ++ gap = VIRT_LOWMEM_BASE + VIRT_LOWMEM_SIZE; ++ if (base < gap && (base + size) > gap) { ++ /* ++ * memory map for the maining nodes splited into two part ++ * lowram: [base, +(gap - base)) ++ * highram: [VIRT_HIGHMEM_BASE, +(size - (gap - base))) ++ */ ++ memmap_add_entry(base, gap - base, 1); ++ size -= gap - base; ++ base = VIRT_HIGHMEM_BASE; ++ } ++ ++ if (size) ++ memmap_add_entry(base, size, 1); ++} ++ + static void virt_init(MachineState *machine) + { + LoongArchCPU *lacpu; +@@ -1051,9 +1107,9 @@ static void virt_init(MachineState *machine) + } + fdt_add_cpu_nodes(lvms); + fdt_add_memory_nodes(machine); ++ fw_cfg_add_memory(machine); + + /* Node0 memory */ +- memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1); + memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.node0.lowram", + machine->ram, offset, VIRT_LOWMEM_SIZE); + memory_region_add_subregion(address_space_mem, phyAddr, &lvms->lowmem); +@@ -1066,7 +1122,6 @@ static void virt_init(MachineState *machine) + highram_size = ram_size - VIRT_LOWMEM_SIZE; + } + phyAddr = VIRT_HIGHMEM_BASE; +- memmap_add_entry(phyAddr, highram_size, 1); + memory_region_init_alias(&lvms->highmem, NULL, "loongarch.node0.highram", + machine->ram, offset, highram_size); + memory_region_add_subregion(address_space_mem, phyAddr, &lvms->highmem); +@@ -1081,7 +1136,6 @@ static void virt_init(MachineState *machine) + memory_region_init_alias(nodemem, NULL, ramName, machine->ram, + offset, numa_info[i].node_mem); + memory_region_add_subregion(address_space_mem, phyAddr, nodemem); +- memmap_add_entry(phyAddr, numa_info[i].node_mem, 1); + offset += numa_info[i].node_mem; + phyAddr += numa_info[i].node_mem; + } +-- +2.39.1 + diff --git a/hw-loongarch-Refine-system-dram-memory-region.patch b/hw-loongarch-Refine-system-dram-memory-region.patch new file mode 100644 index 0000000000000000000000000000000000000000..3db195d89ab32a09e7635de8e2a02f154dab0c07 --- /dev/null +++ b/hw-loongarch-Refine-system-dram-memory-region.patch @@ -0,0 +1,110 @@ +From 1a7f567308756a2a26020802b24fe7fd106cf84a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:25 +0800 +Subject: [PATCH 26/78] hw/loongarch: Refine system dram memory region + +For system dram memory region, it is not necessary to use numa node +information. There is only low memory region and high memory region. + +Remove numa node information for ddr memory region here, it can reduce +memory region number on LoongArch virt machine. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240515093927.3453674-5-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 53 +++++++++++++++------------------------------ + 1 file changed, 17 insertions(+), 36 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 7e89921431..96755f5deb 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -1065,14 +1065,10 @@ static void virt_init(MachineState *machine) + { + LoongArchCPU *lacpu; + const char *cpu_model = machine->cpu_type; +- ram_addr_t offset = 0; +- ram_addr_t ram_size = machine->ram_size; +- uint64_t highram_size = 0, phyAddr = 0; + MemoryRegion *address_space_mem = get_system_memory(); + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); +- int nb_numa_nodes = machine->numa_state->num_nodes; +- NodeInfo *numa_info = machine->numa_state->nodes; + int i; ++ hwaddr base, size, ram_size = machine->ram_size; + const CPUArchIdList *possible_cpus; + MachineClass *mc = MACHINE_GET_CLASS(machine); + CPUState *cpu; +@@ -1110,40 +1106,27 @@ static void virt_init(MachineState *machine) + fw_cfg_add_memory(machine); + + /* Node0 memory */ +- memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.node0.lowram", +- machine->ram, offset, VIRT_LOWMEM_SIZE); +- memory_region_add_subregion(address_space_mem, phyAddr, &lvms->lowmem); +- +- offset += VIRT_LOWMEM_SIZE; +- if (nb_numa_nodes > 0) { +- assert(numa_info[0].node_mem > VIRT_LOWMEM_SIZE); +- highram_size = numa_info[0].node_mem - VIRT_LOWMEM_SIZE; +- } else { +- highram_size = ram_size - VIRT_LOWMEM_SIZE; ++ size = ram_size; ++ base = VIRT_LOWMEM_BASE; ++ if (size > VIRT_LOWMEM_SIZE) { ++ size = VIRT_LOWMEM_SIZE; + } +- phyAddr = VIRT_HIGHMEM_BASE; +- memory_region_init_alias(&lvms->highmem, NULL, "loongarch.node0.highram", +- machine->ram, offset, highram_size); +- memory_region_add_subregion(address_space_mem, phyAddr, &lvms->highmem); +- +- /* Node1 - Nodemax memory */ +- offset += highram_size; +- phyAddr += highram_size; +- +- for (i = 1; i < nb_numa_nodes; i++) { +- MemoryRegion *nodemem = g_new(MemoryRegion, 1); +- g_autofree char *ramName = g_strdup_printf("loongarch.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); +- offset += numa_info[i].node_mem; +- phyAddr += numa_info[i].node_mem; ++ ++ memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.lowram", ++ machine->ram, base, size); ++ memory_region_add_subregion(address_space_mem, base, &lvms->lowmem); ++ base += size; ++ if (ram_size - size) { ++ base = VIRT_HIGHMEM_BASE; ++ memory_region_init_alias(&lvms->highmem, NULL, "loongarch.highram", ++ machine->ram, VIRT_LOWMEM_BASE + size, ram_size - size); ++ memory_region_add_subregion(address_space_mem, base, &lvms->highmem); ++ base += ram_size - size; + } + + /* initialize device memory address space */ + if (machine->ram_size < machine->maxram_size) { + ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size; +- hwaddr device_mem_base; + + if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) { + error_report("unsupported amount of memory slots: %"PRIu64, +@@ -1157,9 +1140,7 @@ static void virt_init(MachineState *machine) + "%d bytes", TARGET_PAGE_SIZE); + exit(EXIT_FAILURE); + } +- /* device memory base is the top of high memory address. */ +- device_mem_base = ROUND_UP(VIRT_HIGHMEM_BASE + highram_size, 1 * GiB); +- machine_memory_devices_init(machine, device_mem_base, device_mem_size); ++ machine_memory_devices_init(machine, base, device_mem_size); + } + + /* load the BIOS image. */ +-- +2.39.1 + diff --git a/hw-loongarch-Remove-default-enable-with-VIRTIO_VGA-d.patch b/hw-loongarch-Remove-default-enable-with-VIRTIO_VGA-d.patch new file mode 100644 index 0000000000000000000000000000000000000000..abf36b0b9bcbe433ca4d6a326c1f673cea5f9253 --- /dev/null +++ b/hw-loongarch-Remove-default-enable-with-VIRTIO_VGA-d.patch @@ -0,0 +1,39 @@ +From 94fa0b75c098ca6fc987f103760c1e07695ffd1a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Fri, 23 Aug 2024 15:30:50 +0800 +Subject: [PATCH 34/78] hw/loongarch: Remove default enable with VIRTIO_VGA + device + +For virtio VGA deivce libvirt will select VIRTIO_VGA firstly rather than +VIRTIO_GPU, VIRTIO_VGA device supports frame buffer however it requires +legacy VGA compatible support. Frame buffer area 0xa0000 -- 0xc0000 +conflicts with low memory area 0 -- 0x10000000. + +Here remove default support for VIRTIO_VGA device, VIRTIO_GPU is prefered +on LoongArch system. For frame buffer video card support, standard VGA can +be used. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240823073050.2619484-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index b2a3adb7dc..40944a8365 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -4,7 +4,6 @@ config LOONGARCH_VIRT + depends on LOONGARCH64 + select PCI + select PCI_EXPRESS_GENERIC_BRIDGE +- imply VIRTIO_VGA + imply PCI_DEVICES + imply NVDIMM + imply TPM_TIS_SYSBUS +-- +2.39.1 + diff --git a/hw-loongarch-Remove-minimum-and-default-memory-size.patch b/hw-loongarch-Remove-minimum-and-default-memory-size.patch new file mode 100644 index 0000000000000000000000000000000000000000..9298f984b95f334c2080b8b621b45e680ef4cbed --- /dev/null +++ b/hw-loongarch-Remove-minimum-and-default-memory-size.patch @@ -0,0 +1,46 @@ +From 858f16ea09fbbac9966ca73b6b86d290a36be6f5 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:26 +0800 +Subject: [PATCH 27/78] hw/loongarch: Remove minimum and default memory size + +Some qtest test cases such as numa use default memory size of generic +machine class, which is 128M by fault. + +Here generic default memory size is used, and also remove minimum memory +size which is 1G originally. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240515093927.3453674-6-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 96755f5deb..11ba879e52 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -1077,10 +1077,6 @@ static void virt_init(MachineState *machine) + cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); + } + +- if (ram_size < 1 * GiB) { +- error_report("ram_size must be greater than 1G."); +- exit(1); +- } + create_fdt(lvms); + + /* Create IOCSR space */ +@@ -1369,7 +1365,6 @@ static void virt_class_init(ObjectClass *oc, void *data) + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); + + mc->init = virt_init; +- mc->default_ram_size = 1 * GiB; + mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464"); + mc->default_ram_id = "loongarch.ram"; + mc->max_cpus = LOONGARCH_MAX_CPUS; +-- +2.39.1 + diff --git a/hw-loongarch-Rename-LOONGARCH_MACHINE-with-LOONGARCH.patch b/hw-loongarch-Rename-LOONGARCH_MACHINE-with-LOONGARCH.patch new file mode 100644 index 0000000000000000000000000000000000000000..38fc14acdb8923769779d6376a7533b5207f8afa --- /dev/null +++ b/hw-loongarch-Rename-LOONGARCH_MACHINE-with-LOONGARCH.patch @@ -0,0 +1,188 @@ +From 8e2986a6fc5dda2afbe33f723efdacd01f147b7a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 8 May 2024 11:11:06 +0800 +Subject: [PATCH 19/78] hw/loongarch: Rename LOONGARCH_MACHINE with + LOONGARCH_VIRT_MACHINE +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On LoongArch system, there is only virt machine type now, name +LOONGARCH_MACHINE is confused, rename it with LOONGARCH_VIRT_MACHINE. +Machine name about Other real hw boards can be added in future. + +Signed-off-by: Bibo Mao +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20240508031110.2507477-2-maobibo@loongson.cn> +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Xianglai Li +--- + hw/loongarch/acpi-build.c | 8 ++++---- + hw/loongarch/boot.c | 2 +- + hw/loongarch/virt.c | 19 +++++++++---------- + include/hw/loongarch/virt.h | 4 ++-- + 4 files changed, 16 insertions(+), 17 deletions(-) + +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index f990405d04..fff3497c62 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -167,7 +167,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + int i, arch_id, node_id; + uint64_t mem_len, mem_base; + int nb_numa_nodes = machine->numa_state->num_nodes; +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); + MachineClass *mc = MACHINE_GET_CLASS(lams); + const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine); + AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id, +@@ -279,7 +279,7 @@ static void + build_la_ged_aml(Aml *dsdt, MachineState *machine) + { + uint32_t event; +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); + + build_ged_aml(dsdt, "\\_SB."GED_DEVICE, + HOTPLUG_HANDLER(lams->acpi_ged), +@@ -391,7 +391,7 @@ static void + build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) + { + Aml *dsdt, *scope, *pkg; +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); + AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id, + .oem_table_id = lams->oem_table_id }; + +@@ -421,7 +421,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) + + static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); + GArray *table_offsets; + AcpiFadtData fadt_data; + unsigned facs, rsdt, dsdt; +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index 03f6301a77..e37512729d 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -319,7 +319,7 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + + void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(ms); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(ms); + int i; + + /* register reset function */ +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 76b36539e2..cca220cb5b 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -970,7 +970,7 @@ static void loongarch_init(MachineState *machine) + ram_addr_t ram_size = machine->ram_size; + uint64_t highram_size = 0, phyAddr = 0; + MemoryRegion *address_space_mem = get_system_memory(); +- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); + int nb_numa_nodes = machine->numa_state->num_nodes; + NodeInfo *numa_info = machine->numa_state->nodes; + int i; +@@ -1121,7 +1121,7 @@ bool loongarch_is_acpi_enabled(LoongArchMachineState *lams) + static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj); + OnOffAuto acpi = lams->acpi; + + visit_type_OnOffAuto(v, name, &acpi, errp); +@@ -1130,14 +1130,14 @@ static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name, + static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj); + + visit_type_OnOffAuto(v, name, &lams->acpi, errp); + } + + static void loongarch_machine_initfn(Object *obj) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj); + + if (tcg_enabled()) { + lams->veiointc = ON_OFF_AUTO_OFF; +@@ -1172,7 +1172,7 @@ static void virt_machine_device_pre_plug(HotplugHandler *hotplug_dev, + static void virt_mem_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev); + + /* the acpi ged is always exist */ + hotplug_handler_unplug_request(HOTPLUG_HANDLER(lams->acpi_ged), dev, +@@ -1190,7 +1190,7 @@ static void virt_machine_device_unplug_request(HotplugHandler *hotplug_dev, + static void virt_mem_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev); + + hotplug_handler_unplug(HOTPLUG_HANDLER(lams->acpi_ged), dev, errp); + pc_dimm_unplug(PC_DIMM(dev), MACHINE(lams)); +@@ -1208,7 +1208,7 @@ static void virt_machine_device_unplug(HotplugHandler *hotplug_dev, + static void virt_mem_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev); + + pc_dimm_plug(PC_DIMM(dev), MACHINE(lams)); + hotplug_handler_plug(HOTPLUG_HANDLER(lams->acpi_ged), +@@ -1218,7 +1218,7 @@ static void virt_mem_plug(HotplugHandler *hotplug_dev, + static void loongarch_machine_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); ++ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev); + MachineClass *mc = MACHINE_GET_CLASS(lams); + + if (device_is_dynamic_sysbus(mc, dev)) { +@@ -1300,7 +1300,6 @@ static void loongarch_class_init(ObjectClass *oc, void *data) + MachineClass *mc = MACHINE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); + +- mc->desc = "Loongson-3A5000 LS7A1000 machine"; + mc->init = loongarch_init; + mc->default_ram_size = 1 * GiB; + mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464"); +@@ -1341,7 +1340,7 @@ static void loongarch_class_init(ObjectClass *oc, void *data) + + static const TypeInfo loongarch_machine_types[] = { + { +- .name = TYPE_LOONGARCH_MACHINE, ++ .name = TYPE_LOONGARCH_VIRT_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(LoongArchMachineState), + .class_init = loongarch_class_init, +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 36158c758f..0509b9a9af 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -66,8 +66,8 @@ struct LoongArchMachineState { + struct loongarch_boot_info bootinfo; + }; + +-#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") +-OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_MACHINE) ++#define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt") ++OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_VIRT_MACHINE) + bool loongarch_is_acpi_enabled(LoongArchMachineState *lams); + void loongarch_acpi_setup(LoongArchMachineState *lams); + #endif +-- +2.39.1 + diff --git a/hw-loongarch-Rename-LoongArchMachineState-with-Loong.patch b/hw-loongarch-Rename-LoongArchMachineState-with-Loong.patch new file mode 100644 index 0000000000000000000000000000000000000000..65f8a224abf16bd450cdf57fc49445de2f7a3985 --- /dev/null +++ b/hw-loongarch-Rename-LoongArchMachineState-with-Loong.patch @@ -0,0 +1,1324 @@ +From a501582ef5e986bfa9dc198c63582b3e35332643 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 8 May 2024 11:11:07 +0800 +Subject: [PATCH 20/78] hw/loongarch: Rename LoongArchMachineState with + LoongArchVirtMachineState +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Rename LoongArchMachineState with LoongArchVirtMachineState, and change +variable name LoongArchMachineState *lams with LoongArchVirtMachineState +*lvms. + +Rename function specific for virtmachine loongarch_xxx() +with virt_xxx(). However some common functions keep unchanged such as +loongarch_acpi_setup()/loongarch_load_kernel(), since there functions +can be used for real hw boards. + +Signed-off-by: Bibo Mao +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20240508031110.2507477-3-maobibo@loongson.cn> +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Xianglai Li +--- + hw/loongarch/acpi-build.c | 89 +++++---- + hw/loongarch/boot.c | 10 +- + hw/loongarch/fw_cfg.c | 2 +- + hw/loongarch/fw_cfg.h | 2 +- + hw/loongarch/virt.c | 366 ++++++++++++++++++------------------ + include/hw/loongarch/virt.h | 7 +- + 6 files changed, 239 insertions(+), 237 deletions(-) + +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index fff3497c62..2b4e09bf37 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -105,14 +105,15 @@ build_facs(GArray *table_data) + + /* build MADT */ + static void +-build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams) ++build_madt(GArray *table_data, BIOSLinker *linker, ++ LoongArchVirtMachineState *lvms) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + MachineClass *mc = MACHINE_GET_CLASS(ms); + const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); + int i, arch_id; +- AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id, +- .oem_table_id = lams->oem_table_id }; ++ AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lvms->oem_id, ++ .oem_table_id = lvms->oem_table_id }; + + acpi_table_begin(&table, table_data); + +@@ -167,11 +168,11 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + int i, arch_id, node_id; + uint64_t mem_len, mem_base; + int nb_numa_nodes = machine->numa_state->num_nodes; +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); +- MachineClass *mc = MACHINE_GET_CLASS(lams); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); + const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine); +- AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id, +- .oem_table_id = lams->oem_table_id }; ++ AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lvms->oem_id, ++ .oem_table_id = lvms->oem_table_id }; + + acpi_table_begin(&table, table_data); + build_append_int_noprefix(table_data, 1, 4); /* Reserved */ +@@ -279,13 +280,13 @@ static void + build_la_ged_aml(Aml *dsdt, MachineState *machine) + { + uint32_t event; +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + + build_ged_aml(dsdt, "\\_SB."GED_DEVICE, +- HOTPLUG_HANDLER(lams->acpi_ged), ++ HOTPLUG_HANDLER(lvms->acpi_ged), + VIRT_SCI_IRQ, AML_SYSTEM_MEMORY, + VIRT_GED_EVT_ADDR); +- event = object_property_get_uint(OBJECT(lams->acpi_ged), ++ event = object_property_get_uint(OBJECT(lvms->acpi_ged), + "ged-event", &error_abort); + if (event & ACPI_GED_MEM_HOTPLUG_EVT) { + build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL, +@@ -295,7 +296,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine) + acpi_dsdt_add_power_button(dsdt); + } + +-static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams) ++static void build_pci_device_aml(Aml *scope, LoongArchVirtMachineState *lvms) + { + struct GPEXConfig cfg = { + .mmio64.base = VIRT_PCI_MEM_BASE, +@@ -305,13 +306,13 @@ static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams) + .ecam.base = VIRT_PCI_CFG_BASE, + .ecam.size = VIRT_PCI_CFG_SIZE, + .irq = VIRT_GSI_BASE + VIRT_DEVICE_IRQS, +- .bus = lams->pci_bus, ++ .bus = lvms->pci_bus, + }; + + acpi_dsdt_add_gpex(scope, &cfg); + } + +-static void build_flash_aml(Aml *scope, LoongArchMachineState *lams) ++static void build_flash_aml(Aml *scope, LoongArchVirtMachineState *lvms) + { + Aml *dev, *crs; + MemoryRegion *flash_mem; +@@ -322,11 +323,11 @@ static void build_flash_aml(Aml *scope, LoongArchMachineState *lams) + hwaddr flash1_base; + hwaddr flash1_size; + +- flash_mem = pflash_cfi01_get_memory(lams->flash[0]); ++ flash_mem = pflash_cfi01_get_memory(lvms->flash[0]); + flash0_base = flash_mem->addr; + flash0_size = memory_region_size(flash_mem); + +- flash_mem = pflash_cfi01_get_memory(lams->flash[1]); ++ flash_mem = pflash_cfi01_get_memory(lvms->flash[1]); + flash1_base = flash_mem->addr; + flash1_size = memory_region_size(flash_mem); + +@@ -352,7 +353,7 @@ static void build_flash_aml(Aml *scope, LoongArchMachineState *lams) + } + + #ifdef CONFIG_TPM +-static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms) ++static void acpi_dsdt_add_tpm(Aml *scope, LoongArchVirtMachineState *vms) + { + PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); + hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS; +@@ -391,18 +392,18 @@ static void + build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) + { + Aml *dsdt, *scope, *pkg; +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); +- AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id, +- .oem_table_id = lams->oem_table_id }; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); ++ AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lvms->oem_id, ++ .oem_table_id = lvms->oem_table_id }; + + acpi_table_begin(&table, table_data); + dsdt = init_aml_allocator(); + build_uart_device_aml(dsdt); +- build_pci_device_aml(dsdt, lams); ++ build_pci_device_aml(dsdt, lvms); + build_la_ged_aml(dsdt, machine); +- build_flash_aml(dsdt, lams); ++ build_flash_aml(dsdt, lvms); + #ifdef CONFIG_TPM +- acpi_dsdt_add_tpm(dsdt, lams); ++ acpi_dsdt_add_tpm(dsdt, lvms); + #endif + /* System State Package */ + scope = aml_scope("\\"); +@@ -421,7 +422,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) + + static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + { +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + GArray *table_offsets; + AcpiFadtData fadt_data; + unsigned facs, rsdt, dsdt; +@@ -455,14 +456,14 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + fadt_data.dsdt_tbl_offset = &dsdt; + fadt_data.xdsdt_tbl_offset = &dsdt; + build_fadt(tables_blob, tables->linker, &fadt_data, +- lams->oem_id, lams->oem_table_id); ++ lvms->oem_id, lvms->oem_table_id); + + acpi_add_table(table_offsets, tables_blob); +- build_madt(tables_blob, tables->linker, lams); ++ build_madt(tables_blob, tables->linker, lvms); + + acpi_add_table(table_offsets, tables_blob); + build_pptt(tables_blob, tables->linker, machine, +- lams->oem_id, lams->oem_table_id); ++ lvms->oem_id, lvms->oem_table_id); + + acpi_add_table(table_offsets, tables_blob); + build_srat(tables_blob, tables->linker, machine); +@@ -470,13 +471,13 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + if (machine->numa_state->num_nodes) { + if (machine->numa_state->have_numa_distance) { + acpi_add_table(table_offsets, tables_blob); +- build_slit(tables_blob, tables->linker, machine, lams->oem_id, +- lams->oem_table_id); ++ build_slit(tables_blob, tables->linker, machine, lvms->oem_id, ++ lvms->oem_table_id); + } + if (machine->numa_state->hmat_enabled) { + acpi_add_table(table_offsets, tables_blob); + build_hmat(tables_blob, tables->linker, machine->numa_state, +- lams->oem_id, lams->oem_table_id); ++ lvms->oem_id, lvms->oem_table_id); + } + } + +@@ -486,8 +487,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + .base = cpu_to_le64(VIRT_PCI_CFG_BASE), + .size = cpu_to_le64(VIRT_PCI_CFG_SIZE), + }; +- build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id, +- lams->oem_table_id); ++ build_mcfg(tables_blob, tables->linker, &mcfg, lvms->oem_id, ++ lvms->oem_table_id); + } + + #ifdef CONFIG_TPM +@@ -495,8 +496,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + 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, lams->oem_id, +- lams->oem_table_id); ++ tables->tcpalog, lvms->oem_id, ++ lvms->oem_table_id); + } + #endif + /* Add tables supplied by user (if any) */ +@@ -510,13 +511,13 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) + /* RSDT is pointed to by RSDP */ + rsdt = tables_blob->len; + build_rsdt(tables_blob, tables->linker, table_offsets, +- lams->oem_id, lams->oem_table_id); ++ lvms->oem_id, lvms->oem_table_id); + + /* RSDP is in FSEG memory, so allocate it separately */ + { + AcpiRsdpData rsdp_data = { + .revision = 0, +- .oem_id = lams->oem_id, ++ .oem_id = lvms->oem_id, + .xsdt_tbl_offset = NULL, + .rsdt_tbl_offset = &rsdt, + }; +@@ -593,17 +594,25 @@ static const VMStateDescription vmstate_acpi_build = { + }, + }; + +-void loongarch_acpi_setup(LoongArchMachineState *lams) ++static bool loongarch_is_acpi_enabled(LoongArchVirtMachineState *lvms) ++{ ++ if (lvms->acpi == ON_OFF_AUTO_OFF) { ++ return false; ++ } ++ return true; ++} ++ ++void loongarch_acpi_setup(LoongArchVirtMachineState *lvms) + { + AcpiBuildTables tables; + AcpiBuildState *build_state; + +- if (!lams->fw_cfg) { ++ if (!lvms->fw_cfg) { + ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); + return; + } + +- if (!loongarch_is_acpi_enabled(lams)) { ++ if (!loongarch_is_acpi_enabled(lvms)) { + ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n"); + return; + } +@@ -611,7 +620,7 @@ void loongarch_acpi_setup(LoongArchMachineState *lams) + build_state = g_malloc0(sizeof *build_state); + + acpi_build_tables_init(&tables); +- acpi_build(&tables, MACHINE(lams)); ++ acpi_build(&tables, MACHINE(lvms)); + + /* Now expose it all to Guest */ + build_state->table_mr = acpi_add_rom_blob(acpi_build_update, +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index e37512729d..b8e1aa18d5 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -259,10 +259,10 @@ static void fw_cfg_add_kernel_info(struct loongarch_boot_info *info, + } + } + +-static void loongarch_firmware_boot(LoongArchMachineState *lams, ++static void loongarch_firmware_boot(LoongArchVirtMachineState *lvms, + struct loongarch_boot_info *info) + { +- fw_cfg_add_kernel_info(info, lams->fw_cfg); ++ fw_cfg_add_kernel_info(info, lvms->fw_cfg); + } + + static void init_boot_rom(struct loongarch_boot_info *info, void *p) +@@ -319,7 +319,7 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + + void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info) + { +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(ms); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(ms); + int i; + + /* register reset function */ +@@ -331,8 +331,8 @@ void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info) + info->kernel_cmdline = ms->kernel_cmdline; + info->initrd_filename = ms->initrd_filename; + +- if (lams->bios_loaded) { +- loongarch_firmware_boot(lams, info); ++ if (lvms->bios_loaded) { ++ loongarch_firmware_boot(lvms, info); + } else { + loongarch_direct_kernel_boot(info); + } +diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c +index f15a17416c..35aeb2decb 100644 +--- a/hw/loongarch/fw_cfg.c ++++ b/hw/loongarch/fw_cfg.c +@@ -17,7 +17,7 @@ static void fw_cfg_boot_set(void *opaque, const char *boot_device, + fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); + } + +-FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms) ++FWCfgState *virt_fw_cfg_init(ram_addr_t ram_size, MachineState *ms) + { + FWCfgState *fw_cfg; + int max_cpus = ms->smp.max_cpus; +diff --git a/hw/loongarch/fw_cfg.h b/hw/loongarch/fw_cfg.h +index 7c0de4db4a..27ee68286e 100644 +--- a/hw/loongarch/fw_cfg.h ++++ b/hw/loongarch/fw_cfg.h +@@ -11,5 +11,5 @@ + #include "hw/boards.h" + #include "hw/nvram/fw_cfg.h" + +-FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms); ++FWCfgState *virt_fw_cfg_init(ram_addr_t ram_size, MachineState *ms); + #endif +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index cca220cb5b..e39989193e 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -48,9 +48,9 @@ + #include "hw/block/flash.h" + #include "qemu/error-report.h" + +-static bool virt_is_veiointc_enabled(LoongArchMachineState *lams) ++static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms) + { +- if (lams->veiointc == ON_OFF_AUTO_OFF) { ++ if (lvms->veiointc == ON_OFF_AUTO_OFF) { + return false; + } + return true; +@@ -59,8 +59,8 @@ static bool virt_is_veiointc_enabled(LoongArchMachineState *lams) + static void virt_get_veiointc(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); +- OnOffAuto veiointc = lams->veiointc; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); ++ OnOffAuto veiointc = lvms->veiointc; + + visit_type_OnOffAuto(v, name, &veiointc, errp); + } +@@ -68,12 +68,12 @@ static void virt_get_veiointc(Object *obj, Visitor *v, const char *name, + static void virt_set_veiointc(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + +- visit_type_OnOffAuto(v, name, &lams->veiointc, errp); ++ visit_type_OnOffAuto(v, name, &lvms->veiointc, errp); + } + +-static PFlashCFI01 *virt_flash_create1(LoongArchMachineState *lams, ++static PFlashCFI01 *virt_flash_create1(LoongArchVirtMachineState *lvms, + const char *name, + const char *alias_prop_name) + { +@@ -88,16 +88,16 @@ static PFlashCFI01 *virt_flash_create1(LoongArchMachineState *lams, + qdev_prop_set_uint16(dev, "id2", 0x00); + qdev_prop_set_uint16(dev, "id3", 0x00); + qdev_prop_set_string(dev, "name", name); +- object_property_add_child(OBJECT(lams), name, OBJECT(dev)); +- object_property_add_alias(OBJECT(lams), alias_prop_name, ++ object_property_add_child(OBJECT(lvms), name, OBJECT(dev)); ++ object_property_add_alias(OBJECT(lvms), alias_prop_name, + OBJECT(dev), "drive"); + return PFLASH_CFI01(dev); + } + +-static void virt_flash_create(LoongArchMachineState *lams) ++static void virt_flash_create(LoongArchVirtMachineState *lvms) + { +- lams->flash[0] = virt_flash_create1(lams, "virt.flash0", "pflash0"); +- lams->flash[1] = virt_flash_create1(lams, "virt.flash1", "pflash1"); ++ lvms->flash[0] = virt_flash_create1(lvms, "virt.flash0", "pflash0"); ++ lvms->flash[1] = virt_flash_create1(lvms, "virt.flash1", "pflash1"); + } + + static void virt_flash_map1(PFlashCFI01 *flash, +@@ -123,20 +123,20 @@ static void virt_flash_map1(PFlashCFI01 *flash, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); + } + +-static void virt_flash_map(LoongArchMachineState *lams, ++static void virt_flash_map(LoongArchVirtMachineState *lvms, + MemoryRegion *sysmem) + { +- PFlashCFI01 *flash0 = lams->flash[0]; +- PFlashCFI01 *flash1 = lams->flash[1]; ++ PFlashCFI01 *flash0 = lvms->flash[0]; ++ PFlashCFI01 *flash1 = lvms->flash[1]; + + virt_flash_map1(flash0, VIRT_FLASH0_BASE, VIRT_FLASH0_SIZE, sysmem); + virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem); + } + +-static void fdt_add_cpuic_node(LoongArchMachineState *lams, ++static void fdt_add_cpuic_node(LoongArchVirtMachineState *lvms, + uint32_t *cpuintc_phandle) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + char *nodename; + + *cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt); +@@ -150,11 +150,11 @@ static void fdt_add_cpuic_node(LoongArchMachineState *lams, + g_free(nodename); + } + +-static void fdt_add_eiointc_node(LoongArchMachineState *lams, ++static void fdt_add_eiointc_node(LoongArchVirtMachineState *lvms, + uint32_t *cpuintc_phandle, + uint32_t *eiointc_phandle) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + char *nodename; + hwaddr extioi_base = APIC_BASE; + hwaddr extioi_size = EXTIOI_SIZE; +@@ -175,11 +175,11 @@ static void fdt_add_eiointc_node(LoongArchMachineState *lams, + g_free(nodename); + } + +-static void fdt_add_pch_pic_node(LoongArchMachineState *lams, ++static void fdt_add_pch_pic_node(LoongArchVirtMachineState *lvms, + uint32_t *eiointc_phandle, + uint32_t *pch_pic_phandle) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + char *nodename; + hwaddr pch_pic_base = VIRT_PCH_REG_BASE; + hwaddr pch_pic_size = VIRT_PCH_REG_SIZE; +@@ -200,11 +200,11 @@ static void fdt_add_pch_pic_node(LoongArchMachineState *lams, + g_free(nodename); + } + +-static void fdt_add_pch_msi_node(LoongArchMachineState *lams, ++static void fdt_add_pch_msi_node(LoongArchVirtMachineState *lvms, + uint32_t *eiointc_phandle, + uint32_t *pch_msi_phandle) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + char *nodename; + hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW; + hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE; +@@ -228,9 +228,9 @@ static void fdt_add_pch_msi_node(LoongArchMachineState *lams, + g_free(nodename); + } + +-static void fdt_add_flash_node(LoongArchMachineState *lams) ++static void fdt_add_flash_node(LoongArchVirtMachineState *lvms) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + char *nodename; + MemoryRegion *flash_mem; + +@@ -240,11 +240,11 @@ static void fdt_add_flash_node(LoongArchMachineState *lams) + hwaddr flash1_base; + hwaddr flash1_size; + +- flash_mem = pflash_cfi01_get_memory(lams->flash[0]); ++ flash_mem = pflash_cfi01_get_memory(lvms->flash[0]); + flash0_base = flash_mem->addr; + flash0_size = memory_region_size(flash_mem); + +- flash_mem = pflash_cfi01_get_memory(lams->flash[1]); ++ flash_mem = pflash_cfi01_get_memory(lvms->flash[1]); + flash1_base = flash_mem->addr; + flash1_size = memory_region_size(flash_mem); + +@@ -258,13 +258,13 @@ static void fdt_add_flash_node(LoongArchMachineState *lams) + g_free(nodename); + } + +-static void fdt_add_rtc_node(LoongArchMachineState *lams, ++static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms, + uint32_t *pch_pic_phandle) + { + char *nodename; + hwaddr base = VIRT_RTC_REG_BASE; + hwaddr size = VIRT_RTC_LEN; +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + + nodename = g_strdup_printf("/rtc@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); +@@ -278,13 +278,13 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams, + g_free(nodename); + } + +-static void fdt_add_uart_node(LoongArchMachineState *lams, ++static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, + uint32_t *pch_pic_phandle) + { + char *nodename; + hwaddr base = VIRT_UART_BASE; + hwaddr size = VIRT_UART_SIZE; +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + + nodename = g_strdup_printf("/serial@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); +@@ -299,11 +299,11 @@ static void fdt_add_uart_node(LoongArchMachineState *lams, + g_free(nodename); + } + +-static void create_fdt(LoongArchMachineState *lams) ++static void create_fdt(LoongArchVirtMachineState *lvms) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + +- ms->fdt = create_device_tree(&lams->fdt_size); ++ ms->fdt = create_device_tree(&lvms->fdt_size); + if (!ms->fdt) { + error_report("create_device_tree() failed"); + exit(1); +@@ -317,10 +317,10 @@ static void create_fdt(LoongArchMachineState *lams) + qemu_fdt_add_subnode(ms->fdt, "/chosen"); + } + +-static void fdt_add_cpu_nodes(const LoongArchMachineState *lams) ++static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms) + { + int num; +- const MachineState *ms = MACHINE(lams); ++ const MachineState *ms = MACHINE(lvms); + int smp_cpus = ms->smp.cpus; + + qemu_fdt_add_subnode(ms->fdt, "/cpus"); +@@ -374,11 +374,11 @@ static void fdt_add_cpu_nodes(const LoongArchMachineState *lams) + } + } + +-static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams) ++static void fdt_add_fw_cfg_node(const LoongArchVirtMachineState *lvms) + { + char *nodename; + hwaddr base = VIRT_FWCFG_BASE; +- const MachineState *ms = MACHINE(lams); ++ const MachineState *ms = MACHINE(lvms); + + nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); +@@ -390,7 +390,7 @@ static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams) + g_free(nodename); + } + +-static void fdt_add_pcie_irq_map_node(const LoongArchMachineState *lams, ++static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState *lvms, + char *nodename, + uint32_t *pch_pic_phandle) + { +@@ -398,7 +398,7 @@ static void fdt_add_pcie_irq_map_node(const LoongArchMachineState *lams, + uint32_t irq_map_stride = 0; + uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {}; + uint32_t *irq_map = full_irq_map; +- const MachineState *ms = MACHINE(lams); ++ const MachineState *ms = MACHINE(lvms); + + /* This code creates a standard swizzle of interrupts such that + * each device's first interrupt is based on it's PCI_SLOT number. +@@ -443,7 +443,7 @@ static void fdt_add_pcie_irq_map_node(const LoongArchMachineState *lams, + 0x1800, 0, 0, 0x7); + } + +-static void fdt_add_pcie_node(const LoongArchMachineState *lams, ++static void fdt_add_pcie_node(const LoongArchVirtMachineState *lvms, + uint32_t *pch_pic_phandle, + uint32_t *pch_msi_phandle) + { +@@ -456,7 +456,7 @@ static void fdt_add_pcie_node(const LoongArchMachineState *lams, + hwaddr size_pcie = VIRT_PCI_CFG_SIZE; + hwaddr base = base_pcie; + +- const MachineState *ms = MACHINE(lams); ++ const MachineState *ms = MACHINE(lvms); + + nodename = g_strdup_printf("/pcie@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); +@@ -479,7 +479,7 @@ static void fdt_add_pcie_node(const LoongArchMachineState *lams, + qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map", + 0, *pch_msi_phandle, 0, 0x10000); + +- fdt_add_pcie_irq_map_node(lams, nodename, pch_pic_phandle); ++ fdt_add_pcie_irq_map_node(lvms, nodename, pch_pic_phandle); + + g_free(nodename); + } +@@ -501,15 +501,15 @@ static void fdt_add_memory_node(MachineState *ms, + g_free(nodename); + } + +-static void virt_build_smbios(LoongArchMachineState *lams) ++static void virt_build_smbios(LoongArchVirtMachineState *lvms) + { +- MachineState *ms = MACHINE(lams); +- MachineClass *mc = MACHINE_GET_CLASS(lams); ++ MachineState *ms = MACHINE(lvms); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); + uint8_t *smbios_tables, *smbios_anchor; + size_t smbios_tables_len, smbios_anchor_len; + const char *product = "QEMU Virtual Machine"; + +- if (!lams->fw_cfg) { ++ if (!lvms->fw_cfg) { + return; + } + +@@ -520,26 +520,26 @@ static void virt_build_smbios(LoongArchMachineState *lams) + &smbios_anchor, &smbios_anchor_len, &error_fatal); + + if (smbios_anchor) { +- fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-tables", ++ fw_cfg_add_file(lvms->fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); +- fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-anchor", ++ fw_cfg_add_file(lvms->fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } + } + +-static void virt_machine_done(Notifier *notifier, void *data) ++static void virt_done(Notifier *notifier, void *data) + { +- LoongArchMachineState *lams = container_of(notifier, +- LoongArchMachineState, machine_done); +- virt_build_smbios(lams); +- loongarch_acpi_setup(lams); ++ LoongArchVirtMachineState *lvms = container_of(notifier, ++ LoongArchVirtMachineState, machine_done); ++ virt_build_smbios(lvms); ++ loongarch_acpi_setup(lvms); + } + + static void virt_powerdown_req(Notifier *notifier, void *opaque) + { +- LoongArchMachineState *s = container_of(notifier, +- LoongArchMachineState, powerdown_notifier); ++ LoongArchVirtMachineState *s; + ++ s = container_of(notifier, LoongArchVirtMachineState, powerdown_notifier); + acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS); + } + +@@ -559,10 +559,11 @@ static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) + memmap_entries++; + } + +-static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState *lams) ++static DeviceState *create_acpi_ged(DeviceState *pch_pic, ++ LoongArchVirtMachineState *lvms) + { + DeviceState *dev; +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + uint32_t event = ACPI_GED_PWR_DOWN_EVT; + + if (ms->ram_slots) { +@@ -609,12 +610,12 @@ static DeviceState *create_platform_bus(DeviceState *pch_pic) + return dev; + } + +-static void loongarch_devices_init(DeviceState *pch_pic, +- LoongArchMachineState *lams, ++static void virt_devices_init(DeviceState *pch_pic, ++ LoongArchVirtMachineState *lvms, + uint32_t *pch_pic_phandle, + uint32_t *pch_msi_phandle) + { +- MachineClass *mc = MACHINE_GET_CLASS(lams); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); + DeviceState *gpex_dev; + SysBusDevice *d; + PCIBus *pci_bus; +@@ -626,7 +627,7 @@ static void loongarch_devices_init(DeviceState *pch_pic, + d = SYS_BUS_DEVICE(gpex_dev); + sysbus_realize_and_unref(d, &error_fatal); + pci_bus = PCI_HOST_BRIDGE(gpex_dev)->bus; +- lams->pci_bus = pci_bus; ++ lvms->pci_bus = pci_bus; + + /* Map only part size_ecam bytes of ECAM space */ + ecam_alias = g_new0(MemoryRegion, 1); +@@ -659,13 +660,13 @@ static void loongarch_devices_init(DeviceState *pch_pic, + } + + /* Add pcie node */ +- fdt_add_pcie_node(lams, pch_pic_phandle, pch_msi_phandle); ++ fdt_add_pcie_node(lvms, pch_pic_phandle, pch_msi_phandle); + + serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0, + qdev_get_gpio_in(pch_pic, + VIRT_UART_IRQ - VIRT_GSI_BASE), + 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); +- fdt_add_uart_node(lams, pch_pic_phandle); ++ fdt_add_uart_node(lvms, pch_pic_phandle); + + /* Network init */ + for (i = 0; i < nb_nics; i++) { +@@ -680,17 +681,17 @@ static void loongarch_devices_init(DeviceState *pch_pic, + sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE, + qdev_get_gpio_in(pch_pic, + VIRT_RTC_IRQ - VIRT_GSI_BASE)); +- fdt_add_rtc_node(lams, pch_pic_phandle); ++ fdt_add_rtc_node(lvms, pch_pic_phandle); + + /* acpi ged */ +- lams->acpi_ged = create_acpi_ged(pch_pic, lams); ++ lvms->acpi_ged = create_acpi_ged(pch_pic, lvms); + /* platform bus */ +- lams->platform_bus_dev = create_platform_bus(pch_pic); ++ lvms->platform_bus_dev = create_platform_bus(pch_pic); + } + +-static void loongarch_irq_init(LoongArchMachineState *lams) ++static void virt_irq_init(LoongArchVirtMachineState *lvms) + { +- MachineState *ms = MACHINE(lams); ++ MachineState *ms = MACHINE(lvms); + DeviceState *pch_pic, *pch_msi, *cpudev; + DeviceState *ipi, *extioi; + SysBusDevice *d; +@@ -728,20 +729,20 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); + + /* IPI iocsr memory region */ +- memory_region_add_subregion(&lams->system_iocsr, SMP_IPI_MAILBOX, ++ memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX, + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0)); +- memory_region_add_subregion(&lams->system_iocsr, MAIL_SEND_ADDR, ++ memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR, + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1)); + + /* Add cpu interrupt-controller */ +- fdt_add_cpuic_node(lams, &cpuintc_phandle); ++ fdt_add_cpuic_node(lvms, &cpuintc_phandle); + + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { + cpu_state = qemu_get_cpu(cpu); + cpudev = DEVICE(cpu_state); + lacpu = LOONGARCH_CPU(cpu_state); + env = &(lacpu->env); +- env->address_space_iocsr = &lams->as_iocsr; ++ env->address_space_iocsr = &lvms->as_iocsr; + + /* connect ipi irq to cpu irq */ + qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); +@@ -751,18 +752,18 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + /* Create EXTIOI device */ + extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); + qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus); +- if (virt_is_veiointc_enabled(lams)) { ++ if (virt_is_veiointc_enabled(lvms)) { + qdev_prop_set_bit(extioi, "has-virtualization-extension", true); + } + sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); + +- memory_region_add_subregion(&lams->system_iocsr, APIC_BASE, ++ memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE, + sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0)); +- if (virt_is_veiointc_enabled(lams)) { +- memory_region_add_subregion(&lams->system_iocsr, EXTIOI_VIRT_BASE, ++ if (virt_is_veiointc_enabled(lvms)) { ++ memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE, + sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1)); + } +- lams->extioi = extioi; ++ lvms->extioi = extioi; + + /* + * connect ext irq to the cpu irq +@@ -777,7 +778,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + } + + /* Add Extend I/O Interrupt Controller node */ +- fdt_add_eiointc_node(lams, &cpuintc_phandle, &eiointc_phandle); ++ fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle); + + pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); + num = VIRT_PCH_PIC_IRQ_NUM; +@@ -799,7 +800,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + } + + /* Add PCH PIC node */ +- fdt_add_pch_pic_node(lams, &eiointc_phandle, &pch_pic_phandle); ++ fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle); + + pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); + start = num; +@@ -816,30 +817,30 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + } + + /* Add PCH MSI node */ +- fdt_add_pch_msi_node(lams, &eiointc_phandle, &pch_msi_phandle); ++ fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle); + +- loongarch_devices_init(pch_pic, lams, &pch_pic_phandle, &pch_msi_phandle); ++ virt_devices_init(pch_pic, lvms, &pch_pic_phandle, &pch_msi_phandle); + } + +-static void loongarch_firmware_init(LoongArchMachineState *lams) ++static void virt_firmware_init(LoongArchVirtMachineState *lvms) + { +- char *filename = MACHINE(lams)->firmware; ++ char *filename = MACHINE(lvms)->firmware; + char *bios_name = NULL; + int bios_size, i; + BlockBackend *pflash_blk0; + MemoryRegion *mr; + +- lams->bios_loaded = false; ++ lvms->bios_loaded = false; + + /* Map legacy -drive if=pflash to machine properties */ +- for (i = 0; i < ARRAY_SIZE(lams->flash); i++) { +- pflash_cfi01_legacy_drive(lams->flash[i], ++ for (i = 0; i < ARRAY_SIZE(lvms->flash); i++) { ++ pflash_cfi01_legacy_drive(lvms->flash[i], + drive_get(IF_PFLASH, 0, i)); + } + +- virt_flash_map(lams, get_system_memory()); ++ virt_flash_map(lvms, get_system_memory()); + +- pflash_blk0 = pflash_cfi01_get_blk(lams->flash[0]); ++ pflash_blk0 = pflash_cfi01_get_blk(lvms->flash[0]); + + if (pflash_blk0) { + if (filename) { +@@ -847,7 +848,7 @@ static void loongarch_firmware_init(LoongArchMachineState *lams) + "options at once"); + exit(1); + } +- lams->bios_loaded = true; ++ lvms->bios_loaded = true; + return; + } + +@@ -858,14 +859,14 @@ static void loongarch_firmware_init(LoongArchMachineState *lams) + exit(1); + } + +- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(lams->flash[0]), 0); ++ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(lvms->flash[0]), 0); + bios_size = load_image_mr(bios_name, mr); + if (bios_size < 0) { + error_report("Could not load ROM image '%s'", bios_name); + exit(1); + } + g_free(bios_name); +- lams->bios_loaded = true; ++ lvms->bios_loaded = true; + } + } + +@@ -873,16 +874,16 @@ static void loongarch_firmware_init(LoongArchMachineState *lams) + static MemTxResult loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size, MemTxAttrs attrs) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(opaque); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque); + uint64_t features; + + switch (addr) { + case MISC_FUNC_REG: +- if (!virt_is_veiointc_enabled(lams)) { ++ if (!virt_is_veiointc_enabled(lvms)) { + return MEMTX_OK; + } + +- features = address_space_ldl(&lams->as_iocsr, ++ features = address_space_ldl(&lvms->as_iocsr, + EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, + attrs, NULL); + if (val & BIT_ULL(IOCSRM_EXTIOI_EN)) { +@@ -892,7 +893,7 @@ static MemTxResult loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, + features |= BIT(EXTIOI_ENABLE_INT_ENCODE); + } + +- address_space_stl(&lams->as_iocsr, ++ address_space_stl(&lvms->as_iocsr, + EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, + features, attrs, NULL); + } +@@ -904,7 +905,7 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, + uint64_t *data, + unsigned size, MemTxAttrs attrs) + { +- LoongArchMachineState *lams = LOONGARCH_MACHINE(opaque); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque); + uint64_t ret = 0; + int features; + +@@ -926,12 +927,12 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, + ret = 0x303030354133ULL; /* "3A5000" */ + break; + case MISC_FUNC_REG: +- if (!virt_is_veiointc_enabled(lams)) { ++ if (!virt_is_veiointc_enabled(lvms)) { + ret |= BIT_ULL(IOCSRM_EXTIOI_EN); + break; + } + +- features = address_space_ldl(&lams->as_iocsr, ++ features = address_space_ldl(&lvms->as_iocsr, + EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, + attrs, NULL); + if (features & BIT(EXTIOI_ENABLE)) { +@@ -948,7 +949,7 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, + return MEMTX_OK; + } + +-static const MemoryRegionOps loongarch_qemu_ops = { ++static const MemoryRegionOps virt_iocsr_misc_ops = { + .read_with_attrs = loongarch_qemu_read, + .write_with_attrs = loongarch_qemu_write, + .endianness = DEVICE_LITTLE_ENDIAN, +@@ -962,7 +963,7 @@ static const MemoryRegionOps loongarch_qemu_ops = { + }, + }; + +-static void loongarch_init(MachineState *machine) ++static void virt_init(MachineState *machine) + { + LoongArchCPU *lacpu; + const char *cpu_model = machine->cpu_type; +@@ -970,7 +971,7 @@ static void loongarch_init(MachineState *machine) + ram_addr_t ram_size = machine->ram_size; + uint64_t highram_size = 0, phyAddr = 0; + MemoryRegion *address_space_mem = get_system_memory(); +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + int nb_numa_nodes = machine->numa_state->num_nodes; + NodeInfo *numa_info = machine->numa_state->nodes; + int i; +@@ -986,16 +987,16 @@ static void loongarch_init(MachineState *machine) + error_report("ram_size must be greater than 1G."); + exit(1); + } +- create_fdt(lams); ++ create_fdt(lvms); + + /* Create IOCSR space */ +- memory_region_init_io(&lams->system_iocsr, OBJECT(machine), NULL, ++ memory_region_init_io(&lvms->system_iocsr, OBJECT(machine), NULL, + machine, "iocsr", UINT64_MAX); +- address_space_init(&lams->as_iocsr, &lams->system_iocsr, "IOCSR"); +- memory_region_init_io(&lams->iocsr_mem, OBJECT(machine), +- &loongarch_qemu_ops, ++ address_space_init(&lvms->as_iocsr, &lvms->system_iocsr, "IOCSR"); ++ memory_region_init_io(&lvms->iocsr_mem, OBJECT(machine), ++ &virt_iocsr_misc_ops, + machine, "iocsr_misc", 0x428); +- memory_region_add_subregion(&lams->system_iocsr, 0, &lams->iocsr_mem); ++ memory_region_add_subregion(&lvms->system_iocsr, 0, &lvms->iocsr_mem); + + /* Init CPUs */ + possible_cpus = mc->possible_cpu_arch_ids(machine); +@@ -1006,14 +1007,14 @@ static void loongarch_init(MachineState *machine) + lacpu = LOONGARCH_CPU(cpu); + lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id; + } +- fdt_add_cpu_nodes(lams); ++ fdt_add_cpu_nodes(lvms); + + /* Node0 memory */ + memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1); + fdt_add_memory_node(machine, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 0); +- memory_region_init_alias(&lams->lowmem, NULL, "loongarch.node0.lowram", ++ memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.node0.lowram", + machine->ram, offset, VIRT_LOWMEM_SIZE); +- memory_region_add_subregion(address_space_mem, phyAddr, &lams->lowmem); ++ memory_region_add_subregion(address_space_mem, phyAddr, &lvms->lowmem); + + offset += VIRT_LOWMEM_SIZE; + if (nb_numa_nodes > 0) { +@@ -1025,9 +1026,9 @@ static void loongarch_init(MachineState *machine) + phyAddr = VIRT_HIGHMEM_BASE; + memmap_add_entry(phyAddr, highram_size, 1); + fdt_add_memory_node(machine, phyAddr, highram_size, 0); +- memory_region_init_alias(&lams->highmem, NULL, "loongarch.node0.highram", ++ memory_region_init_alias(&lvms->highmem, NULL, "loongarch.node0.highram", + machine->ram, offset, highram_size); +- memory_region_add_subregion(address_space_mem, phyAddr, &lams->highmem); ++ memory_region_add_subregion(address_space_mem, phyAddr, &lvms->highmem); + + /* Node1 - Nodemax memory */ + offset += highram_size; +@@ -1068,30 +1069,30 @@ static void loongarch_init(MachineState *machine) + } + + /* load the BIOS image. */ +- loongarch_firmware_init(lams); ++ virt_firmware_init(lvms); + + /* fw_cfg init */ +- lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine); +- rom_set_fw(lams->fw_cfg); +- if (lams->fw_cfg != NULL) { +- fw_cfg_add_file(lams->fw_cfg, "etc/memmap", ++ lvms->fw_cfg = virt_fw_cfg_init(ram_size, machine); ++ rom_set_fw(lvms->fw_cfg); ++ if (lvms->fw_cfg != NULL) { ++ fw_cfg_add_file(lvms->fw_cfg, "etc/memmap", + memmap_table, + sizeof(struct memmap_entry) * (memmap_entries)); + } +- fdt_add_fw_cfg_node(lams); +- fdt_add_flash_node(lams); ++ fdt_add_fw_cfg_node(lvms); ++ fdt_add_flash_node(lvms); + + /* Initialize the IO interrupt subsystem */ +- loongarch_irq_init(lams); ++ virt_irq_init(lvms); + platform_bus_add_all_fdt_nodes(machine->fdt, "/platic", + VIRT_PLATFORM_BUS_BASEADDRESS, + VIRT_PLATFORM_BUS_SIZE, + VIRT_PLATFORM_BUS_IRQ); +- lams->machine_done.notify = virt_machine_done; +- qemu_add_machine_init_done_notifier(&lams->machine_done); ++ lvms->machine_done.notify = virt_done; ++ qemu_add_machine_init_done_notifier(&lvms->machine_done); + /* connect powerdown request */ +- lams->powerdown_notifier.notify = virt_powerdown_req; +- qemu_register_powerdown_notifier(&lams->powerdown_notifier); ++ lvms->powerdown_notifier.notify = virt_powerdown_req; ++ qemu_register_powerdown_notifier(&lvms->powerdown_notifier); + + /* + * Since lowmem region starts from 0 and Linux kernel legacy start address +@@ -1100,52 +1101,44 @@ static void loongarch_init(MachineState *machine) + * Put the FDT into the memory map as a ROM image: this will ensure + * the FDT is copied again upon reset, even if addr points into RAM. + */ +- qemu_fdt_dumpdtb(machine->fdt, lams->fdt_size); +- rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, FDT_BASE, ++ qemu_fdt_dumpdtb(machine->fdt, lvms->fdt_size); ++ rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE, + &address_space_memory); + qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, +- rom_ptr_for_as(&address_space_memory, FDT_BASE, lams->fdt_size)); ++ rom_ptr_for_as(&address_space_memory, FDT_BASE, lvms->fdt_size)); + +- lams->bootinfo.ram_size = ram_size; +- loongarch_load_kernel(machine, &lams->bootinfo); ++ lvms->bootinfo.ram_size = ram_size; ++ loongarch_load_kernel(machine, &lvms->bootinfo); + } + +-bool loongarch_is_acpi_enabled(LoongArchMachineState *lams) ++static void virt_get_acpi(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) + { +- if (lams->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 *lams = LOONGARCH_VIRT_MACHINE(obj); +- OnOffAuto acpi = lams->acpi; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); ++ OnOffAuto acpi = lvms->acpi; + + visit_type_OnOffAuto(v, name, &acpi, errp); + } + +-static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name, ++static void virt_set_acpi(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + +- visit_type_OnOffAuto(v, name, &lams->acpi, errp); ++ visit_type_OnOffAuto(v, name, &lvms->acpi, errp); + } + +-static void loongarch_machine_initfn(Object *obj) ++static void virt_initfn(Object *obj) + { +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + + if (tcg_enabled()) { +- lams->veiointc = ON_OFF_AUTO_OFF; ++ lvms->veiointc = ON_OFF_AUTO_OFF; + } +- lams->acpi = ON_OFF_AUTO_AUTO; +- lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); +- lams->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); +- virt_flash_create(lams); ++ lvms->acpi = ON_OFF_AUTO_AUTO; ++ lvms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); ++ lvms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); ++ virt_flash_create(lvms); + } + + static bool memhp_type_supported(DeviceState *dev) +@@ -1161,7 +1154,7 @@ static void virt_mem_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp); + } + +-static void virt_machine_device_pre_plug(HotplugHandler *hotplug_dev, ++static void virt_device_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { + if (memhp_type_supported(dev)) { +@@ -1172,14 +1165,14 @@ static void virt_machine_device_pre_plug(HotplugHandler *hotplug_dev, + static void virt_mem_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); + + /* the acpi ged is always exist */ +- hotplug_handler_unplug_request(HOTPLUG_HANDLER(lams->acpi_ged), dev, ++ hotplug_handler_unplug_request(HOTPLUG_HANDLER(lvms->acpi_ged), dev, + errp); + } + +-static void virt_machine_device_unplug_request(HotplugHandler *hotplug_dev, ++static void virt_device_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { + if (memhp_type_supported(dev)) { +@@ -1190,14 +1183,14 @@ static void virt_machine_device_unplug_request(HotplugHandler *hotplug_dev, + static void virt_mem_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); + +- hotplug_handler_unplug(HOTPLUG_HANDLER(lams->acpi_ged), dev, errp); +- pc_dimm_unplug(PC_DIMM(dev), MACHINE(lams)); ++ hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, errp); ++ pc_dimm_unplug(PC_DIMM(dev), MACHINE(lvms)); + qdev_unrealize(dev); + } + +-static void virt_machine_device_unplug(HotplugHandler *hotplug_dev, ++static void virt_device_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { + if (memhp_type_supported(dev)) { +@@ -1208,31 +1201,32 @@ static void virt_machine_device_unplug(HotplugHandler *hotplug_dev, + static void virt_mem_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); + +- pc_dimm_plug(PC_DIMM(dev), MACHINE(lams)); +- hotplug_handler_plug(HOTPLUG_HANDLER(lams->acpi_ged), ++ pc_dimm_plug(PC_DIMM(dev), MACHINE(lvms)); ++ hotplug_handler_plug(HOTPLUG_HANDLER(lvms->acpi_ged), + dev, &error_abort); + } + +-static void loongarch_machine_device_plug_cb(HotplugHandler *hotplug_dev, ++static void virt_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev); +- MachineClass *mc = MACHINE_GET_CLASS(lams); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); ++ PlatformBusDevice *pbus; + + if (device_is_dynamic_sysbus(mc, dev)) { +- if (lams->platform_bus_dev) { +- platform_bus_link_device(PLATFORM_BUS_DEVICE(lams->platform_bus_dev), +- SYS_BUS_DEVICE(dev)); ++ if (lvms->platform_bus_dev) { ++ pbus = PLATFORM_BUS_DEVICE(lvms->platform_bus_dev); ++ platform_bus_link_device(pbus, SYS_BUS_DEVICE(dev)); + } + } else if (memhp_type_supported(dev)) { + virt_mem_plug(hotplug_dev, dev, errp); + } + } + +-static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, +- DeviceState *dev) ++static HotplugHandler *virt_get_hotplug_handler(MachineState *machine, ++ DeviceState *dev) + { + MachineClass *mc = MACHINE_GET_CLASS(machine); + +@@ -1272,8 +1266,8 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + return ms->possible_cpus; + } + +-static CpuInstanceProperties +-virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index) ++static CpuInstanceProperties virt_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); +@@ -1295,12 +1289,12 @@ static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx) + return nidx; + } + +-static void loongarch_class_init(ObjectClass *oc, void *data) ++static void virt_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); + +- mc->init = loongarch_init; ++ mc->init = virt_init; + mc->default_ram_size = 1 * GiB; + mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464"); + mc->default_ram_id = "loongarch.ram"; +@@ -1316,15 +1310,15 @@ static void loongarch_class_init(ObjectClass *oc, void *data) + mc->numa_mem_supported = true; + mc->auto_enable_numa_with_memhp = true; + mc->auto_enable_numa_with_memdev = true; +- mc->get_hotplug_handler = virt_machine_get_hotplug_handler; ++ mc->get_hotplug_handler = virt_get_hotplug_handler; + mc->default_nic = "virtio-net-pci"; +- hc->plug = loongarch_machine_device_plug_cb; +- hc->pre_plug = virt_machine_device_pre_plug; +- hc->unplug_request = virt_machine_device_unplug_request; +- hc->unplug = virt_machine_device_unplug; ++ hc->plug = virt_device_plug_cb; ++ hc->pre_plug = virt_device_pre_plug; ++ hc->unplug_request = virt_device_unplug_request; ++ hc->unplug = virt_device_unplug; + + object_class_property_add(oc, "acpi", "OnOffAuto", +- loongarch_get_acpi, loongarch_set_acpi, ++ virt_get_acpi, virt_set_acpi, + NULL, NULL); + object_class_property_set_description(oc, "acpi", + "Enable ACPI"); +@@ -1338,13 +1332,13 @@ static void loongarch_class_init(ObjectClass *oc, void *data) + #endif + } + +-static const TypeInfo loongarch_machine_types[] = { ++static const TypeInfo virt_machine_types[] = { + { + .name = TYPE_LOONGARCH_VIRT_MACHINE, + .parent = TYPE_MACHINE, +- .instance_size = sizeof(LoongArchMachineState), +- .class_init = loongarch_class_init, +- .instance_init = loongarch_machine_initfn, ++ .instance_size = sizeof(LoongArchVirtMachineState), ++ .class_init = virt_class_init, ++ .instance_init = virt_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } +@@ -1352,4 +1346,4 @@ static const TypeInfo loongarch_machine_types[] = { + } + }; + +-DEFINE_TYPES(loongarch_machine_types) ++DEFINE_TYPES(virt_machine_types) +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 0509b9a9af..0a4d9a25f0 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -37,7 +37,7 @@ + + #define FDT_BASE 0x100000 + +-struct LoongArchMachineState { ++struct LoongArchVirtMachineState { + /*< private >*/ + MachineState parent_obj; + +@@ -67,7 +67,6 @@ struct LoongArchMachineState { + }; + + #define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +-OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_VIRT_MACHINE) +-bool loongarch_is_acpi_enabled(LoongArchMachineState *lams); +-void loongarch_acpi_setup(LoongArchMachineState *lams); ++OBJECT_DECLARE_SIMPLE_TYPE(LoongArchVirtMachineState, LOONGARCH_VIRT_MACHINE) ++void loongarch_acpi_setup(LoongArchVirtMachineState *lvms); + #endif +-- +2.39.1 + diff --git a/hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch b/hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch new file mode 100644 index 0000000000000000000000000000000000000000..8ac61a24faf92d8331dba704172323b3239f362f --- /dev/null +++ b/hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch @@ -0,0 +1,47 @@ +From b7217c8f9b3f1d611485bad1263e109484a743e3 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Wed, 30 Oct 2024 09:23:59 +0800 +Subject: [PATCH 77/78] hw/loongarch/boot: Use warn_report when no kernel + filename +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When we run “qemu-system-loongarch64 -qmp stdio -vnc none -S”, +we get an error message “Need kernel filename” and then we can't use qmp cmd to query some information. +So, we just throw a warning and then the cpus starts running from address VIRT_FLASH0_BASE. + +Signed-off-by: Song Gao +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20241030012359.4040817-1-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index cb668703bd..f258eefe9a 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -278,7 +278,7 @@ static void init_boot_rom(struct loongarch_boot_info *info, void *p) + static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + { + void *p, *bp; +- int64_t kernel_addr = 0; ++ int64_t kernel_addr = VIRT_FLASH0_BASE; + LoongArchCPU *lacpu; + CPUState *cs; + +@@ -286,8 +286,7 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) + kernel_addr = load_kernel_info(info); + } else { + if(!qtest_enabled()) { +- error_report("Need kernel filename\n"); +- exit(1); ++ warn_report("No kernel provided, booting from flash drive."); + } + } + +-- +2.39.1 + diff --git a/hw-loongarch-boot.c-fix-out-of-bound-reading.patch b/hw-loongarch-boot.c-fix-out-of-bound-reading.patch new file mode 100644 index 0000000000000000000000000000000000000000..8e1b0e90b50a7347cf64f5d2764137b6f742d507 --- /dev/null +++ b/hw-loongarch-boot.c-fix-out-of-bound-reading.patch @@ -0,0 +1,35 @@ +From f9cc704bbcf8bb8a06095289921dc88944d0fe94 Mon Sep 17 00:00:00 2001 +From: Dmitry Frolov +Date: Fri, 28 Jun 2024 15:39:10 +0300 +Subject: [PATCH 30/78] hw/loongarch/boot.c: fix out-of-bound reading + +memcpy() is trying to READ 512 bytes from memory, +pointed by info->kernel_cmdline, +which was (presumable) allocated by g_strdup(""); +Found with ASAN, making check with enabled sanitizers. + +Signed-off-by: Dmitry Frolov +Reviewed-by: Song Gao +Message-Id: <20240628123910.577740-1-frolov@swemel.ru> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index b8e1aa18d5..cb668703bd 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -163,7 +163,7 @@ static void init_cmdline(struct loongarch_boot_info *info, void *p, void *start) + info->a0 = 1; + info->a1 = cmdline_addr; + +- memcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE); ++ g_strlcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE); + } + + static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) +-- +2.39.1 + diff --git a/hw-loongarch-clean-code.patch b/hw-loongarch-clean-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..45d44f40e665c5780870407720971d1558b78031 --- /dev/null +++ b/hw-loongarch-clean-code.patch @@ -0,0 +1,197 @@ +From 4a74147e1b2e276eb2ad2855bafc3c0136bc18a3 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 22:34:57 +0800 +Subject: [PATCH 76/78] hw/loongarch: clean code + +remove some unused code + +Signed-off-by: gaosong +Signed-off-by: Xianglai Li +--- + target/loongarch/kvm/kvm.c | 103 --------------------------- + target/loongarch/kvm/kvm_loongarch.h | 2 - + target/loongarch/machine.c | 20 ------ + 3 files changed, 125 deletions(-) + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index ab1ea3d4fd..0acdd5c4c1 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -684,53 +684,6 @@ static int kvm_check_cpucfg2(CPUState *cs) + return ret; + } + +-static int kvm_check_cpucfg6(CPUState *cs) +-{ +- int ret; +- uint64_t val; +- struct kvm_device_attr attr = { +- .group = KVM_LOONGARCH_VCPU_CPUCFG, +- .attr = 6, +- .addr = (uint64_t)&val, +- }; +- LoongArchCPU *cpu = LOONGARCH_CPU(cs); +- CPULoongArchState *env = &cpu->env; +- +- ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); +- if (!ret) { +- kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr); +- +- if (FIELD_EX32(env->cpucfg[6], CPUCFG6, PMP)) { +- /* Check PMP */ +- if (!FIELD_EX32(val, CPUCFG6, PMP)) { +- error_report("'pmu' feature not supported by KVM on this host" +- " Please disable 'pmu' with " +- "'... -cpu XXX,pmu=off ...'\n"); +- exit(EXIT_FAILURE); +- } +- /* Check PMNUM */ +- int guest_pmnum = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMNUM); +- int host_pmnum = FIELD_EX32(val, CPUCFG6, PMNUM); +- if (guest_pmnum > host_pmnum){ +- warn_report("The guest pmnum %d larger than KVM support %d\n", +- guest_pmnum, host_pmnum); +- env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, +- PMNUM, host_pmnum); +- } +- /* Check PMBITS */ +- int guest_pmbits = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMBITS); +- int host_pmbits = FIELD_EX32(val, CPUCFG6, PMBITS); +- if (guest_pmbits != host_pmbits) { +- warn_report("The host not support PMBITS %d\n", guest_pmbits); +- env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, +- PMBITS, host_pmbits); +- } +- } +- } +- +- return ret; +-} +- + static int kvm_loongarch_put_cpucfg(CPUState *cs) + { + int i, ret = 0; +@@ -745,12 +698,6 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs) + return ret; + } + } +- if (i == 6) { +- ret = kvm_check_cpucfg6(cs); +- if (ret) { +- return ret; +- } +- } + val = env->cpucfg[i]; + ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val); + if (ret < 0) { +@@ -760,56 +707,6 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs) + return ret; + } + +-int kvm_loongarch_put_pvtime(LoongArchCPU *cpu) +-{ +- CPULoongArchState *env = &cpu->env; +- int err; +- struct kvm_device_attr attr = { +- .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, +- .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, +- .addr = (uint64_t)&env->st.guest_addr, +- }; +- +- err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr); +- if (err != 0) { +- /* It's ok even though kvm has not such attr */ +- return 0; +- } +- +- err = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_DEVICE_ATTR, attr); +- if (err != 0) { +- error_report("PVTIME IPA: KVM_SET_DEVICE_ATTR: %s", strerror(-err)); +- return err; +- } +- +- return 0; +-} +- +-int kvm_loongarch_get_pvtime(LoongArchCPU *cpu) +-{ +- CPULoongArchState *env = &cpu->env; +- int err; +- struct kvm_device_attr attr = { +- .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, +- .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, +- .addr = (uint64_t)&env->st.guest_addr, +- }; +- +- err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr); +- if (err != 0) { +- /* It's ok even though kvm has not such attr */ +- return 0; +- } +- +- err = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_DEVICE_ATTR, attr); +- if (err != 0) { +- error_report("PVTIME IPA: KVM_GET_DEVICE_ATTR: %s", strerror(-err)); +- return err; +- } +- +- return 0; +-} +- + int kvm_arch_get_registers(CPUState *cs) + { + int ret; +diff --git a/target/loongarch/kvm/kvm_loongarch.h b/target/loongarch/kvm/kvm_loongarch.h +index 8482f9308d..1051a341ec 100644 +--- a/target/loongarch/kvm/kvm_loongarch.h ++++ b/target/loongarch/kvm/kvm_loongarch.h +@@ -11,8 +11,6 @@ + #define QEMU_KVM_LOONGARCH_H + + int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level); +-int kvm_loongarch_put_pvtime(LoongArchCPU *cpu); +-int kvm_loongarch_get_pvtime(LoongArchCPU *cpu); + void kvm_arch_reset_vcpu(CPUState *cs); + + #endif +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index fd69ea05dc..57abdddc09 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -112,24 +112,6 @@ static const VMStateDescription vmstate_lasx = { + }, + }; + +-static int cpu_post_load(void *opaque, int version_id) +-{ +-#ifdef CONFIG_KVM +- LoongArchCPU *cpu = opaque; +- kvm_loongarch_put_pvtime(cpu); +-#endif +- return 0; +-} +- +-static int cpu_pre_save(void *opaque) +-{ +-#ifdef CONFIG_KVM +- LoongArchCPU *cpu = opaque; +- kvm_loongarch_get_pvtime(cpu); +-#endif +- return 0; +-} +- + static bool lbt_needed(void *opaque) + { + LoongArchCPU *cpu = opaque; +@@ -190,8 +172,6 @@ const VMStateDescription vmstate_loongarch_cpu = { + .name = "cpu", + .version_id = 3, + .minimum_version_id = 3, +- .post_load = cpu_post_load, +- .pre_save = cpu_pre_save, + .fields = (const VMStateField[]) { + VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32), + VMSTATE_UINTTL(env.pc, LoongArchCPU), +-- +2.39.1 + diff --git a/hw-loongarch-fdt-adds-Extend-I-O-Interrupt-Controlle.patch b/hw-loongarch-fdt-adds-Extend-I-O-Interrupt-Controlle.patch new file mode 100644 index 0000000000000000000000000000000000000000..ebab65007b888cafff0af13bf9942fe1c6e68a79 --- /dev/null +++ b/hw-loongarch-fdt-adds-Extend-I-O-Interrupt-Controlle.patch @@ -0,0 +1,91 @@ +From ed42940a2d943fd0e666e46bbc9b599b9ed1bd75 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:45 +0800 +Subject: [PATCH 10/78] hw/loongarch: fdt adds Extend I/O Interrupt Controller + +fdt adds Extend I/O Interrupt Controller, +we use 'loongson,ls2k2000-eiointc'. + +See: +https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-eiointc.c +https://lore.kernel.org/r/764e02d924094580ac0f1d15535f4b98308705c6.1683279769.git.zhoubinbin@loongson.cn + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-12-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 30 +++++++++++++++++++++++++++++- + include/hw/intc/loongarch_extioi.h | 1 + + 2 files changed, 30 insertions(+), 1 deletion(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index fdc4a5d708..820eb52cba 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -150,6 +150,31 @@ static void fdt_add_cpuic_node(LoongArchMachineState *lams, + g_free(nodename); + } + ++static void fdt_add_eiointc_node(LoongArchMachineState *lams, ++ uint32_t *cpuintc_phandle, ++ uint32_t *eiointc_phandle) ++{ ++ MachineState *ms = MACHINE(lams); ++ char *nodename; ++ hwaddr extioi_base = APIC_BASE; ++ hwaddr extioi_size = EXTIOI_SIZE; ++ ++ *eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt); ++ nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base); ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,ls2k2000-eiointc"); ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *cpuintc_phandle); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, ++ extioi_base, 0x0, extioi_size); ++ g_free(nodename); ++} ++ + static void fdt_add_flash_node(LoongArchMachineState *lams) + { + MachineState *ms = MACHINE(lams); +@@ -574,7 +599,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + CPULoongArchState *env; + CPUState *cpu_state; + int cpu, pin, i, start, num; +- uint32_t cpuintc_phandle; ++ uint32_t cpuintc_phandle, eiointc_phandle; + + /* + * The connection of interrupts: +@@ -652,6 +677,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + } + } + ++ /* Add Extend I/O Interrupt Controller node */ ++ fdt_add_eiointc_node(lams, &cpuintc_phandle, &eiointc_phandle); ++ + pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); + num = VIRT_PCH_PIC_IRQ_NUM; + qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num); +diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h +index 98f348c49d..722ffee1bc 100644 +--- a/include/hw/intc/loongarch_extioi.h ++++ b/include/hw/intc/loongarch_extioi.h +@@ -39,6 +39,7 @@ + #define EXTIOI_COREISR_END (0xB20 - APIC_OFFSET) + #define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET) + #define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET) ++#define EXTIOI_SIZE 0x800 + + #define EXTIOI_VIRT_BASE (0x40000000) + #define EXTIOI_VIRT_SIZE (0x1000) +-- +2.39.1 + diff --git a/hw-loongarch-fdt-adds-cpu-interrupt-controller-node.patch b/hw-loongarch-fdt-adds-cpu-interrupt-controller-node.patch new file mode 100644 index 0000000000000000000000000000000000000000..5c65e60d3ed95b8a5052e7e2fadcdff9672d3a45 --- /dev/null +++ b/hw-loongarch-fdt-adds-cpu-interrupt-controller-node.patch @@ -0,0 +1,69 @@ +From cd506fbf0d9a00aa0f25de1e7bd26ad4335c8257 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:44 +0800 +Subject: [PATCH 09/78] hw/loongarch: fdt adds cpu interrupt controller node + +fdt adds cpu interrupt controller node, +we use 'loongson,cpu-interrupt-controller'. + +See: +https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongarch-cpu.c +https://lore.kernel.org/r/20221114113824.1880-2-liupeibao@loongson.cn + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-11-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 99a3dc8696..fdc4a5d708 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -133,6 +133,23 @@ static void virt_flash_map(LoongArchMachineState *lams, + virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem); + } + ++static void fdt_add_cpuic_node(LoongArchMachineState *lams, ++ uint32_t *cpuintc_phandle) ++{ ++ MachineState *ms = MACHINE(lams); ++ char *nodename; ++ ++ *cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt); ++ nodename = g_strdup_printf("/cpuic"); ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,cpu-interrupt-controller"); ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1); ++ g_free(nodename); ++} ++ + static void fdt_add_flash_node(LoongArchMachineState *lams) + { + MachineState *ms = MACHINE(lams); +@@ -557,6 +574,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + CPULoongArchState *env; + CPUState *cpu_state; + int cpu, pin, i, start, num; ++ uint32_t cpuintc_phandle; + + /* + * The connection of interrupts: +@@ -591,6 +609,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + memory_region_add_subregion(&lams->system_iocsr, MAIL_SEND_ADDR, + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1)); + ++ /* Add cpu interrupt-controller */ ++ fdt_add_cpuic_node(lams, &cpuintc_phandle); ++ + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { + cpu_state = qemu_get_cpu(cpu); + cpudev = DEVICE(cpu_state); +-- +2.39.1 + diff --git a/hw-loongarch-fdt-adds-pch_msi-Controller.patch b/hw-loongarch-fdt-adds-pch_msi-Controller.patch new file mode 100644 index 0000000000000000000000000000000000000000..ce895f52286086d5e4d3f7f98a401b8ac0b7a5a8 --- /dev/null +++ b/hw-loongarch-fdt-adds-pch_msi-Controller.patch @@ -0,0 +1,93 @@ +From ea34d3896abfaf67cdf7fdb3cb205cc5a0e2e708 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:47 +0800 +Subject: [PATCH 12/78] hw/loongarch: fdt adds pch_msi Controller + +fdt adds pch msi controller, we use 'loongson,pch-msi-1.0'. + +See: +https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-msi.c +https://lore.kernel.org/r/20200528152757.1028711-6-jiaxun.yang@flygoat.com + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-14-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 33 ++++++++++++++++++++++++++++++++- + include/hw/pci-host/ls7a.h | 1 + + 2 files changed, 33 insertions(+), 1 deletion(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 36fcfd12eb..032106ebad 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -200,6 +200,34 @@ static void fdt_add_pch_pic_node(LoongArchMachineState *lams, + g_free(nodename); + } + ++static void fdt_add_pch_msi_node(LoongArchMachineState *lams, ++ uint32_t *eiointc_phandle, ++ uint32_t *pch_msi_phandle) ++{ ++ MachineState *ms = MACHINE(lams); ++ char *nodename; ++ hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW; ++ hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE; ++ ++ *pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt); ++ nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base); ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,pch-msi-1.0"); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", ++ 0, pch_msi_base, ++ 0, pch_msi_size); ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *eiointc_phandle); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec", ++ VIRT_PCH_PIC_IRQ_NUM); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs", ++ EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM); ++ g_free(nodename); ++} ++ + static void fdt_add_flash_node(LoongArchMachineState *lams) + { + MachineState *ms = MACHINE(lams); +@@ -624,7 +652,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + CPULoongArchState *env; + CPUState *cpu_state; + int cpu, pin, i, start, num; +- uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle; ++ uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, pch_msi_phandle; + + /* + * The connection of interrupts: +@@ -741,6 +769,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + qdev_get_gpio_in(extioi, i + start)); + } + ++ /* Add PCH MSI node */ ++ fdt_add_pch_msi_node(lams, &eiointc_phandle, &pch_msi_phandle); ++ + loongarch_devices_init(pch_pic, lams); + } + +diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h +index fe260f0183..cd7c9ec7bc 100644 +--- a/include/hw/pci-host/ls7a.h ++++ b/include/hw/pci-host/ls7a.h +@@ -25,6 +25,7 @@ + #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE) + #define VIRT_PCH_MSI_ADDR_LOW 0x2FF00000UL + #define VIRT_PCH_REG_SIZE 0x400 ++#define VIRT_PCH_MSI_SIZE 0x8 + + /* + * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot +-- +2.39.1 + diff --git a/hw-loongarch-fdt-adds-pch_pic-Controller.patch b/hw-loongarch-fdt-adds-pch_pic-Controller.patch new file mode 100644 index 0000000000000000000000000000000000000000..87ab827d7acff7a2c3663db79b4d7f5aa3a67890 --- /dev/null +++ b/hw-loongarch-fdt-adds-pch_pic-Controller.patch @@ -0,0 +1,90 @@ +From 78222abb3bde044b4520f23c6fc2f0f0bd805d2a Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:46 +0800 +Subject: [PATCH 11/78] hw/loongarch: fdt adds pch_pic Controller + +fdt adds pch pic controller, we use 'loongson,pch-pic-1.0' + +See: +https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-pic.c +https://lore.kernel.org/r/20200528152757.1028711-4-jiaxun.yang@flygoat.com + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-13-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 30 +++++++++++++++++++++++++++++- + include/hw/pci-host/ls7a.h | 1 + + 2 files changed, 30 insertions(+), 1 deletion(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 820eb52cba..36fcfd12eb 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -175,6 +175,31 @@ static void fdt_add_eiointc_node(LoongArchMachineState *lams, + g_free(nodename); + } + ++static void fdt_add_pch_pic_node(LoongArchMachineState *lams, ++ uint32_t *eiointc_phandle, ++ uint32_t *pch_pic_phandle) ++{ ++ MachineState *ms = MACHINE(lams); ++ char *nodename; ++ hwaddr pch_pic_base = VIRT_PCH_REG_BASE; ++ hwaddr pch_pic_size = VIRT_PCH_REG_SIZE; ++ ++ *pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt); ++ nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base); ++ qemu_fdt_add_subnode(ms->fdt, nodename); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_pic_phandle); ++ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", ++ "loongson,pch-pic-1.0"); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, ++ pch_pic_base, 0, pch_pic_size); ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", ++ *eiointc_phandle); ++ qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0); ++ g_free(nodename); ++} ++ + static void fdt_add_flash_node(LoongArchMachineState *lams) + { + MachineState *ms = MACHINE(lams); +@@ -599,7 +624,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + CPULoongArchState *env; + CPUState *cpu_state; + int cpu, pin, i, start, num; +- uint32_t cpuintc_phandle, eiointc_phandle; ++ uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle; + + /* + * The connection of interrupts: +@@ -699,6 +724,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); + } + ++ /* Add PCH PIC node */ ++ fdt_add_pch_pic_node(lams, &eiointc_phandle, &pch_pic_phandle); ++ + pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); + start = num; + num = EXTIOI_IRQS - start; +diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h +index e753449593..fe260f0183 100644 +--- a/include/hw/pci-host/ls7a.h ++++ b/include/hw/pci-host/ls7a.h +@@ -24,6 +24,7 @@ + #define VIRT_PCH_REG_BASE 0x10000000UL + #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE) + #define VIRT_PCH_MSI_ADDR_LOW 0x2FF00000UL ++#define VIRT_PCH_REG_SIZE 0x400 + + /* + * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot +-- +2.39.1 + diff --git a/hw-loongarch-fdt-adds-pcie-irq_map-node.patch b/hw-loongarch-fdt-adds-pcie-irq_map-node.patch new file mode 100644 index 0000000000000000000000000000000000000000..459138ed2fd0544d0c4d4622a065c349f355b637 --- /dev/null +++ b/hw-loongarch-fdt-adds-pcie-irq_map-node.patch @@ -0,0 +1,137 @@ +From 1325effbd595781b9ab75dceab9f87944156c606 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:48 +0800 +Subject: [PATCH 13/78] hw/loongarch: fdt adds pcie irq_map node + +This patch adds pcie irq_map node for FDT. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-15-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 73 ++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 69 insertions(+), 4 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 032106ebad..c32cc3c818 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -379,7 +379,62 @@ static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams) + g_free(nodename); + } + +-static void fdt_add_pcie_node(const LoongArchMachineState *lams) ++static void fdt_add_pcie_irq_map_node(const LoongArchMachineState *lams, ++ char *nodename, ++ uint32_t *pch_pic_phandle) ++{ ++ int pin, dev; ++ uint32_t irq_map_stride = 0; ++ uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {}; ++ uint32_t *irq_map = full_irq_map; ++ const MachineState *ms = MACHINE(lams); ++ ++ /* This code creates a standard swizzle of interrupts such that ++ * each device's first interrupt is based on it's PCI_SLOT number. ++ * (See pci_swizzle_map_irq_fn()) ++ * ++ * We only need one entry per interrupt in the table (not one per ++ * possible slot) seeing the interrupt-map-mask will allow the table ++ * to wrap to any number of devices. ++ */ ++ ++ for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { ++ int devfn = dev * 0x8; ++ ++ for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { ++ int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); ++ int i = 0; ++ ++ /* Fill PCI address cells */ ++ irq_map[i] = cpu_to_be32(devfn << 8); ++ i += 3; ++ ++ /* Fill PCI Interrupt cells */ ++ irq_map[i] = cpu_to_be32(pin + 1); ++ i += 1; ++ ++ /* Fill interrupt controller phandle and cells */ ++ irq_map[i++] = cpu_to_be32(*pch_pic_phandle); ++ irq_map[i++] = cpu_to_be32(irq_nr); ++ ++ if (!irq_map_stride) { ++ irq_map_stride = i; ++ } ++ irq_map += irq_map_stride; ++ } ++ } ++ ++ ++ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map, ++ GPEX_NUM_IRQS * GPEX_NUM_IRQS * ++ irq_map_stride * sizeof(uint32_t)); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask", ++ 0x1800, 0, 0, 0x7); ++} ++ ++static void fdt_add_pcie_node(const LoongArchMachineState *lams, ++ uint32_t *pch_pic_phandle, ++ uint32_t *pch_msi_phandle) + { + char *nodename; + hwaddr base_mmio = VIRT_PCI_MEM_BASE; +@@ -410,6 +465,11 @@ static void fdt_add_pcie_node(const LoongArchMachineState *lams) + 2, base_pio, 2, size_pio, + 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, + 2, base_mmio, 2, size_mmio); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map", ++ 0, *pch_msi_phandle, 0, 0x10000); ++ ++ fdt_add_pcie_irq_map_node(lams, nodename, pch_pic_phandle); ++ + g_free(nodename); + } + +@@ -569,7 +629,10 @@ static DeviceState *create_platform_bus(DeviceState *pch_pic) + return dev; + } + +-static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState *lams) ++static void loongarch_devices_init(DeviceState *pch_pic, ++ LoongArchMachineState *lams, ++ uint32_t *pch_pic_phandle, ++ uint32_t *pch_msi_phandle) + { + MachineClass *mc = MACHINE_GET_CLASS(lams); + DeviceState *gpex_dev; +@@ -615,6 +678,9 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * + gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i); + } + ++ /* Add pcie node */ ++ fdt_add_pcie_node(lams, pch_pic_phandle, pch_msi_phandle); ++ + serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0, + qdev_get_gpio_in(pch_pic, + VIRT_UART_IRQ - VIRT_GSI_BASE), +@@ -772,7 +838,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) + /* Add PCH MSI node */ + fdt_add_pch_msi_node(lams, &eiointc_phandle, &pch_msi_phandle); + +- loongarch_devices_init(pch_pic, lams); ++ loongarch_devices_init(pch_pic, lams, &pch_pic_phandle, &pch_msi_phandle); + } + + static void loongarch_firmware_init(LoongArchMachineState *lams) +@@ -1048,7 +1114,6 @@ static void loongarch_init(MachineState *machine) + lams->powerdown_notifier.notify = virt_powerdown_req; + qemu_register_powerdown_notifier(&lams->powerdown_notifier); + +- fdt_add_pcie_node(lams); + /* + * Since lowmem region starts from 0 and Linux kernel legacy start address + * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer +-- +2.39.1 + diff --git a/hw-loongarch-fdt-remove-unused-irqchip-node.patch b/hw-loongarch-fdt-remove-unused-irqchip-node.patch new file mode 100644 index 0000000000000000000000000000000000000000..75c7217971b92cc7b22b82097c98218fc4c0927d --- /dev/null +++ b/hw-loongarch-fdt-remove-unused-irqchip-node.patch @@ -0,0 +1,67 @@ +From e87697c72641ab2209d4004f573f47283d118235 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:49 +0800 +Subject: [PATCH 14/78] hw/loongarch: fdt remove unused irqchip node + +This patch removes the unused fdt irqchip node. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240426091551.2397867-16-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 31 +------------------------------ + 1 file changed, 1 insertion(+), 30 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index c32cc3c818..ff9513034b 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -473,34 +473,6 @@ static void fdt_add_pcie_node(const LoongArchMachineState *lams, + g_free(nodename); + } + +-static void fdt_add_irqchip_node(LoongArchMachineState *lams) +-{ +- MachineState *ms = MACHINE(lams); +- char *nodename; +- uint32_t irqchip_phandle; +- +- irqchip_phandle = qemu_fdt_alloc_phandle(ms->fdt); +- qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", irqchip_phandle); +- +- nodename = g_strdup_printf("/intc@%lx", VIRT_IOAPIC_REG_BASE); +- qemu_fdt_add_subnode(ms->fdt, nodename); +- qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3); +- qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); +- qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2); +- qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2); +- qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0); +- +- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", +- "loongarch,ls7a"); +- +- qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", +- 2, VIRT_IOAPIC_REG_BASE, +- 2, PCH_PIC_ROUTE_ENTRY_OFFSET); +- +- qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", irqchip_phandle); +- g_free(nodename); +-} +- + static void fdt_add_memory_node(MachineState *ms, + uint64_t base, uint64_t size, int node_id) + { +@@ -1103,8 +1075,7 @@ static void loongarch_init(MachineState *machine) + + /* Initialize the IO interrupt subsystem */ + loongarch_irq_init(lams); +- fdt_add_irqchip_node(lams); +- platform_bus_add_all_fdt_nodes(machine->fdt, "/intc", ++ platform_bus_add_all_fdt_nodes(machine->fdt, "/platic", + VIRT_PLATFORM_BUS_BASEADDRESS, + VIRT_PLATFORM_BUS_SIZE, + VIRT_PLATFORM_BUS_IRQ); +-- +2.39.1 + diff --git a/hw-loongarch-fix-cpu-hotplug-reset.patch b/hw-loongarch-fix-cpu-hotplug-reset.patch new file mode 100644 index 0000000000000000000000000000000000000000..d86cc0577b38fde20bfdc9a6301a0d70a7fd902a --- /dev/null +++ b/hw-loongarch-fix-cpu-hotplug-reset.patch @@ -0,0 +1,51 @@ +From f3f7b49a8a323ebfe2be176985336aaf2c97c6c2 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Mon, 9 Sep 2024 04:14:49 +0800 +Subject: [PATCH 78/78] hw/loongarch: fix cpu hotplug reset + +Signed-off-by: gaosong +Signed-off-by: Xianglai Li +--- + hw/loongarch/boot.c | 2 +- + hw/loongarch/virt.c | 1 + + include/hw/loongarch/virt.h | 1 + + 3 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index f258eefe9a..53dcefbb55 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -216,7 +216,7 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) + return kernel_entry; + } + +-static void reset_load_elf(void *opaque) ++void reset_load_elf(void *opaque) + { + LoongArchCPU *cpu = opaque; + CPULoongArchState *env = &cpu->env; +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 5b0468f6cb..0c24e632bb 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -1494,6 +1494,7 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, + env = &(cpu->env); + env->address_space_iocsr = &lvms->as_iocsr; + ++ qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(cs->cpu_index))); + env->ipistate = lvms->ipi; + if (!(kvm_enabled() && kvm_irqchip_in_kernel())) { + /* connect ipi irq to cpu irq, logic cpu index used here */ +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 168b40c31b..a79ad41663 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -86,4 +86,5 @@ struct LoongArchVirtMachineState { + #define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt") + OBJECT_DECLARE_SIMPLE_TYPE(LoongArchVirtMachineState, LOONGARCH_VIRT_MACHINE) + void loongarch_acpi_setup(LoongArchVirtMachineState *lvms); ++void reset_load_elf(void *opaque); + #endif +-- +2.39.1 + diff --git a/hw-loongarch-move-memory-map-to-boot.c.patch b/hw-loongarch-move-memory-map-to-boot.c.patch new file mode 100644 index 0000000000000000000000000000000000000000..ac4f660d88891f631c4f82fe3bac59a7f9092517 --- /dev/null +++ b/hw-loongarch-move-memory-map-to-boot.c.patch @@ -0,0 +1,113 @@ +From 5e4d612de23539499b9a22986bebe9a3007edae1 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Tue, 7 May 2024 16:51:35 +0200 +Subject: [PATCH 18/78] hw/loongarch: move memory map to boot.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Ensure that it can be used even if virt.c is not included in the build, as +is the case for --without-default-devices. + +Signed-off-by: Paolo Bonzini +Acked-by: Richard Henderson +Message-ID: <20240507145135.270803-1-pbonzini@redhat.com> +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Xianglai Li +--- + .gitlab-ci.d/buildtest.yml | 5 +++-- + hw/loongarch/boot.c | 3 +++ + hw/loongarch/virt.c | 3 --- + include/hw/loongarch/boot.h | 10 ++++++++++ + include/hw/loongarch/virt.h | 10 ---------- + 5 files changed, 16 insertions(+), 15 deletions(-) + +diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml +index 3fb99e79e9..983c3c132e 100644 +--- a/.gitlab-ci.d/buildtest.yml ++++ b/.gitlab-ci.d/buildtest.yml +@@ -579,8 +579,9 @@ build-tci: + - make check-tcg + + # Check our reduced build configurations +-# requires libfdt: aarch64, arm, i386, loongarch64, x86_64 +-# does not build without boards: i386, loongarch64, x86_64 ++# requires libfdt: aarch64, arm, i386, loongarch64, microblaze, microblazeel, ++# mips64el, or1k, ppc, ppc64, riscv32, riscv64, rx, x86_64 ++# does not build without boards: i386, s390x, sh4, sh4eb, x86_64 + build-without-defaults: + extends: .native_build_job_template + needs: +diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c +index 7d1630b2e7..03f6301a77 100644 +--- a/hw/loongarch/boot.c ++++ b/hw/loongarch/boot.c +@@ -15,6 +15,9 @@ + #include "sysemu/reset.h" + #include "sysemu/qtest.h" + ++struct memmap_entry *memmap_table; ++unsigned memmap_entries; ++ + ram_addr_t initrd_offset; + uint64_t initrd_size; + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 0972ebd150..76b36539e2 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -543,9 +543,6 @@ static void virt_powerdown_req(Notifier *notifier, void *opaque) + acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS); + } + +-struct memmap_entry *memmap_table; +-unsigned memmap_entries; +- + static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type) + { + /* Ensure there are no duplicate entries. */ +diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h +index 4ebcc89dcf..b3b870df1f 100644 +--- a/include/hw/loongarch/boot.h ++++ b/include/hw/loongarch/boot.h +@@ -104,6 +104,16 @@ struct loongarch_boot_info { + uint64_t a0, a1, a2; + }; + ++extern struct memmap_entry *memmap_table; ++extern unsigned memmap_entries; ++ ++struct memmap_entry { ++ uint64_t address; ++ uint64_t length; ++ uint32_t type; ++ uint32_t reserved; ++}; ++ + void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info); + + #endif /* HW_LOONGARCH_BOOT_H */ +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 673b57aa2b..36158c758f 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -37,16 +37,6 @@ + + #define FDT_BASE 0x100000 + +-extern struct memmap_entry *memmap_table; +-extern unsigned memmap_entries; +- +-struct memmap_entry { +- uint64_t address; +- uint64_t length; +- uint32_t type; +- uint32_t reserved; +-}; +- + struct LoongArchMachineState { + /*< private >*/ + MachineState parent_obj; +-- +2.39.1 + diff --git a/hw-loongarch-virt-Add-CPU-topology-support.patch b/hw-loongarch-virt-Add-CPU-topology-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..acdcf11d7443c21fc75ad54cf918ef1b1bd89e5c --- /dev/null +++ b/hw-loongarch-virt-Add-CPU-topology-support.patch @@ -0,0 +1,278 @@ +From 8d440efd992fd6be0aca55118a9b60c224f6eade Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 23 Oct 2024 15:13:10 +0800 +Subject: [PATCH 69/78] hw/loongarch/virt: Add CPU topology support + +Add topological relationships for Loongarch VCPU and initialize +topology member variables. Also physical cpu id calculation +method comes from its topo information. + +Co-developed-by: Xianglai Li +Signed-off-by: Bibo Mao +Message-ID: <20241023071312.881866-2-maobibo@loongson.cn> +Signed-off-by: Xianglai Li +--- + docs/system/loongarch/virt.rst | 31 +++++++++++++ + hw/loongarch/virt.c | 82 ++++++++++++++++++++++++++++------ + target/loongarch/cpu.c | 12 +++++ + target/loongarch/cpu.h | 11 +++++ + 4 files changed, 122 insertions(+), 14 deletions(-) + +diff --git a/docs/system/loongarch/virt.rst b/docs/system/loongarch/virt.rst +index c37268b404..aa4719d4bd 100644 +--- a/docs/system/loongarch/virt.rst ++++ b/docs/system/loongarch/virt.rst +@@ -28,6 +28,37 @@ The ``qemu-system-loongarch64`` provides emulation for virt + machine. You can specify the machine type ``virt`` and + cpu type ``la464``. + ++CPU Topology ++------------ ++ ++The ``LA464`` type CPUs have the concept of Socket Core and Thread. ++ ++For example: ++ ++``-smp 1,maxcpus=M,sockets=S,cores=C,threads=T`` ++ ++The above parameters indicate that the machine has a maximum of ``M`` vCPUs and ++``S`` sockets, each socket has ``C`` cores, each core has ``T`` threads, ++and each thread corresponds to a vCPU. ++ ++Then ``M`` ``S`` ``C`` ``T`` has the following relationship: ++ ++``M = S * C * T`` ++ ++In the CPU topology relationship, When we know the ``socket_id`` ``core_id`` ++and ``thread_id`` of the CPU, we can calculate its ``arch_id``: ++ ++``arch_id = (socket_id * S) + (core_id * C) + (thread_id * T)`` ++ ++Similarly, when we know the ``arch_id`` of the CPU, ++we can also get its ``socket_id`` ``core_id`` and ``thread_id``: ++ ++``socket_id = arch_id / (C * T)`` ++ ++``core_id = (arch_id / T) % C`` ++ ++``thread_id = arch_id % T`` ++ + Boot options + ------------ + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 9510aa7a7e..8d1e53ff62 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -1123,9 +1123,7 @@ static void virt_init(MachineState *machine) + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + int i; + hwaddr base, size, ram_size = machine->ram_size; +- const CPUArchIdList *possible_cpus; + MachineClass *mc = MACHINE_GET_CLASS(machine); +- CPUState *cpu; + + if (!cpu_model) { + cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); +@@ -1143,14 +1141,39 @@ static void virt_init(MachineState *machine) + memory_region_add_subregion(&lvms->system_iocsr, 0, &lvms->iocsr_mem); + + /* Init CPUs */ +- possible_cpus = mc->possible_cpu_arch_ids(machine); +- for (i = 0; i < possible_cpus->len; i++) { +- cpu = cpu_create(machine->cpu_type); +- cpu->cpu_index = i; +- machine->possible_cpus->cpus[i].cpu = OBJECT(cpu); +- lacpu = LOONGARCH_CPU(cpu); ++ mc->possible_cpu_arch_ids(machine); ++ for (i = 0; i < machine->smp.cpus; i++) { ++ Object *cpuobj; ++ cpuobj = object_new(machine->cpu_type); ++ lacpu = LOONGARCH_CPU(cpuobj); ++ + lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id; ++ object_property_set_int(cpuobj, "socket-id", ++ machine->possible_cpus->cpus[i].props.socket_id, ++ NULL); ++ object_property_set_int(cpuobj, "core-id", ++ machine->possible_cpus->cpus[i].props.core_id, ++ NULL); ++ object_property_set_int(cpuobj, "thread-id", ++ machine->possible_cpus->cpus[i].props.thread_id, ++ NULL); ++ /* ++ * The CPU in place at the time of machine startup will also enter ++ * the CPU hot-plug process when it is created, but at this time, ++ * the GED device has not been created, resulting in exit in the CPU ++ * hot-plug process, which can avoid the incumbent CPU repeatedly ++ * applying for resources. ++ * ++ * The interrupt resource of the in-place CPU will be requested at ++ * the current function call loongarch_irq_init(). ++ * ++ * The interrupt resource of the subsequently inserted CPU will be ++ * requested in the CPU hot-plug process. ++ */ ++ qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); ++ object_unref(cpuobj); + } ++ + fdt_add_cpu_nodes(lvms); + fdt_add_memory_nodes(machine); + fw_cfg_add_memory(machine); +@@ -1266,6 +1289,27 @@ static void virt_initfn(Object *obj) + virt_flash_create(lvms); + } + ++static int virt_get_arch_id_from_topo(MachineState *ms, LoongArchCPUTopo *topo) ++{ ++ int arch_id, sock_vcpu_num, core_vcpu_num; ++ ++ /* ++ * calculate total logical cpus across socket/core/thread. ++ * For more information on how to calculate the arch_id, ++ * you can refer to the CPU Topology chapter of the ++ * docs/system/loongarch/virt.rst document. ++ */ ++ sock_vcpu_num = topo->socket_id * (ms->smp.threads * ms->smp.cores); ++ core_vcpu_num = topo->core_id * ms->smp.threads; ++ ++ /* get vcpu-id(logical cpu index) for this vcpu from this topology */ ++ arch_id = (sock_vcpu_num + core_vcpu_num) + topo->thread_id; ++ ++ assert(arch_id >= 0 && arch_id < ms->possible_cpus->len); ++ ++ return arch_id; ++} ++ + static bool memhp_type_supported(DeviceState *dev) + { + /* we only support pc dimm now */ +@@ -1363,10 +1407,19 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine, + return NULL; + } + ++static void virt_get_cpu_topo_from_index(MachineState *ms, ++ LoongArchCPUTopo *topo, int index) ++{ ++ topo->socket_id = index / (ms->smp.cores * ms->smp.threads); ++ topo->core_id = index / ms->smp.threads % ms->smp.cores; ++ topo->thread_id = index % ms->smp.threads; ++} ++ + static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + { + int n; + unsigned int max_cpus = ms->smp.max_cpus; ++ LoongArchCPUTopo topo; + + if (ms->possible_cpus) { + assert(ms->possible_cpus->len == max_cpus); +@@ -1377,17 +1430,18 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + sizeof(CPUArchId) * max_cpus); + ms->possible_cpus->len = max_cpus; + for (n = 0; n < ms->possible_cpus->len; n++) { ++ ms->possible_cpus->cpus[n].vcpus_count = ms->smp.threads; + ms->possible_cpus->cpus[n].type = ms->cpu_type; +- ms->possible_cpus->cpus[n].arch_id = n; ++ virt_get_cpu_topo_from_index(ms, &topo, n); + + ms->possible_cpus->cpus[n].props.has_socket_id = true; +- ms->possible_cpus->cpus[n].props.socket_id = +- n / (ms->smp.cores * ms->smp.threads); ++ ms->possible_cpus->cpus[n].props.socket_id = topo.socket_id; + ms->possible_cpus->cpus[n].props.has_core_id = true; +- ms->possible_cpus->cpus[n].props.core_id = +- n / ms->smp.threads % ms->smp.cores; ++ ms->possible_cpus->cpus[n].props.core_id = topo.core_id; + ms->possible_cpus->cpus[n].props.has_thread_id = true; +- ms->possible_cpus->cpus[n].props.thread_id = n % ms->smp.threads; ++ ms->possible_cpus->cpus[n].props.thread_id = topo.thread_id; ++ ms->possible_cpus->cpus[n].arch_id = ++ virt_get_arch_id_from_topo(ms, &topo); + } + return ms->possible_cpus; + } +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 2ee1d63989..673ed8ea18 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -17,6 +17,7 @@ + #include "kvm/kvm_loongarch.h" + #include "exec/exec-all.h" + #include "cpu.h" ++#include "hw/qdev-properties.h" + #include "internals.h" + #include "fpu/softfloat-helpers.h" + #include "cpu-csr.h" +@@ -860,6 +861,15 @@ static int64_t loongarch_cpu_get_arch_id(CPUState *cs) + } + #endif + ++static Property loongarch_cpu_properties[] = { ++ DEFINE_PROP_INT32("socket-id", LoongArchCPU, socket_id, 0), ++ DEFINE_PROP_INT32("core-id", LoongArchCPU, core_id, 0), ++ DEFINE_PROP_INT32("thread-id", LoongArchCPU, thread_id, 0), ++ DEFINE_PROP_INT32("node-id", LoongArchCPU, node_id, CPU_UNSET_NUMA_NODE_ID), ++ ++ DEFINE_PROP_END_OF_LIST() ++}; ++ + static void loongarch_cpu_class_init(ObjectClass *c, void *data) + { + LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c); +@@ -867,6 +877,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) + DeviceClass *dc = DEVICE_CLASS(c); + ResettableClass *rc = RESETTABLE_CLASS(c); + ++ device_class_set_props(dc, loongarch_cpu_properties); + device_class_set_parent_realize(dc, loongarch_cpu_realizefn, + &lacc->parent_realize); + resettable_class_set_parent_phases(rc, NULL, loongarch_cpu_reset_hold, NULL, +@@ -890,6 +901,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) + #ifdef CONFIG_TCG + cc->tcg_ops = &loongarch_tcg_ops; + #endif ++ dc->user_creatable = true; + } + + static const gchar *loongarch32_gdb_arch_name(CPUState *cs) +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 4c90cf9ef3..9af622aba5 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -398,6 +398,12 @@ typedef struct CPUArchState { + } st; + } CPULoongArchState; + ++typedef struct LoongArchCPUTopo { ++ int32_t socket_id; /* socket-id of this VCPU */ ++ int32_t core_id; /* core-id of this VCPU */ ++ int32_t thread_id; /* thread-id of this VCPU */ ++} LoongArchCPUTopo; ++ + /** + * LoongArchCPU: + * @env: #CPULoongArchState +@@ -412,6 +418,10 @@ struct ArchCPU { + uint32_t phy_id; + OnOffAuto lbt; + OnOffAuto pmu; ++ int32_t socket_id; /* socket-id of this VCPU */ ++ int32_t core_id; /* core-id of this VCPU */ ++ int32_t thread_id; /* thread-id of this VCPU */ ++ int32_t node_id; /* NUMA node this CPU belongs to */ + + /* 'compatible' string for this CPU for Linux device trees */ + const char *dtb_compatible; +@@ -430,6 +440,7 @@ struct LoongArchCPUClass { + CPUClass parent_class; + + DeviceRealize parent_realize; ++ DeviceUnrealize parent_unrealize; + ResettablePhases parent_phases; + }; + +-- +2.39.1 + diff --git a/hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch b/hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch new file mode 100644 index 0000000000000000000000000000000000000000..a2f0b2b19d2f352725ca87390c9ee1d38f8d4da6 --- /dev/null +++ b/hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch @@ -0,0 +1,84 @@ +From fa276847efb3fd47a730d279f1b14705fe3991b1 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 18 Sep 2024 09:42:06 +0800 +Subject: [PATCH 39/78] hw/loongarch/virt: Add FDT table support with acpi ged + pm register + +ACPI ged is used for power management on LoongArch virt platform, in +general it is parsed from acpi table. However if system boot directly from +elf kernel, no UEFI bios is provided and acpi table cannot be used also. + +Here acpi ged pm register is exposed with FDT table, it is compatbile +with syscon method in FDT table, only that acpi ged pm register is accessed +with 8-bit mode, rather with 32-bit mode. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Tested-by: Song Gao +Message-Id: <20240918014206.2165821-3-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 39 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 9f47107379..9510aa7a7e 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -281,6 +281,44 @@ static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms, + g_free(nodename); + } + ++static void fdt_add_ged_reset(LoongArchVirtMachineState *lvms) ++{ ++ char *name; ++ uint32_t ged_handle; ++ MachineState *ms = MACHINE(lvms); ++ hwaddr base = VIRT_GED_REG_ADDR; ++ hwaddr size = ACPI_GED_REG_COUNT; ++ ++ ged_handle = qemu_fdt_alloc_phandle(ms->fdt); ++ name = g_strdup_printf("/ged@%" PRIx64, base); ++ qemu_fdt_add_subnode(ms->fdt, name); ++ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon"); ++ qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, base, 0x0, size); ++ /* 8 bit registers */ ++ qemu_fdt_setprop_cell(ms->fdt, name, "reg-shift", 0); ++ qemu_fdt_setprop_cell(ms->fdt, name, "reg-io-width", 1); ++ qemu_fdt_setprop_cell(ms->fdt, name, "phandle", ged_handle); ++ ged_handle = qemu_fdt_get_phandle(ms->fdt, name); ++ g_free(name); ++ ++ name = g_strdup_printf("/reboot"); ++ qemu_fdt_add_subnode(ms->fdt, name); ++ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot"); ++ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle); ++ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_RESET); ++ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_RESET_VALUE); ++ g_free(name); ++ ++ name = g_strdup_printf("/poweroff"); ++ qemu_fdt_add_subnode(ms->fdt, name); ++ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff"); ++ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle); ++ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_SLEEP_CTL); ++ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_SLP_EN | ++ (ACPI_GED_SLP_TYP_S5 << ACPI_GED_SLP_TYP_POS)); ++ g_free(name); ++} ++ + static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, + uint32_t *pch_pic_phandle, hwaddr base, + int irq, bool chosen) +@@ -739,6 +777,7 @@ static void virt_devices_init(DeviceState *pch_pic, + qdev_get_gpio_in(pch_pic, + VIRT_RTC_IRQ - VIRT_GSI_BASE)); + fdt_add_rtc_node(lvms, pch_pic_phandle); ++ fdt_add_ged_reset(lvms); + + /* acpi ged */ + lvms->acpi_ged = create_acpi_ged(pch_pic, lvms); +-- +2.39.1 + diff --git a/hw-loongarch-virt-Add-basic-CPU-plug-support.patch b/hw-loongarch-virt-Add-basic-CPU-plug-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..76015bfd9b05841afef58648f6f297acf573a77b --- /dev/null +++ b/hw-loongarch-virt-Add-basic-CPU-plug-support.patch @@ -0,0 +1,346 @@ +From 212ea93178ad1e65e625ec6942ee9aff93dd5321 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 23 Oct 2024 15:13:11 +0800 +Subject: [PATCH 70/78] hw/loongarch/virt: Add basic CPU plug support + +Implement interface for cpu hotplug function, and enable cpu hotplug +feature on virt machine. + +Co-developed-by: Xianglai Li +Signed-off-by: Bibo Mao +Message-ID: <20241023071312.881866-3-maobibo@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/Kconfig | 1 + + hw/loongarch/virt.c | 193 +++++++++++++++++++++++++++++++++++- + include/hw/loongarch/virt.h | 1 + + target/loongarch/cpu.c | 13 +++ + 4 files changed, 206 insertions(+), 2 deletions(-) + +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index 40944a8365..b42a8573d4 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -16,6 +16,7 @@ config LOONGARCH_VIRT + select LOONGARCH_EXTIOI + select LS7A_RTC + select SMBIOS ++ select ACPI_CPU_HOTPLUG + select ACPI_PCI + select ACPI_HW_REDUCED + select FW_CFG_DMA +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 8d1e53ff62..e7734ed3c0 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -821,7 +821,7 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + + /* Create IPI device */ + ipi = qdev_new(TYPE_LOONGARCH_IPI); +- qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.cpus); ++ qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); + + /* IPI iocsr memory region */ +@@ -845,9 +845,11 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + env->ipistate = ipi; + } + ++ lvms->ipi = ipi; ++ + /* Create EXTIOI device */ + extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); +- qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus); ++ qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.max_cpus); + if (virt_is_veiointc_enabled(lvms)) { + qdev_prop_set_bit(extioi, "has-virtualization-extension", true); + } +@@ -873,6 +875,8 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) + } + } + ++ lvms->extioi = extioi; ++ + /* Add Extend I/O Interrupt Controller node */ + fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle); + +@@ -1310,6 +1314,181 @@ static int virt_get_arch_id_from_topo(MachineState *ms, LoongArchCPUTopo *topo) + return arch_id; + } + ++/* find cpu slot in machine->possible_cpus by arch_id */ ++static CPUArchId *virt_find_cpu_slot(MachineState *ms, int arch_id, int *index) ++{ ++ int n; ++ for (n = 0; n < ms->possible_cpus->len; n++) { ++ if (ms->possible_cpus->cpus[n].arch_id == arch_id) { ++ if (index) { ++ *index = n; ++ } ++ return &ms->possible_cpus->cpus[n]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ MachineState *ms = MACHINE(OBJECT(hotplug_dev)); ++ MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); ++ LoongArchCPU *cpu = LOONGARCH_CPU(dev); ++ CPUState *cs = CPU(dev); ++ CPUArchId *cpu_slot; ++ Error *local_err = NULL; ++ LoongArchCPUTopo topo; ++ int arch_id, index; ++ ++ if (dev->hotplugged && !mc->has_hotpluggable_cpus) { ++ error_setg(&local_err, "CPU hotplug not supported for this machine"); ++ goto out; ++ } ++ ++ /* sanity check the cpu */ ++ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { ++ error_setg(&local_err, "Invalid CPU type, expected cpu type: '%s'", ++ ms->cpu_type); ++ goto out; ++ } ++ ++ if ((cpu->thread_id < 0) || (cpu->thread_id >= ms->smp.threads)) { ++ error_setg(&local_err, ++ "Invalid thread-id %u specified, must be in range 1:%u", ++ cpu->thread_id, ms->smp.threads - 1); ++ goto out; ++ } ++ ++ if ((cpu->core_id < 0) || (cpu->core_id >= ms->smp.cores)) { ++ error_setg(&local_err, ++ "Invalid core-id %u specified, must be in range 1:%u", ++ cpu->core_id, ms->smp.cores - 1); ++ goto out; ++ } ++ ++ if ((cpu->socket_id < 0) || (cpu->socket_id >= ms->smp.sockets)) { ++ error_setg(&local_err, ++ "Invalid socket-id %u specified, must be in range 1:%u", ++ cpu->socket_id, ms->smp.sockets - 1); ++ goto out; ++ } ++ ++ topo.socket_id = cpu->socket_id; ++ topo.core_id = cpu->core_id; ++ topo.thread_id = cpu->thread_id; ++ arch_id = virt_get_arch_id_from_topo(ms, &topo); ++ cpu_slot = virt_find_cpu_slot(ms, arch_id, &index); ++ if (CPU(cpu_slot->cpu)) { ++ error_setg(&local_err, ++ "cpu(id%d=%d:%d:%d) with arch-id %" PRIu64 " exists", ++ cs->cpu_index, cpu->socket_id, cpu->core_id, ++ cpu->thread_id, cpu_slot->arch_id); ++ goto out; ++ } ++ cpu->phy_id = arch_id; ++ /* ++ * update cpu_index calculation method since it is easily used as index ++ * with possible_cpus array by function virt_cpu_index_to_props ++ */ ++ cs->cpu_index = index; ++ numa_cpu_pre_plug(cpu_slot, dev, &local_err); ++ return ; ++ ++out: ++ error_propagate(errp, local_err); ++} ++ ++static void virt_cpu_unplug_request(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ Error *local_err = NULL; ++ HotplugHandlerClass *hhc; ++ LoongArchCPU *cpu = LOONGARCH_CPU(dev); ++ CPUState *cs = CPU(dev); ++ ++ if (!lvms->acpi_ged) { ++ error_setg(&local_err, "CPU hot unplug not supported without ACPI"); ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ if (cs->cpu_index == 0) { ++ error_setg(&local_err, ++ "hot-unplug of boot cpu(id%d=%d:%d:%d) not supported", ++ cs->cpu_index, cpu->socket_id, ++ cpu->core_id, cpu->thread_id); ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lvms->acpi_ged); ++ hhc->unplug_request(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &local_err); ++} ++ ++static void virt_cpu_unplug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ CPUArchId *cpu_slot; ++ HotplugHandlerClass *hhc; ++ Error *local_err = NULL; ++ LoongArchCPU *cpu = LOONGARCH_CPU(dev); ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lvms->acpi_ged); ++ hhc->unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id, NULL); ++ cpu_slot->cpu = NULL; ++ return; ++} ++ ++static void virt_cpu_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ CPUArchId *cpu_slot; ++ HotplugHandlerClass *hhc; ++ Error *local_err = NULL; ++ LoongArchCPU *cpu = LOONGARCH_CPU(dev); ++ CPUState *cs = CPU(cpu); ++ CPULoongArchState *env; ++ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); ++ int pin; ++ ++ if (lvms->acpi_ged) { ++ env = &(cpu->env); ++ env->address_space_iocsr = &lvms->as_iocsr; ++ ++ env->ipistate = lvms->ipi; ++ if (!(kvm_enabled() && kvm_irqchip_in_kernel())) { ++ /* connect ipi irq to cpu irq, logic cpu index used here */ ++ qdev_connect_gpio_out(lvms->ipi, cs->cpu_index, ++ qdev_get_gpio_in(dev, IRQ_IPI)); ++ ++ for (pin = 0; pin < LS3A_INTC_IP; pin++) { ++ qdev_connect_gpio_out(lvms->extioi, (cs->cpu_index * 8 + pin), ++ qdev_get_gpio_in(dev, pin + 2)); ++ } ++ } ++ hhc = HOTPLUG_HANDLER_GET_CLASS(lvms->acpi_ged); ++ hhc->plug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ } ++ ++ cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id, NULL); ++ cpu_slot->cpu = OBJECT(dev); ++ return; ++} ++ + static bool memhp_type_supported(DeviceState *dev) + { + /* we only support pc dimm now */ +@@ -1328,6 +1507,8 @@ static void virt_device_pre_plug(HotplugHandler *hotplug_dev, + { + if (memhp_type_supported(dev)) { + virt_mem_pre_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ virt_cpu_pre_plug(hotplug_dev, dev, errp); + } + } + +@@ -1346,6 +1527,8 @@ static void virt_device_unplug_request(HotplugHandler *hotplug_dev, + { + if (memhp_type_supported(dev)) { + virt_mem_unplug_request(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ virt_cpu_unplug_request(hotplug_dev, dev, errp); + } + } + +@@ -1364,6 +1547,8 @@ static void virt_device_unplug(HotplugHandler *hotplug_dev, + { + if (memhp_type_supported(dev)) { + virt_mem_unplug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ virt_cpu_unplug(hotplug_dev, dev, errp); + } + } + +@@ -1391,6 +1576,8 @@ static void virt_device_plug_cb(HotplugHandler *hotplug_dev, + } + } else if (memhp_type_supported(dev)) { + virt_mem_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) { ++ virt_cpu_plug(hotplug_dev, dev, errp); + } + } + +@@ -1400,6 +1587,7 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine, + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (device_is_dynamic_sysbus(mc, dev) || ++ object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU) || + object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) || + memhp_type_supported(dev)) { + return HOTPLUG_HANDLER(machine); +@@ -1489,6 +1677,7 @@ static void virt_class_init(ObjectClass *oc, void *data) + mc->numa_mem_supported = true; + mc->auto_enable_numa_with_memhp = true; + mc->auto_enable_numa_with_memdev = true; ++ mc->has_hotpluggable_cpus = true; + mc->get_hotplug_handler = virt_get_hotplug_handler; + mc->default_nic = "virtio-net-pci"; + hc->plug = virt_device_plug_cb; +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 0a4d9a25f0..27c52af9f3 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -64,6 +64,7 @@ struct LoongArchVirtMachineState { + AddressSpace as_iocsr; + int features; + struct loongarch_boot_info bootinfo; ++ DeviceState *ipi; + }; + + #define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 673ed8ea18..ee764f0bc7 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -644,6 +644,17 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) + lacc->parent_realize(dev, errp); + } + ++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 bool loongarch_get_lsx(Object *obj, Error **errp) + { + LoongArchCPU *cpu = LOONGARCH_CPU(obj); +@@ -880,6 +891,8 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) + device_class_set_props(dc, loongarch_cpu_properties); + device_class_set_parent_realize(dc, loongarch_cpu_realizefn, + &lacc->parent_realize); ++ device_class_set_parent_unrealize(dc, loongarch_cpu_unrealizefn, ++ &lacc->parent_unrealize); + resettable_class_set_parent_phases(rc, NULL, loongarch_cpu_reset_hold, NULL, + &lacc->parent_phases); + +-- +2.39.1 + diff --git a/hw-loongarch-virt-Add-description-for-virt-machine-t.patch b/hw-loongarch-virt-Add-description-for-virt-machine-t.patch new file mode 100644 index 0000000000000000000000000000000000000000..37d210c7cf8eb7e665ea468122747737f5351f71 --- /dev/null +++ b/hw-loongarch-virt-Add-description-for-virt-machine-t.patch @@ -0,0 +1,46 @@ +From 080ca7865257d70b6be671cbc17a97c5ebffbd68 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Fri, 13 Sep 2024 17:52:02 +0800 +Subject: [PATCH 38/78] hw/loongarch/virt: Add description for virt machine + type + +The description about virt machine type is removed by mistake, add +new description here. Here is output result with command +"./qemu-system-loongarch64 -M help" + +Supported machines are: +none empty machine +virt QEMU LoongArch Virtual Machine (default) +x-remote Experimental remote machine + +Without the patch, it shows as follows: +Supported machines are: +none empty machine +virt (null) (default) +x-remote Experimental remote machine + +Fixes: ef2f11454c(hw/loongarch/virt: Replace Loongson IPI with LoongArch IPI) +Signed-off-by: Bibo Mao +Reviewed-by: Thomas Huth +Reviewed-by: Michael Tokarev +Signed-off-by: Michael Tokarev +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 79b16953d2..9f47107379 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -1383,6 +1383,7 @@ static void virt_class_init(ObjectClass *oc, void *data) + mc->init = virt_init; + mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464"); + mc->default_ram_id = "loongarch.ram"; ++ mc->desc = "QEMU LoongArch Virtual Machine"; + mc->max_cpus = LOONGARCH_MAX_CPUS; + mc->is_default = 1; + mc->default_kernel_irqchip_split = false; +-- +2.39.1 + diff --git a/hw-loongarch-virt-Remove-unused-assignment.patch b/hw-loongarch-virt-Remove-unused-assignment.patch new file mode 100644 index 0000000000000000000000000000000000000000..37f7cd13f22d1f70fcfb076b6abe4a0a418657fd --- /dev/null +++ b/hw-loongarch-virt-Remove-unused-assignment.patch @@ -0,0 +1,59 @@ +From 5e0ec61ac98a025124912fc47552550b471ab638 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 12 Jun 2024 11:36:37 +0800 +Subject: [PATCH 32/78] hw/loongarch/virt: Remove unused assignment + +There is abuse usage about local variable gap. Remove +duplicated assignment and solve Coverity reported error. + +Resolves: Coverity CID 1546441 +Fixes: 3cc451cbce ("hw/loongarch: Refine fwcfg memory map") +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240612033637.167787-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 12816c6023..a7283e6755 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -1034,7 +1034,6 @@ static void fw_cfg_add_memory(MachineState *ms) + memmap_add_entry(base, gap, 1); + size -= gap; + base = VIRT_HIGHMEM_BASE; +- gap = ram_size - VIRT_LOWMEM_SIZE; + } + + if (size) { +@@ -1047,17 +1046,17 @@ static void fw_cfg_add_memory(MachineState *ms) + } + + /* add fw_cfg memory map of other nodes */ +- size = ram_size - numa_info[0].node_mem; +- gap = VIRT_LOWMEM_BASE + VIRT_LOWMEM_SIZE; +- if (base < gap && (base + size) > gap) { ++ if (numa_info[0].node_mem < gap && ram_size > gap) { + /* + * memory map for the maining nodes splited into two part +- * lowram: [base, +(gap - base)) +- * highram: [VIRT_HIGHMEM_BASE, +(size - (gap - base))) ++ * lowram: [base, +(gap - numa_info[0].node_mem)) ++ * highram: [VIRT_HIGHMEM_BASE, +(ram_size - gap)) + */ +- memmap_add_entry(base, gap - base, 1); +- size -= gap - base; ++ memmap_add_entry(base, gap - numa_info[0].node_mem, 1); ++ size = ram_size - gap; + base = VIRT_HIGHMEM_BASE; ++ } else { ++ size = ram_size - numa_info[0].node_mem; + } + + if (size) +-- +2.39.1 + diff --git a/hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch b/hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch new file mode 100644 index 0000000000000000000000000000000000000000..d765070c761981175ad9c4fb9f5592c0ad816391 --- /dev/null +++ b/hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch @@ -0,0 +1,143 @@ +From a3728999125cd9fc9e3e841b66a1677663933c27 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 23 Oct 2024 15:13:12 +0800 +Subject: [PATCH 71/78] hw/loongarch/virt: Update the ACPI table for hotplug + cpu + +On LoongArch virt machine, ACPI GED hardware is used for cpu +hotplug, here cpu hotplug support feature is added on GED device, +also cpu scan and reject method is added about CPU device in +DSDT table. + +Co-developed-by: Xianglai Li +Signed-off-by: Bibo Mao +Message-ID: <20241023071312.881866-4-maobibo@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/acpi-build.c | 35 +++++++++++++++++++++++++++++++++-- + hw/loongarch/virt.c | 10 ++++++++++ + include/hw/loongarch/virt.h | 1 + + 3 files changed, 44 insertions(+), 2 deletions(-) + +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index bcdec2e1cb..a54c5e0e70 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -47,6 +47,22 @@ + #define ACPI_BUILD_DPRINTF(fmt, ...) + #endif + ++static void virt_madt_cpu_entry(int uid, ++ const CPUArchIdList *apic_ids, ++ GArray *entry, bool force_enabled) ++{ ++ uint32_t flags, apic_id = apic_ids->cpus[uid].arch_id; ++ ++ flags = apic_ids->cpus[uid].cpu || 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 */ ++} ++ + /* build FADT */ + static void init_common_fadt_data(AcpiFadtData *data) + { +@@ -123,15 +139,17 @@ build_madt(GArray *table_data, BIOSLinker *linker, + build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ + + for (i = 0; i < arch_ids->len; i++) { ++ uint32_t flags; ++ + /* Processor Core Interrupt Controller Structure */ + arch_id = arch_ids->cpus[i].arch_id; +- ++ flags = arch_ids->cpus[i].cpu ? 1 : 0; + build_append_int_noprefix(table_data, 17, 1); /* Type */ + build_append_int_noprefix(table_data, 15, 1); /* Length */ + build_append_int_noprefix(table_data, 1, 1); /* Version */ + build_append_int_noprefix(table_data, i, 4); /* ACPI Processor ID */ + build_append_int_noprefix(table_data, arch_id, 4); /* Core ID */ +- build_append_int_noprefix(table_data, 1, 4); /* Flags */ ++ build_append_int_noprefix(table_data, flags, 4); /* Flags */ + } + + /* Extend I/O Interrupt Controller Structure */ +@@ -334,6 +352,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine) + { + uint32_t event; + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); ++ CPUHotplugFeatures opts; + + build_ged_aml(dsdt, "\\_SB."GED_DEVICE, + HOTPLUG_HANDLER(lvms->acpi_ged), +@@ -346,6 +365,18 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine) + AML_SYSTEM_MEMORY, + VIRT_GED_MEM_ADDR); + } ++ ++ if (event & ACPI_GED_CPU_HOTPLUG_EVT) { ++ opts.acpi_1_compatible = false; ++ opts.has_legacy_cphp = false; ++ opts.fw_unplugs_cpu = false; ++ opts.smi_path = NULL; ++ ++ build_cpus_aml(dsdt, machine, opts, virt_madt_cpu_entry, NULL, ++ VIRT_GED_CPUHP_ADDR, "\\_SB", ++ NULL, AML_SYSTEM_MEMORY); ++ } ++ + acpi_dsdt_add_power_button(dsdt); + } + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index e7734ed3c0..6159fd9470 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -652,11 +652,17 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic, + { + DeviceState *dev; + MachineState *ms = MACHINE(lvms); ++ MachineClass *mc = MACHINE_GET_CLASS(lvms); + uint32_t event = ACPI_GED_PWR_DOWN_EVT; + + if (ms->ram_slots) { + event |= ACPI_GED_MEM_HOTPLUG_EVT; + } ++ ++ if (mc->has_hotpluggable_cpus) { ++ event |= ACPI_GED_CPU_HOTPLUG_EVT; ++ } ++ + dev = qdev_new(TYPE_ACPI_GED); + qdev_prop_set_uint32(dev, "ged-event", event); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); +@@ -668,6 +674,10 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic, + /* ged regs used for reset and power down */ + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_GED_REG_ADDR); + ++ if (mc->has_hotpluggable_cpus) { ++ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 3, VIRT_GED_CPUHP_ADDR); ++ } ++ + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + qdev_get_gpio_in(pch_pic, VIRT_SCI_IRQ - VIRT_GSI_BASE)); + return dev; +diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h +index 27c52af9f3..98c990327b 100644 +--- a/include/hw/loongarch/virt.h ++++ b/include/hw/loongarch/virt.h +@@ -32,6 +32,7 @@ + #define VIRT_GED_EVT_ADDR 0x100e0000 + #define VIRT_GED_MEM_ADDR (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN) + #define VIRT_GED_REG_ADDR (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN) ++#define VIRT_GED_CPUHP_ADDR (VIRT_GED_REG_ADDR + ACPI_GED_REG_COUNT) + + #define COMMAND_LINE_SIZE 512 + +-- +2.39.1 + diff --git a/hw-loongarch-virt-Use-MemTxAttrs-interface-for-misc-.patch b/hw-loongarch-virt-Use-MemTxAttrs-interface-for-misc-.patch new file mode 100644 index 0000000000000000000000000000000000000000..a6ccf48617de2e5fd0f31333f36f1e73fb1573c0 --- /dev/null +++ b/hw-loongarch-virt-Use-MemTxAttrs-interface-for-misc-.patch @@ -0,0 +1,77 @@ +From b63b7b0b6c9bed8e1a316f3838aab7db2e8f2037 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Tue, 28 May 2024 16:38:54 +0800 +Subject: [PATCH 29/78] hw/loongarch/virt: Use MemTxAttrs interface for misc + ops + +Use MemTxAttrs interface read_with_attrs/write_with_attrs +for virt_iocsr_misc_ops. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240528083855.1912757-3-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index f7874bccf9..12816c6023 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -915,8 +915,8 @@ static void virt_firmware_init(LoongArchVirtMachineState *lvms) + } + + +-static MemTxResult loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, +- unsigned size, MemTxAttrs attrs) ++static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size, MemTxAttrs attrs) + { + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque); + uint64_t features; +@@ -945,9 +945,9 @@ static MemTxResult loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, + return MEMTX_OK; + } + +-static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, +- uint64_t *data, +- unsigned size, MemTxAttrs attrs) ++static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr, ++ uint64_t *data, ++ unsigned size, MemTxAttrs attrs) + { + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque); + uint64_t ret = 0; +@@ -962,7 +962,7 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, + if (kvm_enabled()) { + ret |= BIT(IOCSRF_VM); + } +- return ret; ++ break; + case VENDOR_REG: + ret = 0x6e6f73676e6f6f4cULL; /* "Loongson" */ + break; +@@ -986,6 +986,8 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, + ret |= BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE); + } + break; ++ default: ++ g_assert_not_reached(); + } + + *data = ret; +@@ -993,8 +995,8 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr, + } + + static const MemoryRegionOps virt_iocsr_misc_ops = { +- .read_with_attrs = loongarch_qemu_read, +- .write_with_attrs = loongarch_qemu_write, ++ .read_with_attrs = virt_iocsr_misc_read, ++ .write_with_attrs = virt_iocsr_misc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, +-- +2.39.1 + diff --git a/hw-loongarch-virt-pass-random-seed-to-fdt.patch b/hw-loongarch-virt-pass-random-seed-to-fdt.patch new file mode 100644 index 0000000000000000000000000000000000000000..acc6323f0ecde2714b6b82fe38cc789a69c779f4 --- /dev/null +++ b/hw-loongarch-virt-pass-random-seed-to-fdt.patch @@ -0,0 +1,66 @@ +From 573f3bec8137caf829457620380d794165c96a92 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 5 Sep 2024 17:33:16 +0200 +Subject: [PATCH 36/78] hw/loongarch: virt: pass random seed to fdt + +If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to +initialize early. Set this using the usual guest random number +generation function. + +This is the same procedure that's done in b91b6b5a2c ("hw/microblaze: +pass random seed to fdt"), e4b4f0b71c ("hw/riscv: virt: pass random seed +to fdt"), c6fe3e6b4c ("hw/openrisc: virt: pass random seed to fdt"), +67f7e426e5 ("hw/i386: pass RNG seed via setup_data entry"), c287941a4d +("hw/rx: pass random seed to fdt"), 5e19cc68fb ("hw/mips: boston: pass +random seed to fdt"), 6b23a67916 ("hw/nios2: virt: pass random seed to fdt") +c4b075318e ("hw/ppc: pass random seed to fdt"), and 5242876f37 +("hw/arm/virt: dt: add rng-seed property"). + +These earlier commits later were amended to rerandomize the RNG seed on +snapshot load, but the LoongArch code somehow already does that, despite +not having this patch here, presumably due to some lucky copy and +pasting. + +Signed-off-by: Jason A. Donenfeld +Reviewed-by: Song Gao +Message-Id: <20240905153316.2038769-1-Jason@zx2c4.com> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index a6e9309064..79b16953d2 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -49,6 +49,7 @@ + #include "hw/block/flash.h" + #include "hw/virtio/virtio-iommu.h" + #include "qemu/error-report.h" ++#include "qemu/guest-random.h" + + static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms) + { +@@ -304,6 +305,7 @@ static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, + static void create_fdt(LoongArchVirtMachineState *lvms) + { + MachineState *ms = MACHINE(lvms); ++ uint8_t rng_seed[32]; + + ms->fdt = create_device_tree(&lvms->fdt_size); + if (!ms->fdt) { +@@ -317,6 +319,10 @@ static void create_fdt(LoongArchVirtMachineState *lvms) + qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); + qemu_fdt_add_subnode(ms->fdt, "/chosen"); ++ ++ /* Pass seed to RNG */ ++ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); ++ qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + } + + static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms) +-- +2.39.1 + diff --git a/hw-loongarch-virt-support-up-to-4-serial-ports.patch b/hw-loongarch-virt-support-up-to-4-serial-ports.patch new file mode 100644 index 0000000000000000000000000000000000000000..665c9ffbb7a7e2a71da54b8ca18d7bbb10ecef3f --- /dev/null +++ b/hw-loongarch-virt-support-up-to-4-serial-ports.patch @@ -0,0 +1,172 @@ +From 04895c794652c5da1ece0cad82741bed9aa8ad02 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sat, 7 Sep 2024 16:34:39 +0200 +Subject: [PATCH 35/78] hw/loongarch: virt: support up to 4 serial ports + +In order to support additional channels of communication using +`-serial`, add several serial ports, up to the standard 4 generally +supported by the 8250 driver. + +Fixed: https://lore.kernel.org/all/20240907143439.2792924-1-Jason@zx2c4.com/ + +Signed-off-by: Jason A. Donenfeld +Tested-by: Bibo Mao +[gaosong: ACPI uart need't reverse order] +Signed-off-by: Song Gao +Message-Id: <20240907143439.2792924-1-Jason@zx2c4.com> +Signed-off-by: Xianglai Li +--- + hw/loongarch/acpi-build.c | 23 +++++++++++++++-------- + hw/loongarch/virt.c | 27 +++++++++++++++++---------- + include/hw/pci-host/ls7a.h | 9 +++++---- + 3 files changed, 37 insertions(+), 22 deletions(-) + +diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c +index 1a9d25fc51..33a92223d8 100644 +--- a/hw/loongarch/acpi-build.c ++++ b/hw/loongarch/acpi-build.c +@@ -31,6 +31,7 @@ + + #include "hw/acpi/generic_event_device.h" + #include "hw/pci-host/gpex.h" ++#include "sysemu/sysemu.h" + #include "sysemu/tpm.h" + #include "hw/platform-bus.h" + #include "hw/acpi/aml-build.h" +@@ -252,23 +253,27 @@ struct AcpiBuildState { + MemoryRegion *linker_mr; + } AcpiBuildState; + +-static void build_uart_device_aml(Aml *table) ++static void build_uart_device_aml(Aml *table, int index) + { + Aml *dev; + Aml *crs; + Aml *pkg0, *pkg1, *pkg2; +- uint32_t uart_irq = VIRT_UART_IRQ; +- +- Aml *scope = aml_scope("_SB"); +- dev = aml_device("COMA"); ++ Aml *scope; ++ uint32_t uart_irq; ++ uint64_t base; ++ ++ uart_irq = VIRT_UART_IRQ + index; ++ base = VIRT_UART_BASE + index * VIRT_UART_SIZE; ++ scope = aml_scope("_SB"); ++ dev = aml_device("COM%d", index); + 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("_UID", aml_int(index))); + 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, VIRT_UART_BASE, VIRT_UART_BASE + VIRT_UART_SIZE - 1, ++ 0, base, base + VIRT_UART_SIZE - 1, + 0, VIRT_UART_SIZE)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_SHARED, &uart_irq, 1)); +@@ -401,6 +406,7 @@ static void acpi_dsdt_add_tpm(Aml *scope, LoongArchVirtMachineState *vms) + static void + build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) + { ++ int i; + Aml *dsdt, *scope, *pkg; + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lvms->oem_id, +@@ -408,7 +414,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) + + acpi_table_begin(&table, table_data); + dsdt = init_aml_allocator(); +- build_uart_device_aml(dsdt); ++ for (i = 0; i < VIRT_UART_COUNT; i++) ++ build_uart_device_aml(dsdt, i); + build_pci_device_aml(dsdt, lvms); + build_la_ged_aml(dsdt, machine); + build_flash_aml(dsdt, lvms); +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index a7283e6755..a6e9309064 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -281,10 +281,10 @@ static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms, + } + + static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, +- uint32_t *pch_pic_phandle) ++ uint32_t *pch_pic_phandle, hwaddr base, ++ int irq, bool chosen) + { + char *nodename; +- hwaddr base = VIRT_UART_BASE; + hwaddr size = VIRT_UART_SIZE; + MachineState *ms = MACHINE(lvms); + +@@ -293,9 +293,9 @@ static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a"); + qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size); + qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000); +- qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); +- qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", +- VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4); ++ if (chosen) ++ qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0x4); + qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", + *pch_pic_phandle); + g_free(nodename); +@@ -706,11 +706,18 @@ static void virt_devices_init(DeviceState *pch_pic, + /* Add pcie node */ + fdt_add_pcie_node(lvms, pch_pic_phandle, pch_msi_phandle); + +- serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0, +- qdev_get_gpio_in(pch_pic, +- VIRT_UART_IRQ - VIRT_GSI_BASE), +- 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); +- fdt_add_uart_node(lvms, pch_pic_phandle); ++ /* ++ * Create uart fdt node in reverse order so that they appear ++ * in the finished device tree lowest address first ++ */ ++ for (i = VIRT_UART_COUNT; i --> 0;) { ++ hwaddr base = VIRT_UART_BASE + i * VIRT_UART_SIZE; ++ int irq = VIRT_UART_IRQ + i - VIRT_GSI_BASE; ++ serial_mm_init(get_system_memory(), base, 0, ++ qdev_get_gpio_in(pch_pic, irq), ++ 115200, serial_hd(i), DEVICE_LITTLE_ENDIAN); ++ fdt_add_uart_node(lvms, pch_pic_phandle, base, irq, i == 0); ++ } + + /* Network init */ + for (i = 0; i < nb_nics; i++) { +diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h +index cd7c9ec7bc..79d4ea8501 100644 +--- a/include/hw/pci-host/ls7a.h ++++ b/include/hw/pci-host/ls7a.h +@@ -36,17 +36,18 @@ + #define VIRT_PCH_PIC_IRQ_NUM 32 + #define VIRT_GSI_BASE 64 + #define VIRT_DEVICE_IRQS 16 ++#define VIRT_UART_COUNT 4 + #define VIRT_UART_IRQ (VIRT_GSI_BASE + 2) + #define VIRT_UART_BASE 0x1fe001e0 +-#define VIRT_UART_SIZE 0X100 +-#define VIRT_RTC_IRQ (VIRT_GSI_BASE + 3) ++#define VIRT_UART_SIZE 0x100 ++#define VIRT_RTC_IRQ (VIRT_GSI_BASE + 6) + #define VIRT_MISC_REG_BASE (VIRT_PCH_REG_BASE + 0x00080000) + #define VIRT_RTC_REG_BASE (VIRT_MISC_REG_BASE + 0x00050100) + #define VIRT_RTC_LEN 0x100 +-#define VIRT_SCI_IRQ (VIRT_GSI_BASE + 4) ++#define VIRT_SCI_IRQ (VIRT_GSI_BASE + 7) + + #define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 + #define VIRT_PLATFORM_BUS_SIZE 0x2000000 + #define VIRT_PLATFORM_BUS_NUM_IRQS 2 +-#define VIRT_PLATFORM_BUS_IRQ (VIRT_GSI_BASE + 5) ++#define VIRT_PLATFORM_BUS_IRQ (VIRT_GSI_BASE + 8) + #endif +-- +2.39.1 + diff --git a/linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch b/linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch new file mode 100644 index 0000000000000000000000000000000000000000..88d04a7dbffcf482e3530f22a301c4ee833434da --- /dev/null +++ b/linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch @@ -0,0 +1,40 @@ +From 734b877ee97c73c7cbeeb02c560b9b4e6a8c0dda Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Thu, 17 Oct 2024 10:07:07 +0800 +Subject: [PATCH 60/78] linux-headers: loongarch: Add kvm_para.h and + unistd_64.h + +KVM LBT supports on LoongArch depends on the linux-header file +kvm_para.h, also unistd_64.h is required by unistd.h on LoongArch +since 6.11, otherwise there will be compiling error such as: + +linux-headers/asm/unistd.h:3:10: fatal error: asm/unistd_64.h: No such file or directory + #include + +Signed-off-by: Bibo Mao +Acked-by: Song Gao +Message-Id: <20241017020708.1728620-2-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + scripts/update-linux-headers.sh | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh +index 34295c0fe5..88c76b8f69 100755 +--- a/scripts/update-linux-headers.sh ++++ b/scripts/update-linux-headers.sh +@@ -156,6 +156,10 @@ for arch in $ARCHLIST; do + cp_portable "$tmpdir/bootparam.h" \ + "$output/include/standard-headers/asm-$arch" + fi ++ if [ $arch = loongarch ]; then ++ cp "$hdrdir/include/asm/kvm_para.h" "$output/linux-headers/asm-loongarch/" ++ cp "$hdrdir/include/asm/unistd_64.h" "$output/linux-headers/asm-loongarch/" ++ fi + done + + rm -rf "$output/linux-headers/linux" +-- +2.39.1 + diff --git a/loongarch-switch-boards-to-default-y.patch b/loongarch-switch-boards-to-default-y.patch new file mode 100644 index 0000000000000000000000000000000000000000..305436b3ece883594467499e853fcd7763068e88 --- /dev/null +++ b/loongarch-switch-boards-to-default-y.patch @@ -0,0 +1,60 @@ +From 0e0326de88282a601ea5178d421242d5b77afbfa Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 25 Jan 2024 13:36:37 +0100 +Subject: [PATCH 17/78] loongarch: switch boards to "default y" + +Some targets use "default y" for boards to filter out those that require +TCG. For consistency we are switching all other targets to do the same. +Continue with Loongarch. + +No changes to generated config-devices.mak file. + +Signed-off-by: Paolo Bonzini +Signed-off-by: Xianglai Li +--- + .gitlab-ci.d/buildtest.yml | 2 ++ + configs/devices/loongarch64-softmmu/default.mak | 6 +++++- + hw/loongarch/Kconfig | 2 ++ + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml +index 91663946de..3fb99e79e9 100644 +--- a/.gitlab-ci.d/buildtest.yml ++++ b/.gitlab-ci.d/buildtest.yml +@@ -579,6 +579,8 @@ build-tci: + - make check-tcg + + # Check our reduced build configurations ++# requires libfdt: aarch64, arm, i386, loongarch64, x86_64 ++# does not build without boards: i386, loongarch64, x86_64 + build-without-defaults: + extends: .native_build_job_template + needs: +diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak +index 928bc117ef..ffe705836f 100644 +--- a/configs/devices/loongarch64-softmmu/default.mak ++++ b/configs/devices/loongarch64-softmmu/default.mak +@@ -1,3 +1,7 @@ + # Default configuration for loongarch64-softmmu + +-CONFIG_LOONGARCH_VIRT=y ++# Uncomment the following lines to disable these optional devices: ++# CONFIG_PCI_DEVICES=n ++ ++# Boards are selected by default, uncomment to keep out of the build. ++# CONFIG_LOONGARCH_VIRT=n +diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig +index 5727efed6d..7864050563 100644 +--- a/hw/loongarch/Kconfig ++++ b/hw/loongarch/Kconfig +@@ -1,5 +1,7 @@ + config LOONGARCH_VIRT + bool ++ default y ++ depends on LOONGARCH64 + select PCI + select PCI_EXPRESS_GENERIC_BRIDGE + imply VIRTIO_VGA +-- +2.39.1 + diff --git a/physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch b/physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch new file mode 100644 index 0000000000000000000000000000000000000000..4d3413d07b954188d94a397bc4d5582663040a77 --- /dev/null +++ b/physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch @@ -0,0 +1,93 @@ +From 7efd5d829730d0481659cda91f725df3b141f469 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:15:01 +0100 +Subject: [PATCH 66/78] physmem: Add helper function to destroy CPU + AddressSpace + +Virtual CPU Hot-unplug leads to unrealization of a CPU object. This also +involves destruction of the CPU AddressSpace. Add common function to help +destroy the CPU AddressSpace. + +Signed-off-by: Salil Mehta +Tested-by: Vishnu Pajjuri +Reviewed-by: Gavin Shan +Tested-by: Xianglai Li +Tested-by: Miguel Luis +Reviewed-by: Shaoqin Huang +Tested-by: Zhao Liu +Acked-by: Igor Mammedov +Message-Id: <20240716111502.202344-7-salil.mehta@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Xianglai Li +--- + include/hw/core/cpu.h | 4 ++-- + system/physmem.c | 18 +++++++++++------- + 2 files changed, 13 insertions(+), 9 deletions(-) + +diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h +index ee04ee44c2..37f3a469c8 100644 +--- a/include/hw/core/cpu.h ++++ b/include/hw/core/cpu.h +@@ -495,8 +495,8 @@ struct CPUState { + QemuMutex work_mutex; + QSIMPLEQ_HEAD(, qemu_work_item) work_list; + +- CPUAddressSpace *cpu_ases; +- int cpu_ases_ref_count; ++ struct CPUAddressSpace *cpu_ases; ++ int cpu_ases_count; + int num_ases; + AddressSpace *as; + MemoryRegion *memory; +diff --git a/system/physmem.c b/system/physmem.c +index 2c8b83f811..c50ac24786 100644 +--- a/system/physmem.c ++++ b/system/physmem.c +@@ -761,7 +761,7 @@ void cpu_address_space_init(CPUState *cpu, int asidx, + + if (!cpu->cpu_ases) { + cpu->cpu_ases = g_new0(CPUAddressSpace, cpu->num_ases); +- cpu->cpu_ases_ref_count = cpu->num_ases; ++ cpu->cpu_ases_count = cpu->num_ases; + } + + newas = &cpu->cpu_ases[asidx]; +@@ -779,24 +779,28 @@ void cpu_address_space_destroy(CPUState *cpu, int asidx) + { + CPUAddressSpace *cpuas; + +- assert(asidx < cpu->num_ases); +- assert(asidx == 0 || !kvm_enabled()); + assert(cpu->cpu_ases); ++ assert(asidx >= 0 && asidx < cpu->num_ases); ++ /* KVM cannot currently support multiple address spaces. */ ++ assert(asidx == 0 || !kvm_enabled()); + + cpuas = &cpu->cpu_ases[asidx]; + if (tcg_enabled()) { + memory_listener_unregister(&cpuas->tcg_as_listener); + } + +- cpuas->as->free_in_rcu = true; + address_space_destroy(cpuas->as); ++ g_free_rcu(cpuas->as, rcu); + +- if (cpu->cpu_ases_ref_count == 1) { ++ if (asidx == 0) { ++ /* reset the convenience alias for address space 0 */ ++ cpu->as = NULL; ++ } ++ ++ if (--cpu->cpu_ases_count == 0) { + g_free(cpu->cpu_ases); + cpu->cpu_ases = NULL; + } +- +- cpu->cpu_ases_ref_count--; + } + + AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx) +-- +2.39.1 + diff --git a/qemu.spec b/qemu.spec index 316b3062cca3d89ff7c22626f70b6a053b074fff..f09c6da0677d03f2228b4706635c85ad88dbd198 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 26 +Release: 27 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -485,6 +485,84 @@ Patch0468: target-m68k-Map-FPU-exceptions-to-FPSR-register.patch Patch0469: migration-fix-possible-int-overflow.patch Patch0470: tcg-Allow-top-bit-of-SIMD_DATA_BITS-to-be-set-in-sim.patch Patch0471: vdpa-dev-Fix-initialisation-order-to-restore-VDUSE-c.patch +Patch0472: hw-loongarch-Move-boot-functions-to-boot.c.patch +Patch0473: hw-loongarch-Add-load-initrd.patch +Patch0474: hw-loongarch-Add-slave-cpu-boot_code.patch +Patch0475: hw-loongarch-Add-init_cmdline.patch +Patch0476: hw-loongarch-Init-efi_system_table.patch +Patch0477: hw-loongarch-Init-efi_boot_memmap-table.patch +Patch0478: hw-loongarch-Init-efi_initrd-table.patch +Patch0479: hw-loongarch-Init-efi_fdt-table.patch +Patch0480: hw-loongarch-fdt-adds-cpu-interrupt-controller-node.patch +Patch0481: hw-loongarch-fdt-adds-Extend-I-O-Interrupt-Controlle.patch +Patch0482: hw-loongarch-fdt-adds-pch_pic-Controller.patch +Patch0483: hw-loongarch-fdt-adds-pch_msi-Controller.patch +Patch0484: hw-loongarch-fdt-adds-pcie-irq_map-node.patch +Patch0485: hw-loongarch-fdt-remove-unused-irqchip-node.patch +Patch0486: hw-loongarch-Add-cells-missing-from-uart-node.patch +Patch0487: hw-loongarch-Add-cells-missing-from-rtc-node.patch +Patch0488: loongarch-switch-boards-to-default-y.patch +Patch0489: hw-loongarch-move-memory-map-to-boot.c.patch +Patch0490: hw-loongarch-Rename-LOONGARCH_MACHINE-with-LOONGARCH.patch +Patch0491: hw-loongarch-Rename-LoongArchMachineState-with-Loong.patch +Patch0492: hw-loongarch-Refine-default-numa-id-calculation.patch +Patch0493: hw-loongarch-Add-VM-mode-in-IOCSR-feature-register-i.patch +Patch0494: hw-loongarch-Refine-acpi-srat-table-for-numa-memory.patch +Patch0495: hw-loongarch-Refine-fadt-memory-table-for-numa-memor.patch +Patch0496: hw-loongarch-Refine-fwcfg-memory-map.patch +Patch0497: hw-loongarch-Refine-system-dram-memory-region.patch +Patch0498: hw-loongarch-Remove-minimum-and-default-memory-size.patch +Patch0499: tests-libqos-Add-loongarch-virt-machine-node.patch +Patch0500: hw-loongarch-virt-Use-MemTxAttrs-interface-for-misc-.patch +Patch0501: hw-loongarch-boot.c-fix-out-of-bound-reading.patch +Patch0502: hw-loongarch-Change-the-tpm-support-by-default.patch +Patch0503: hw-loongarch-virt-Remove-unused-assignment.patch +Patch0504: hw-loongarch-Fix-length-for-lowram-in-ACPI-SRAT.patch +Patch0505: hw-loongarch-Remove-default-enable-with-VIRTIO_VGA-d.patch +Patch0506: hw-loongarch-virt-support-up-to-4-serial-ports.patch +Patch0507: hw-loongarch-virt-pass-random-seed-to-fdt.patch +Patch0508: hw-loongarch-Add-acpi-SPCR-table-support.patch +Patch0509: hw-loongarch-virt-Add-description-for-virt-machine-t.patch +Patch0510: hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch +Patch0511: hw-arm-virt-acpi-build.c-Migrate-SPCR-creation-to-co.patch +Patch0512: target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch +Patch0513: target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch +Patch0514: target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch +Patch0515: target-loongarch-Add-loongarch-vector-property-uncon.patch +Patch0516: target-loongarch-kvm-Add-software-breakpoint-support-sync-upstream.patch +Patch0517: target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch +Patch0518: target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch +Patch0519: target-loongarch-Fix-cpu_reset-set-wrong-CSR_CRMD.patch +Patch0520: target-loongarch-Add-compatible-support-about-VM-reb.patch +Patch0521: target-loongarch-kvm-Add-vCPU-reset-function.patch +Patch0522: target-loongarch-Support-QMP-dump-guest-memory.patch +Patch0523: target-loongarch-fix-Werror-maybe-uninitialized-fals.patch +Patch0524: target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch +Patch0525: target-loongarch-Avoid-bits-shift-exceeding-width-of.patch +Patch0526: sync-loongarch-linux-headers.patch +Patch0527: target-loongarch-Add-loongson-binary-translation-fea.patch +Patch0528: target-loongarch-Implement-lbt-registers-save-restor.patch +Patch0529: target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch +Patch0530: linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch +Patch0531: target-loongarch-Add-steal-time-support-on-migration.patch +Patch0532: accel-kvm-Extract-common-KVM-vCPU-creation-parking-c-sync-upstream.patch +Patch0533: hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c-sync-upstream.patch +Patch0534: hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho-sync-upstream.patch +Patch0535: hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change-sync-upstream.patch +Patch0536: physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch +Patch0537: gdbstub-Add-helper-function-to-unregister-GDB-regist.patch +Patch0538: accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch +Patch0539: hw-loongarch-virt-Add-CPU-topology-support.patch +Patch0540: hw-loongarch-virt-Add-basic-CPU-plug-support.patch +Patch0541: hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch +Patch0542: hw-loongarch-Add-KVM-IPI-device-support.patch +Patch0543: hw-loongarch-Add-KVM-extioi-device-support.patch +Patch0544: hw-loongarch-Add-KVM-pch-pic-device-support.patch +Patch0545: hw-loongarch-Add-KVM-pch-msi-device-support.patch +Patch0546: hw-loongarch-clean-code.patch +Patch0547: hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch +Patch0548: hw-loongarch-fix-cpu-hotplug-reset.patch +Patch0549: fix-compile-error-on-loongarch.patch BuildRequires: flex BuildRequires: gcc @@ -662,6 +740,7 @@ This package provides the QEMU system emulator for riscv. %package system-loongarch64 Summary: Qemu-system-loongarch64 Requires: qemu +Requires: spice-gtk %description system-loongarch64 This package provides the QEMU system emulator for loongarch64. @@ -1082,6 +1161,86 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Fri Dec 13 2024 Xianglai Li - 11:8.2.0-27 +- fix compile error on loongarch +- hw/loongarch: fix cpu hotplug reset +- hw/loongarch/boot: Use warn_report when no kernel filename +- hw/loongarch: clean code +- hw/loongarch: Add KVM pch msi device support +- hw/loongarch: Add KVM pch pic device support +- hw/loongarch: Add KVM extioi device support +- hw/loongarch: Add KVM IPI device support +- hw/loongarch/virt: Update the ACPI table for hotplug cpu +- hw/loongarch/virt: Add basic CPU plug support +- hw/loongarch/virt: Add CPU topology support +- accel/kvm/kvm-all: Fixes the missing break in vCPU unpark logic +- gdbstub: Add helper function to unregister GDB register space +- physmem: Add helper function to destroy CPU AddressSpace +- hw/acpi: Update CPUs AML with cpu-(ctrl)dev change +- hw/acpi: Update ACPI GED framework to support vCPU Hotplug +- hw/acpi: Move CPU ctrl-dev MMIO region len macro to common header file +- accel/kvm: Extract common KVM vCPU {creation,parking} code +- target/loongarch: Add steal time support on migration +- linux-headers: loongarch: Add kvm_para.h and unistd_64.h +- target/loongarch/kvm: Implement LoongArch PMU extension +- target/loongarch: Implement lbt registers save/restore function +- target/loongarch: Add loongson binary translation feature +- sync loongarch linux-headers +- target/loongarch: Avoid bits shift exceeding width of bool type +- target/loongarch: Use explicit little-endian LD/ST API +- target/loongarch: fix -Werror=maybe-uninitialized false-positive +- target/loongarch: Support QMP dump-guest-memory +- target/loongarch/kvm: Add vCPU reset function +- target/loongarch: Add compatible support about VM reboot +- target/loongarch: Fix cpu_reset set wrong CSR_CRMD +- target/loongarch: Set CSR_PRCFG1 and CSR_PRCFG2 values +- target/loongarch: Remove avail_64 in trans_srai_w() and simplify it +- target/loongarch/kvm: Add software breakpoint support +- target/loongarch: Add loongarch vector property unconditionally +- target/loongarch/kvm: Fix VM recovery from disk failures +- target/loongarch: Put cpucfg operation before CSR register +- target/loongarch: Add TCG macro in structure CPUArchState +- hw/arm/virt-acpi-build.c: Migrate SPCR creation to common location +- hw/loongarch/virt: Add FDT table support with acpi ged pm register +- hw/loongarch/virt: Add description for virt machine type +- hw/loongarch: Add acpi SPCR table support +- hw/loongarch: virt: pass random seed to fdt +- hw/loongarch: virt: support up to 4 serial ports +- hw/loongarch: Remove default enable with VIRTIO_VGA device +- hw/loongarch: Fix length for lowram in ACPI SRAT +- hw/loongarch/virt: Remove unused assignment +- hw/loongarch: Change the tpm support by default +- hw/loongarch/boot.c: fix out-of-bound reading +- hw/loongarch/virt: Use MemTxAttrs interface for misc ops +- tests/libqos: Add loongarch virt machine node +- hw/loongarch: Remove minimum and default memory size +- hw/loongarch: Refine system dram memory region +- hw/loongarch: Refine fwcfg memory map +- hw/loongarch: Refine fadt memory table for numa memory +- hw/loongarch: Refine acpi srat table for numa memory +- hw/loongarch: Add VM mode in IOCSR feature register in kvm mode +- hw/loongarch: Refine default numa id calculation +- hw/loongarch: Rename LoongArchMachineState with LoongArchVirtMachineState +- hw/loongarch: Rename LOONGARCH_MACHINE with LOONGARCH_VIRT_MACHINE +- hw/loongarch: move memory map to boot.c +- loongarch: switch boards to "default y" +- hw/loongarch: Add cells missing from rtc node +- hw/loongarch: Add cells missing from uart node +- hw/loongarch: fdt remove unused irqchip node +- hw/loongarch: fdt adds pcie irq_map node +- hw/loongarch: fdt adds pch_msi Controller +- hw/loongarch: fdt adds pch_pic Controller +- hw/loongarch: fdt adds Extend I/O Interrupt Controller +- hw/loongarch: fdt adds cpu interrupt controller node +- hw/loongarch: Init efi_fdt table +- hw/loongarch: Init efi_initrd table +- hw/loongarch: Init efi_boot_memmap table +- hw/loongarch: Init efi_system_table +- hw/loongarch: Add init_cmdline +- hw/loongarch: Add slave cpu boot_code +- hw/loongarch: Add load initrd +- hw/loongarch: Move boot functions to boot.c + * Thu Dec 12 2024 Jiabo Feng - 11:8.2.0-26 - vdpa-dev: Fix initialisation order to restore VDUSE compatibility - tcg: Allow top bit of SIMD_DATA_BITS to be set in simd_desc() diff --git a/sync-loongarch-linux-headers.patch b/sync-loongarch-linux-headers.patch new file mode 100644 index 0000000000000000000000000000000000000000..30aad853a0a78ef0dabc008b50641c0eaed084d5 --- /dev/null +++ b/sync-loongarch-linux-headers.patch @@ -0,0 +1,97 @@ +From 23cede66eaa62e8ec559cfa538a59e72375c9fa8 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 03:28:16 +0800 +Subject: [PATCH 56/78] sync loongarch linux-headers + +Signed-off-by: gaosong +Signed-off-by: Xianglai Li +--- + linux-headers/asm-loongarch/kvm.h | 36 +++++++++++++++++++++++++++- + linux-headers/asm-loongarch/unistd.h | 1 + + 2 files changed, 36 insertions(+), 1 deletion(-) + +diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h +index 81fec85f0a..13c1280662 100644 +--- a/linux-headers/asm-loongarch/kvm.h ++++ b/linux-headers/asm-loongarch/kvm.h +@@ -19,6 +19,7 @@ + + #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 + #define KVM_DIRTY_LOG_PAGE_OFFSET 64 ++#define __KVM_HAVE_IRQ_LINE + + #define KVM_GUESTDBG_USE_SW_BP 0x00010000 + /* +@@ -66,6 +67,7 @@ struct kvm_fpu { + #define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL) + #define KVM_REG_LOONGARCH_FPSIMD (KVM_REG_LOONGARCH | 0x30000ULL) + #define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL) ++#define KVM_REG_LOONGARCH_LBT (KVM_REG_LOONGARCH | 0x50000ULL) + #define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL) + #define KVM_CSR_IDX_MASK 0x7fff + #define KVM_CPUCFG_IDX_MASK 0x7fff +@@ -79,13 +81,34 @@ struct kvm_fpu { + /* Debugging: Special instruction for software breakpoint */ + #define KVM_REG_LOONGARCH_DEBUG_INST (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3) + ++/* LBT registers */ ++#define KVM_REG_LOONGARCH_LBT_SCR0 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 1) ++#define KVM_REG_LOONGARCH_LBT_SCR1 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 2) ++#define KVM_REG_LOONGARCH_LBT_SCR2 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 3) ++#define KVM_REG_LOONGARCH_LBT_SCR3 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 4) ++#define KVM_REG_LOONGARCH_LBT_EFLAGS (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 5) ++#define KVM_REG_LOONGARCH_LBT_FTOP (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 6) ++ + #define LOONGARCH_REG_SHIFT 3 + #define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT)) + #define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG) + #define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG) ++ ++/* Device Control API on vm fd */ ++#define KVM_LOONGARCH_VM_FEAT_CTRL 0 ++#define KVM_LOONGARCH_VM_FEAT_LSX 0 ++#define KVM_LOONGARCH_VM_FEAT_LASX 1 ++#define KVM_LOONGARCH_VM_FEAT_X86BT 2 ++#define KVM_LOONGARCH_VM_FEAT_ARMBT 3 ++#define KVM_LOONGARCH_VM_FEAT_MIPSBT 4 ++#define KVM_LOONGARCH_VM_FEAT_PMU 5 ++#define KVM_LOONGARCH_VM_FEAT_PV_IPI 6 ++#define KVM_LOONGARCH_VM_FEAT_PV_STEALTIME 7 ++ ++/* Device Control API on vcpu fd */ + #define KVM_LOONGARCH_VCPU_CPUCFG 0 + #define KVM_LOONGARCH_VCPU_PVTIME_CTRL 1 +-#define KVM_LOONGARCH_VCPU_PVTIME_GPA 0 ++#define KVM_LOONGARCH_VCPU_PVTIME_GPA 0 + + struct kvm_debug_exit_arch { + }; +@@ -112,4 +135,15 @@ struct kvm_iocsr_entry { + #define KVM_IRQCHIP_NUM_PINS 64 + #define KVM_MAX_CORES 256 + ++#define KVM_LOONGARCH_VM_HAVE_IRQCHIP 0x40000001 ++ ++#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000002 ++ ++#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000003 ++ ++#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000004 ++#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 ++ ++#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005 ++ + #endif /* __UAPI_ASM_LOONGARCH_KVM_H */ +diff --git a/linux-headers/asm-loongarch/unistd.h b/linux-headers/asm-loongarch/unistd.h +index fcb668984f..b344b1f917 100644 +--- a/linux-headers/asm-loongarch/unistd.h ++++ b/linux-headers/asm-loongarch/unistd.h +@@ -1,4 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++#define __ARCH_WANT_NEW_STAT + #define __ARCH_WANT_SYS_CLONE + #define __ARCH_WANT_SYS_CLONE3 + +-- +2.39.1 + diff --git a/target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch b/target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch new file mode 100644 index 0000000000000000000000000000000000000000..4988ba9ad37b71c226dadf1a5d833e8526dd12c1 --- /dev/null +++ b/target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch @@ -0,0 +1,235 @@ +From 033e2a67885cf7347473e09454a6704074e05878 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Mon, 6 May 2024 09:19:12 +0800 +Subject: [PATCH 42/78] target/loongarch: Add TCG macro in structure + CPUArchState + +In structure CPUArchState some struct elements are only used in TCG +mode, and it is not used in KVM mode. Macro CONFIG_TCG is added to +make it simpiler in KVM mode, also there is the same modification +in c code when these structure elements are used. + +When VM runs in KVM mode, TLB entries are not used and do not need +migrate. It is only useful when it runs in TCG mode. + +Signed-off-by: Bibo Mao +Reviewed-by: Richard Henderson +Message-Id: <20240506011912.2108842-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 7 +++-- + target/loongarch/cpu.h | 16 +++++++---- + target/loongarch/cpu_helper.c | 9 ++++++ + target/loongarch/machine.c | 52 ++++++++++++++++++++++++----------- + 4 files changed, 60 insertions(+), 24 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index f7b5dae7ed..220d40fb01 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -536,7 +536,9 @@ static void loongarch_cpu_reset_hold(Object *obj) + lacc->parent_phases.hold(obj); + } + ++#ifdef CONFIG_TCG + env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3; ++#endif + env->fcsr0 = 0x0; + + int n; +@@ -581,7 +583,9 @@ static void loongarch_cpu_reset_hold(Object *obj) + + #ifndef CONFIG_USER_ONLY + env->pc = 0x1c000000; ++#ifdef CONFIG_TCG + memset(env->tlb, 0, sizeof(env->tlb)); ++#endif + if (kvm_enabled()) { + kvm_arch_reset_vcpu(env); + } +@@ -778,8 +782,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) + int i; + + qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); +- qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0, +- get_float_exception_flags(&env->fp_status)); ++ qemu_fprintf(f, " FCSR0 0x%08x\n", env->fcsr0); + + /* gpr */ + for (i = 0; i < 32; i++) { +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index e3a15c593f..19bcad28de 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -275,6 +275,7 @@ union fpr_t { + VReg vreg; + }; + ++#ifdef CONFIG_TCG + struct LoongArchTLB { + uint64_t tlb_misc; + /* Fields corresponding to CSR_TLBELO0/1 */ +@@ -282,23 +283,18 @@ struct LoongArchTLB { + uint64_t tlb_entry1; + }; + typedef struct LoongArchTLB LoongArchTLB; ++#endif + + typedef struct CPUArchState { + uint64_t gpr[32]; + uint64_t pc; + + fpr_t fpr[32]; +- float_status fp_status; + bool cf[8]; +- + uint32_t fcsr0; +- uint32_t fcsr0_mask; + + uint32_t cpucfg[21]; + +- uint64_t lladdr; /* LL virtual address compared against SC */ +- uint64_t llval; +- + /* LoongArch CSRs */ + uint64_t CSR_CRMD; + uint64_t CSR_PRMD; +@@ -355,8 +351,16 @@ typedef struct CPUArchState { + uint64_t CSR_DERA; + uint64_t CSR_DSAVE; + ++#ifdef CONFIG_TCG ++ float_status fp_status; ++ uint32_t fcsr0_mask; ++ uint64_t lladdr; /* LL virtual address compared against SC */ ++ uint64_t llval; ++#endif + #ifndef CONFIG_USER_ONLY ++#ifdef CONFIG_TCG + LoongArchTLB tlb[LOONGARCH_TLB_MAX]; ++#endif + + AddressSpace *address_space_iocsr; + bool load_elf; +diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c +index f68d63f466..39037eecb4 100644 +--- a/target/loongarch/cpu_helper.c ++++ b/target/loongarch/cpu_helper.c +@@ -11,6 +11,7 @@ + #include "internals.h" + #include "cpu-csr.h" + ++#ifdef CONFIG_TCG + static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + int access_type, int index, int mmu_idx) +@@ -154,6 +155,14 @@ static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, + + return TLBRET_NOMATCH; + } ++#else ++static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, ++ int *prot, target_ulong address, ++ MMUAccessType access_type, int mmu_idx) ++{ ++ return TLBRET_NOMATCH; ++} ++#endif + + static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va, + target_ulong dmw) +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index ec5abe56db..4bbf495d6b 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -8,6 +8,7 @@ + #include "qemu/osdep.h" + #include "cpu.h" + #include "migration/cpu.h" ++#include "sysemu/tcg.h" + #include "vec.h" + #include "kvm/kvm_loongarch.h" + #include "sysemu/kvm.h" +@@ -111,19 +112,6 @@ static const VMStateDescription vmstate_lasx = { + }, + }; + +-/* TLB state */ +-const VMStateDescription vmstate_tlb = { +- .name = "cpu/tlb", +- .version_id = 0, +- .minimum_version_id = 0, +- .fields = (VMStateField[]) { +- VMSTATE_UINT64(tlb_misc, LoongArchTLB), +- VMSTATE_UINT64(tlb_entry0, LoongArchTLB), +- VMSTATE_UINT64(tlb_entry1, LoongArchTLB), +- VMSTATE_END_OF_LIST() +- } +-}; +- + static int cpu_post_load(void *opaque, int version_id) + { + #ifdef CONFIG_KVM +@@ -142,6 +130,38 @@ static int cpu_pre_save(void *opaque) + return 0; + } + ++#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) ++static bool tlb_needed(void *opaque) ++{ ++ return tcg_enabled(); ++} ++ ++/* TLB state */ ++static const VMStateDescription vmstate_tlb_entry = { ++ .name = "cpu/tlb_entry", ++ .version_id = 0, ++ .minimum_version_id = 0, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT64(tlb_misc, LoongArchTLB), ++ VMSTATE_UINT64(tlb_entry0, LoongArchTLB), ++ VMSTATE_UINT64(tlb_entry1, LoongArchTLB), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static const VMStateDescription vmstate_tlb = { ++ .name = "cpu/tlb", ++ .version_id = 0, ++ .minimum_version_id = 0, ++ .needed = tlb_needed, ++ .fields = (const VMStateField[]) { ++ VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, ++ 0, vmstate_tlb_entry, LoongArchTLB), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++#endif ++ + /* LoongArch CPU state */ + const VMStateDescription vmstate_loongarch_cpu = { + .name = "cpu", +@@ -212,9 +232,6 @@ const VMStateDescription vmstate_loongarch_cpu = { + VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU), + VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU), + VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU), +- /* TLB */ +- VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, +- 0, vmstate_tlb, LoongArchTLB), + + VMSTATE_UINT64(kvm_state_counter, LoongArchCPU), + +@@ -224,6 +241,9 @@ const VMStateDescription vmstate_loongarch_cpu = { + &vmstate_fpu, + &vmstate_lsx, + &vmstate_lasx, ++#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) ++ &vmstate_tlb, ++#endif + NULL + } + }; +-- +2.39.1 + diff --git a/target-loongarch-Add-compatible-support-about-VM-reb.patch b/target-loongarch-Add-compatible-support-about-VM-reb.patch new file mode 100644 index 0000000000000000000000000000000000000000..0354a6bd1f67f79b5400cc322e974f8ab1349366 --- /dev/null +++ b/target-loongarch-Add-compatible-support-about-VM-reb.patch @@ -0,0 +1,51 @@ +From 2c6cf54ea2f52774f2587e7e66eed9beba3a3dec Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 27 Aug 2024 11:58:07 +0800 +Subject: [PATCH 50/78] target/loongarch: Add compatible support about VM + reboot + +With edk2-stable202408 LoongArch UEFI bios, CSR PGD register is set only +if its value is equal to zero for boot cpu, it causes reboot issue. Since +CSR PGD register is changed with linux kernel, UEFI BIOS cannot use it. + +Add workaround to clear CSR registers relative with TLB in function +loongarch_cpu_reset_hold(), so that VM can reboot with edk2-stable202408 +UEFI bios. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240827035807.3326293-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index d8a31929b4..2038984d02 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -580,6 +580,20 @@ static void loongarch_cpu_reset_hold(Object *obj) + env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); + env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0); + env->CSR_TID = cs->cpu_index; ++ /* ++ * Workaround for edk2-stable202408, CSR PGD register is set only if ++ * its value is equal to zero for boot cpu, it causes reboot issue. ++ * ++ * Here clear CSR registers relative with TLB. ++ */ ++ env->CSR_PGDH = 0; ++ env->CSR_PGDL = 0; ++ env->CSR_PWCL = 0; ++ env->CSR_PWCH = 0; ++ env->CSR_STLBPS = 0; ++ env->CSR_EENTRY = 0; ++ env->CSR_TLBRENTRY = 0; ++ env->CSR_MERRENTRY = 0; + + for (n = 0; n < 4; n++) { + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0); +-- +2.39.1 + diff --git a/target-loongarch-Add-loongarch-vector-property-uncon.patch b/target-loongarch-Add-loongarch-vector-property-uncon.patch new file mode 100644 index 0000000000000000000000000000000000000000..4b370e12ff8dac2a442637d2e4fd8010432f42ca --- /dev/null +++ b/target-loongarch-Add-loongarch-vector-property-uncon.patch @@ -0,0 +1,46 @@ +From f572c385e0d368cbf12acf7d6f0b33b5f2efd7f0 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 21 May 2024 16:05:48 +0800 +Subject: [PATCH 45/78] target/loongarch: Add loongarch vector property + unconditionally + +Currently LSX/LASX vector property is decided by the default value. +Instead vector property should be added unconditionally, and it is +irrelative with its default value. If vector is disabled by default, +vector also can be enabled from command line. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240521080549.434197-2-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 220d40fb01..f89740a5aa 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -720,14 +720,10 @@ void loongarch_cpu_post_init(Object *obj) + { + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + +- if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) { +- object_property_add_bool(obj, "lsx", loongarch_get_lsx, +- loongarch_set_lsx); +- } +- if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) { +- object_property_add_bool(obj, "lasx", loongarch_get_lasx, +- loongarch_set_lasx); +- } ++ object_property_add_bool(obj, "lsx", loongarch_get_lsx, ++ loongarch_set_lsx); ++ object_property_add_bool(obj, "lasx", loongarch_get_lasx, ++ loongarch_set_lasx); + + if (kvm_enabled()) { + object_property_add_bool(obj, "pmu", loongarch_get_pmu, +-- +2.39.1 + diff --git a/target-loongarch-Add-loongson-binary-translation-fea.patch b/target-loongarch-Add-loongson-binary-translation-fea.patch new file mode 100644 index 0000000000000000000000000000000000000000..159a1af87cfc12f5a26ad3c7155f7b21bcd9af13 --- /dev/null +++ b/target-loongarch-Add-loongson-binary-translation-fea.patch @@ -0,0 +1,200 @@ +From 962f649aa5a06169f0ac23f61e273f0860942ebb Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 29 Sep 2024 15:04:04 +0800 +Subject: [PATCH 57/78] target/loongarch: Add loongson binary translation + feature + +Loongson Binary Translation (LBT) is used to accelerate binary +translation, which contains 4 scratch registers (scr0 to scr3), x86/ARM +eflags (eflags) and x87 fpu stack pointer (ftop). + +Now LBT feature is added in kvm mode, not supported in TCG mode since +it is not emulated. Feature variable lbt is added with OnOffAuto type, +If lbt feature is not supported with KVM host, it reports error if there +is lbt=on command line. + +If there is no any command line about lbt parameter, it checks whether +KVM host supports lbt feature and set the corresponding value in cpucfg. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240929070405.235200-2-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 20 ++++++++++ + target/loongarch/cpu.h | 6 +++ + target/loongarch/kvm/kvm.c | 57 ++++++++++++++++++++++++++- + target/loongarch/loongarch-qmp-cmds.c | 2 +- + 4 files changed, 83 insertions(+), 2 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index d6a13de901..a57067938d 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -737,6 +737,18 @@ static void loongarch_set_pmnum(Object *obj, Visitor *v, + } + } + ++static bool loongarch_get_lbt(Object *obj, Error **errp) ++{ ++ return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF; ++} ++ ++static void loongarch_set_lbt(Object *obj, bool value, Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(obj); ++ ++ cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; ++} ++ + void loongarch_cpu_post_init(Object *obj) + { + LoongArchCPU *cpu = LOONGARCH_CPU(obj); +@@ -756,6 +768,14 @@ void loongarch_cpu_post_init(Object *obj) + loongarch_set_pmnum, NULL, + (void *)&value); + } ++ ++ cpu->lbt = ON_OFF_AUTO_AUTO; ++ object_property_add_bool(obj, "lbt", loongarch_get_lbt, ++ loongarch_set_lbt); ++ object_property_set_description(obj, "lbt", ++ "Set off to disable Binary Tranlation."); ++ } else { ++ cpu->lbt = ON_OFF_AUTO_OFF; + } + } + +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 19bcad28de..3e2bcbf608 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -155,6 +155,7 @@ FIELD(CPUCFG2, LLFTP_VER, 15, 3) + FIELD(CPUCFG2, LBT_X86, 18, 1) + FIELD(CPUCFG2, LBT_ARM, 19, 1) + FIELD(CPUCFG2, LBT_MIPS, 20, 1) ++FIELD(CPUCFG2, LBT_ALL, 18, 3) + FIELD(CPUCFG2, LSPW, 21, 1) + FIELD(CPUCFG2, LAM, 22, 1) + +@@ -285,6 +286,10 @@ struct LoongArchTLB { + typedef struct LoongArchTLB LoongArchTLB; + #endif + ++enum loongarch_features { ++ LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */ ++}; ++ + typedef struct CPUArchState { + uint64_t gpr[32]; + uint64_t pc; +@@ -388,6 +393,7 @@ struct ArchCPU { + CPULoongArchState env; + QEMUTimer timer; + uint32_t phy_id; ++ OnOffAuto lbt; + + /* 'compatible' string for this CPU for Linux device trees */ + const char *dtb_compatible; +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 90c8379c46..567404bdb5 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -9,6 +9,7 @@ + #include + #include + ++#include "qapi/error.h" + #include "qemu/timer.h" + #include "qemu/error-report.h" + #include "qemu/main-loop.h" +@@ -786,17 +787,71 @@ static void kvm_loongarch_vm_stage_change(void *opaque, bool running, + } + } + ++static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature) ++{ ++ int ret; ++ struct kvm_device_attr attr; ++ ++ switch (feature) { ++ case LOONGARCH_FEATURE_LBT: ++ /* ++ * Return all if all the LBT features are supported such as: ++ * KVM_LOONGARCH_VM_FEAT_X86BT ++ * KVM_LOONGARCH_VM_FEAT_ARMBT ++ * KVM_LOONGARCH_VM_FEAT_MIPSBT ++ */ ++ attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; ++ attr.attr = KVM_LOONGARCH_VM_FEAT_X86BT; ++ ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); ++ attr.attr = KVM_LOONGARCH_VM_FEAT_ARMBT; ++ ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); ++ attr.attr = KVM_LOONGARCH_VM_FEAT_MIPSBT; ++ ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); ++ return (ret == 0); ++ default: ++ return false; ++ } ++} ++ ++static int kvm_cpu_check_lbt(CPUState *cs, Error **errp) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ LoongArchCPU *cpu = LOONGARCH_CPU(cs); ++ bool kvm_supported; ++ ++ kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LBT); ++ if (cpu->lbt == ON_OFF_AUTO_ON) { ++ if (kvm_supported) { ++ env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7); ++ } else { ++ error_setg(errp, "'lbt' feature not supported by KVM on this host"); ++ return -ENOTSUP; ++ } ++ } else if ((cpu->lbt == ON_OFF_AUTO_AUTO) && kvm_supported) { ++ env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7); ++ } ++ ++ return 0; ++} ++ + int kvm_arch_init_vcpu(CPUState *cs) + { + uint64_t val; ++ int ret; ++ Error *local_err = NULL; + ++ ret = 0; + qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs); + + if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) { + brk_insn = val; + } + +- return 0; ++ ret = kvm_cpu_check_lbt(cs, &local_err); ++ if (ret < 0) { ++ error_report_err(local_err); ++ } ++ return ret; + } + + int kvm_arch_destroy_vcpu(CPUState *cs) +diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c +index 2612f43de9..644b528824 100644 +--- a/target/loongarch/loongarch-qmp-cmds.c ++++ b/target/loongarch/loongarch-qmp-cmds.c +@@ -42,7 +42,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) + } + + static const char *cpu_model_advertised_features[] = { +- "lsx", "lasx", "pmu", "pmnum", NULL ++ "lsx", "lasx", "lbt", "pmu", "pmnum", NULL + }; + + CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, +-- +2.39.1 + diff --git a/target-loongarch-Add-steal-time-support-on-migration.patch b/target-loongarch-Add-steal-time-support-on-migration.patch new file mode 100644 index 0000000000000000000000000000000000000000..2bcfe1ad9d88db6be77f1d869bf32cda9e27375d --- /dev/null +++ b/target-loongarch-Add-steal-time-support-on-migration.patch @@ -0,0 +1,151 @@ +From 8febab6bcb01e3e10ca4ac0021bae2a812a4452b Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Mon, 30 Sep 2024 14:40:40 +0800 +Subject: [PATCH 61/78] target/loongarch: Add steal time support on migration + +With pv steal time supported, VM machine needs get physical address +of each vcpu and notify new host during migration. Here two +functions kvm_get_stealtime/kvm_set_stealtime, and guest steal time +physical address is only updated on KVM_PUT_FULL_STATE stage. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-ID: <20240930064040.753929-1-maobibo@loongson.cn> +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.h | 3 ++ + target/loongarch/kvm/kvm.c | 65 ++++++++++++++++++++++++++++++++++++++ + target/loongarch/machine.c | 6 ++-- + 3 files changed, 72 insertions(+), 2 deletions(-) + +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 8ff00d17e1..4c90cf9ef3 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -369,6 +369,9 @@ typedef struct CPUArchState { + uint64_t CSR_DBG; + uint64_t CSR_DERA; + uint64_t CSR_DSAVE; ++ struct { ++ uint64_t guest_addr; ++ } stealtime; + + #ifdef CONFIG_TCG + float_status fp_status; +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 8b0f86a201..550f14269e 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -35,6 +35,55 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO + }; + ++static int kvm_get_stealtime(CPUState *cs) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ int err; ++ struct kvm_device_attr attr = { ++ .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, ++ .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, ++ .addr = (uint64_t)&env->stealtime.guest_addr, ++ }; ++ ++ err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); ++ if (err) { ++ return 0; ++ } ++ ++ err = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, attr); ++ if (err) { ++ error_report("PVTIME: KVM_GET_DEVICE_ATTR: %s", strerror(errno)); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int kvm_set_stealtime(CPUState *cs) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ int err; ++ struct kvm_device_attr attr = { ++ .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, ++ .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, ++ .addr = (uint64_t)&env->stealtime.guest_addr, ++ }; ++ ++ err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); ++ if (err) { ++ return 0; ++ } ++ ++ err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr); ++ if (err) { ++ error_report("PVTIME: KVM_SET_DEVICE_ATTR %s with gpa "TARGET_FMT_lx, ++ strerror(errno), env->stealtime.guest_addr); ++ return err; ++ } ++ ++ return 0; ++} ++ + static int kvm_loongarch_get_regs_core(CPUState *cs) + { + int ret = 0; +@@ -790,6 +839,11 @@ int kvm_arch_get_registers(CPUState *cs) + return ret; + } + ++ ret = kvm_get_stealtime(cs); ++ if (ret) { ++ return ret; ++ } ++ + ret = kvm_loongarch_get_mpstate(cs); + return ret; + } +@@ -823,6 +877,17 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return ret; + } + ++ if (level >= KVM_PUT_FULL_STATE) { ++ /* ++ * only KVM_PUT_FULL_STATE is required, kvm kernel will clear ++ * guest_addr for KVM_PUT_RESET_STATE ++ */ ++ ret = kvm_set_stealtime(cs); ++ if (ret) { ++ return ret; ++ } ++ } ++ + ret = kvm_loongarch_put_mpstate(cs); + return ret; + } +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index 5d62aabd51..fd69ea05dc 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -188,8 +188,8 @@ static const VMStateDescription vmstate_tlb = { + /* LoongArch CPU state */ + const VMStateDescription vmstate_loongarch_cpu = { + .name = "cpu", +- .version_id = 2, +- .minimum_version_id = 2, ++ .version_id = 3, ++ .minimum_version_id = 3, + .post_load = cpu_post_load, + .pre_save = cpu_pre_save, + .fields = (const VMStateField[]) { +@@ -257,6 +257,8 @@ const VMStateDescription vmstate_loongarch_cpu = { + VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU), + + VMSTATE_UINT64(kvm_state_counter, LoongArchCPU), ++ /* PV steal time */ ++ VMSTATE_UINT64(env.stealtime.guest_addr, LoongArchCPU), + + VMSTATE_END_OF_LIST() + }, +-- +2.39.1 + diff --git a/target-loongarch-Avoid-bits-shift-exceeding-width-of.patch b/target-loongarch-Avoid-bits-shift-exceeding-width-of.patch new file mode 100644 index 0000000000000000000000000000000000000000..af68bf09033976135aa5906b4095a36500bbcd84 --- /dev/null +++ b/target-loongarch-Avoid-bits-shift-exceeding-width-of.patch @@ -0,0 +1,42 @@ +From fa79379bd4c5b72e11f14f24439d5d501b8cc98b Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sat, 14 Sep 2024 14:46:45 +0800 +Subject: [PATCH 55/78] target/loongarch: Avoid bits shift exceeding width of + bool type + +Variable env->cf[i] is defined as bool type, it is treated as int type +with shift operation. However the max possible width is 56 for the shift +operation, exceeding the width of int type. And there is existing api +read_fcc() which is converted to u64 type with bitwise shift, it can be +used to dump fp registers into coredump note segment. + +Resolves: Coverity CID 1561133 +Signed-off-by: Bibo Mao +Reviewed-by: Richard Henderson +Message-Id: <20240914064645.2099169-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/arch_dump.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/target/loongarch/arch_dump.c b/target/loongarch/arch_dump.c +index 4986db970e..d9e1120333 100644 +--- a/target/loongarch/arch_dump.c ++++ b/target/loongarch/arch_dump.c +@@ -97,11 +97,7 @@ static int loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f, + + loongarch_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.fpu)); + note.fpu.fcsr = cpu_to_dump64(s, env->fcsr0); +- +- for (i = 0; i < 8; i++) { +- note.fpu.fcc |= env->cf[i] << (8 * i); +- } +- note.fpu.fcc = cpu_to_dump64(s, note.fpu.fcc); ++ note.fpu.fcc = cpu_to_dump64(s, read_fcc(env)); + + for (i = 0; i < 32; ++i) { + note.fpu.fpr[i] = cpu_to_dump64(s, env->fpr[i].vreg.UD[0]); +-- +2.39.1 + diff --git a/target-loongarch-Fix-cpu_reset-set-wrong-CSR_CRMD.patch b/target-loongarch-Fix-cpu_reset-set-wrong-CSR_CRMD.patch new file mode 100644 index 0000000000000000000000000000000000000000..26d3777b6164497fc285ff388ebafe057bb4339b --- /dev/null +++ b/target-loongarch-Fix-cpu_reset-set-wrong-CSR_CRMD.patch @@ -0,0 +1,42 @@ +From d909e6bfef50fc67708358e455a3b53d869249e6 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 5 Jul 2024 10:18:39 +0800 +Subject: [PATCH 49/78] target/loongarch: Fix cpu_reset set wrong CSR_CRMD + +After cpu_reset, DATF in CSR_CRMD is 0, DATM is 0. +See the manual[1] 6.4. + + [1]: https://github.com/loongson/LoongArch-Documentation/releases/download/2023.04.20/LoongArch-Vol1-v1.10-EN.pdf + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240705021839.1004374-2-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 5bb9e5656a..d8a31929b4 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -554,13 +554,13 @@ static void loongarch_cpu_reset_hold(Object *obj) + env->fcsr0 = 0x0; + + int n; +- /* Set csr registers value after reset */ ++ /* Set csr registers value after reset, see the manual 6.4. */ + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0); +- env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 1); +- env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 1); ++ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 0); ++ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 0); + + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0); + env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0); +-- +2.39.1 + diff --git a/target-loongarch-Implement-lbt-registers-save-restor.patch b/target-loongarch-Implement-lbt-registers-save-restor.patch new file mode 100644 index 0000000000000000000000000000000000000000..e88f971112cff0cd80630c6204348a0923d0ca67 --- /dev/null +++ b/target-loongarch-Implement-lbt-registers-save-restor.patch @@ -0,0 +1,191 @@ +From a7b08284143f7ace3635036bf0366cbec4d52c99 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 29 Sep 2024 15:04:05 +0800 +Subject: [PATCH 58/78] target/loongarch: Implement lbt registers save/restore + function + +Six registers scr0 - scr3, eflags and ftop are added in percpu vmstate. +And two functions kvm_loongarch_get_lbt/kvm_loongarch_put_lbt are added +to save/restore lbt registers. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240929070405.235200-3-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.h | 13 ++++++++ + target/loongarch/kvm/kvm.c | 62 ++++++++++++++++++++++++++++++++++++++ + target/loongarch/machine.c | 24 +++++++++++++++ + 3 files changed, 99 insertions(+) + +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 3e2bcbf608..2f8c5cf2dd 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -18,6 +18,7 @@ + #endif + #include "cpu-csr.h" + #include "cpu-qom.h" ++#include "qapi/qapi-types-common.h" + + #define IOCSRF_TEMP 0 + #define IOCSRF_NODECNT 1 +@@ -290,6 +291,17 @@ enum loongarch_features { + LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */ + }; + ++typedef struct LoongArchBT { ++ /* scratch registers */ ++ uint64_t scr0; ++ uint64_t scr1; ++ uint64_t scr2; ++ uint64_t scr3; ++ /* loongarch eflags */ ++ uint32_t eflags; ++ uint32_t ftop; ++} lbt_t; ++ + typedef struct CPUArchState { + uint64_t gpr[32]; + uint64_t pc; +@@ -297,6 +309,7 @@ typedef struct CPUArchState { + fpr_t fpr[32]; + bool cf[8]; + uint32_t fcsr0; ++ lbt_t lbt; + + uint32_t cpucfg[21]; + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 567404bdb5..118f66f742 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -486,6 +486,58 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs) + return ret; + } + ++static int kvm_loongarch_put_lbt(CPUState *cs) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ uint64_t val; ++ int ret; ++ ++ /* check whether vm support LBT firstly */ ++ if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) { ++ return 0; ++ } ++ ++ /* set six LBT registers including scr0-scr3, eflags, ftop */ ++ ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0); ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1); ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2); ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3); ++ /* ++ * Be cautious, KVM_REG_LOONGARCH_LBT_FTOP is defined as 64-bit however ++ * lbt.ftop is 32-bit; the same with KVM_REG_LOONGARCH_LBT_EFLAGS register ++ */ ++ val = env->lbt.eflags; ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val); ++ val = env->lbt.ftop; ++ ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val); ++ ++ return ret; ++} ++ ++static int kvm_loongarch_get_lbt(CPUState *cs) ++{ ++ CPULoongArchState *env = cpu_env(cs); ++ uint64_t val; ++ int ret; ++ ++ /* check whether vm support LBT firstly */ ++ if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) { ++ return 0; ++ } ++ ++ /* get six LBT registers including scr0-scr3, eflags, ftop */ ++ ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0); ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1); ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2); ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3); ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val); ++ env->lbt.eflags = (uint32_t)val; ++ ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val); ++ env->lbt.ftop = (uint32_t)val; ++ ++ return ret; ++} ++ + void kvm_arch_reset_vcpu(CPUState *cs) + { + CPULoongArchState *env = cpu_env(cs); +@@ -733,6 +785,11 @@ int kvm_arch_get_registers(CPUState *cs) + return ret; + } + ++ ret = kvm_loongarch_get_lbt(cs); ++ if (ret) { ++ return ret; ++ } ++ + ret = kvm_loongarch_get_mpstate(cs); + return ret; + } +@@ -761,6 +818,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return ret; + } + ++ ret = kvm_loongarch_put_lbt(cs); ++ if (ret) { ++ return ret; ++ } ++ + ret = kvm_loongarch_put_mpstate(cs); + return ret; + } +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index 97e1152ffd..5d62aabd51 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -130,6 +130,29 @@ static int cpu_pre_save(void *opaque) + return 0; + } + ++static bool lbt_needed(void *opaque) ++{ ++ LoongArchCPU *cpu = opaque; ++ ++ return !!FIELD_EX64(cpu->env.cpucfg[2], CPUCFG2, LBT_ALL); ++} ++ ++static const VMStateDescription vmstate_lbt = { ++ .name = "cpu/lbt", ++ .version_id = 0, ++ .minimum_version_id = 0, ++ .needed = lbt_needed, ++ .fields = (const VMStateField[]) { ++ VMSTATE_UINT64(env.lbt.scr0, LoongArchCPU), ++ VMSTATE_UINT64(env.lbt.scr1, LoongArchCPU), ++ VMSTATE_UINT64(env.lbt.scr2, LoongArchCPU), ++ VMSTATE_UINT64(env.lbt.scr3, LoongArchCPU), ++ VMSTATE_UINT32(env.lbt.eflags, LoongArchCPU), ++ VMSTATE_UINT32(env.lbt.ftop, LoongArchCPU), ++ VMSTATE_END_OF_LIST() ++ }, ++}; ++ + #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) + static bool tlb_needed(void *opaque) + { +@@ -244,6 +267,7 @@ const VMStateDescription vmstate_loongarch_cpu = { + #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) + &vmstate_tlb, + #endif ++ &vmstate_lbt, + NULL + } + }; +-- +2.39.1 + diff --git a/target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch b/target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch new file mode 100644 index 0000000000000000000000000000000000000000..1d2e4568a81fa9db0554724087a3d2933805edf8 --- /dev/null +++ b/target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch @@ -0,0 +1,81 @@ +From 717faefc8f56490ad94ef69b42c2d2491225ace8 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 28 Apr 2024 11:16:51 +0800 +Subject: [PATCH 43/78] target/loongarch: Put cpucfg operation before CSR + register + +On Loongarch, cpucfg is register for cpu feature, some other registers +depend on cpucfg feature such as perf CSR registers. Here put cpucfg +read/write operations before CSR register, so that KVM knows how many +perf CSR registers are valid from pre-set cpucfg feature information. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240428031651.1354587-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/kvm/kvm.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 5c88270132..407d454919 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -714,22 +714,22 @@ int kvm_arch_get_registers(CPUState *cs) + return ret; + } + +- ret = kvm_loongarch_get_csr(cs); ++ ret = kvm_loongarch_get_cpucfg(cs); + if (ret) { + return ret; + } + +- ret = kvm_loongarch_get_regs_fp(cs); ++ ret = kvm_loongarch_get_csr(cs); + if (ret) { + return ret; + } + +- ret = kvm_loongarch_get_mpstate(cs); ++ ret = kvm_loongarch_get_regs_fp(cs); + if (ret) { + return ret; + } + +- ret = kvm_loongarch_get_cpucfg(cs); ++ ret = kvm_loongarch_get_mpstate(cs); + return ret; + } + +@@ -742,22 +742,22 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return ret; + } + +- ret = kvm_loongarch_put_csr(cs, level); ++ ret = kvm_loongarch_put_cpucfg(cs); + if (ret) { + return ret; + } + +- ret = kvm_loongarch_put_regs_fp(cs); ++ ret = kvm_loongarch_put_csr(cs, level); + if (ret) { + return ret; + } + +- ret = kvm_loongarch_put_mpstate(cs); ++ ret = kvm_loongarch_put_regs_fp(cs); + if (ret) { + return ret; + } + +- ret = kvm_loongarch_put_cpucfg(cs); ++ ret = kvm_loongarch_put_mpstate(cs); + return ret; + } + +-- +2.39.1 + diff --git a/target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch b/target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch new file mode 100644 index 0000000000000000000000000000000000000000..ff55f2317e28dbf985a890169fca5c9ff0f17b15 --- /dev/null +++ b/target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch @@ -0,0 +1,56 @@ +From 3b3fdfa6d5439298b883e2e223fa04a2209612f5 Mon Sep 17 00:00:00 2001 +From: Feiyang Chen +Date: Fri, 28 Jun 2024 13:33:57 +1000 +Subject: [PATCH 47/78] target/loongarch: Remove avail_64 in trans_srai_w() and + simplify it + +Since srai.w is a valid instruction on la32, remove the avail_64 check +and simplify trans_srai_w(). + +Fixes: c0c0461e3a06 ("target/loongarch: Add avail_64 to check la64-only instructions") +Reviewed-by: Richard Henderson +Signed-off-by: Feiyang Chen +Message-Id: <20240628033357.50027-1-chris.chenfeiyang@gmail.com> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/tcg/insn_trans/trans_shift.c.inc | 15 +++------------ + 1 file changed, 3 insertions(+), 12 deletions(-) + +diff --git a/target/loongarch/tcg/insn_trans/trans_shift.c.inc b/target/loongarch/tcg/insn_trans/trans_shift.c.inc +index 2f4bd6ff28..377307785a 100644 +--- a/target/loongarch/tcg/insn_trans/trans_shift.c.inc ++++ b/target/loongarch/tcg/insn_trans/trans_shift.c.inc +@@ -67,19 +67,9 @@ static void gen_rotr_d(TCGv dest, TCGv src1, TCGv src2) + tcg_gen_rotr_tl(dest, src1, t0); + } + +-static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) ++static void gen_sari_w(TCGv dest, TCGv src1, target_long imm) + { +- TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); +- TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO); +- +- if (!avail_64(ctx)) { +- return false; +- } +- +- tcg_gen_sextract_tl(dest, src1, a->imm, 32 - a->imm); +- gen_set_gpr(a->rd, dest, EXT_NONE); +- +- return true; ++ tcg_gen_sextract_tl(dest, src1, imm, 32 - imm); + } + + TRANS(sll_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) +@@ -94,6 +84,7 @@ TRANS(slli_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) + TRANS(slli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) + TRANS(srli_w, ALL, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) + TRANS(srli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) ++TRANS(srai_w, ALL, gen_rri_c, EXT_NONE, EXT_NONE, gen_sari_w) + TRANS(srai_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) + TRANS(rotri_w, 64, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) + TRANS(rotri_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) +-- +2.39.1 + diff --git a/target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch b/target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch new file mode 100644 index 0000000000000000000000000000000000000000..c88286d87536b9d4a1345a86073638b3bdf612cc --- /dev/null +++ b/target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch @@ -0,0 +1,55 @@ +From f677a8f2311e823a87ec70dbdbc07712d54e5a85 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 5 Jul 2024 10:18:38 +0800 +Subject: [PATCH 48/78] target/loongarch: Set CSR_PRCFG1 and CSR_PRCFG2 values + +We set the value of register CSR_PRCFG3, but left out CSR_PRCFG1 +and CSR_PRCFG2. Set CSR_PRCFG1 and CSR_PRCFG2 according to the +default values of the physical machine. + +Signed-off-by: Song Gao +Reviewed-by: Bibo Mao +Message-Id: <20240705021839.1004374-1-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index f89740a5aa..5bb9e5656a 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -472,6 +472,18 @@ static void loongarch_la464_initfn(Object *obj) + env->cpucfg[20] = data; + + env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); ++ ++ env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM, 8); ++ env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, TIMER_BITS, 0x2f); ++ env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, VSMAX, 7); ++ ++ env->CSR_PRCFG2 = 0x3ffff000; ++ ++ env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); ++ env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); ++ env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); ++ env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); ++ + loongarch_cpu_post_init(obj); + } + +@@ -569,11 +581,6 @@ static void loongarch_cpu_reset_hold(Object *obj) + env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0); + env->CSR_TID = cs->cpu_index; + +- env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); +- env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); +- env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); +- env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); +- + for (n = 0; n < 4; n++) { + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0); + env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0); +-- +2.39.1 + diff --git a/target-loongarch-Support-QMP-dump-guest-memory.patch b/target-loongarch-Support-QMP-dump-guest-memory.patch new file mode 100644 index 0000000000000000000000000000000000000000..f7decd79eebf274da501b417c3ea7ba5448ffedd --- /dev/null +++ b/target-loongarch-Support-QMP-dump-guest-memory.patch @@ -0,0 +1,237 @@ +From 2f19b259a16985ce515727c819c3a7eb4f41e6d0 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Thu, 22 Aug 2024 14:52:45 +0800 +Subject: [PATCH 52/78] target/loongarch: Support QMP dump-guest-memory + +Add the support needed for creating prstatus elf notes. This allows +us to use QMP dump-guest-memory. + +Now ELF notes of LoongArch only supports general elf notes, LSX and +LASX is not supported, since it is mainly used to dump guest memory. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Tested-by: Song Gao +Message-Id: <20240822065245.2286214-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/arch_dump.c | 167 +++++++++++++++++++++++++++++++++++ + target/loongarch/cpu.c | 1 + + target/loongarch/internals.h | 2 + + target/loongarch/meson.build | 1 + + 4 files changed, 171 insertions(+) + create mode 100644 target/loongarch/arch_dump.c + +diff --git a/target/loongarch/arch_dump.c b/target/loongarch/arch_dump.c +new file mode 100644 +index 0000000000..4986db970e +--- /dev/null ++++ b/target/loongarch/arch_dump.c +@@ -0,0 +1,167 @@ ++/* ++ * Support for writing ELF notes for LoongArch architectures ++ * ++ * Copyright (c) 2023 Loongarch Technology ++ * ++ * 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 "cpu.h" ++#include "elf.h" ++#include "sysemu/dump.h" ++#include "internals.h" ++ ++/* struct user_pt_regs from arch/loongarch/include/uapi/asm/ptrace.h */ ++struct loongarch_user_regs { ++ uint64_t gpr[32]; ++ uint64_t pad1[1]; ++ /* Special CSR registers. */ ++ uint64_t csr_era; ++ uint64_t csr_badv; ++ uint64_t pad2[10]; ++} 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; ++ /* ++ * 76 == offsetof(struct elf_prstatus, pr_reg) - ++ * offsetof(struct elf_prstatus, pr_ppid) ++ */ ++ char pad2[76]; ++ 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_fp_state from arch/loongarch/include/uapi/asm/ptrace.h */ ++struct loongarch_fpu_struct { ++ uint64_t fpr[32]; ++ uint64_t fcc; ++ unsigned int fcsr; ++} QEMU_PACKED; ++ ++QEMU_BUILD_BUG_ON(sizeof(struct loongarch_fpu_struct) != 268); ++ ++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->fcsr0); ++ ++ for (i = 0; i < 8; i++) { ++ note.fpu.fcc |= env->cf[i] << (8 * i); ++ } ++ note.fpu.fcc = cpu_to_dump64(s, note.fpu.fcc); ++ ++ for (i = 0; i < 32; ++i) { ++ note.fpu.fpr[i] = cpu_to_dump64(s, env->fpr[i].vreg.UD[0]); ++ } ++ ++ 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->gpr[i]); ++ } ++ note.prstatus.pr_reg.csr_era = cpu_to_dump64(s, env->CSR_ERA); ++ note.prstatus.pr_reg.csr_badv = cpu_to_dump64(s, env->CSR_BADV); ++ 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/loongarch/cpu.c b/target/loongarch/cpu.c +index 63d1f65608..d6a13de901 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -861,6 +861,7 @@ static struct TCGCPUOps loongarch_tcg_ops = { + #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, + }; + +diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h +index 944153b180..1a02427627 100644 +--- a/target/loongarch/internals.h ++++ b/target/loongarch/internals.h +@@ -72,5 +72,7 @@ void write_fcc(CPULoongArchState *env, uint64_t val); + int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); + int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n); + void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs); ++int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, ++ int cpuid, DumpState *s); + + #endif +diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build +index e002e9aaf6..7817318287 100644 +--- a/target/loongarch/meson.build ++++ b/target/loongarch/meson.build +@@ -8,6 +8,7 @@ loongarch_ss.add(files( + + loongarch_system_ss = ss.source_set() + loongarch_system_ss.add(files( ++ 'arch_dump.c', + 'cpu_helper.c', + 'loongarch-qmp-cmds.c', + 'machine.c', +-- +2.39.1 + diff --git a/target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch b/target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch new file mode 100644 index 0000000000000000000000000000000000000000..45c70dab5ab92f71d40e7db7832cc44d57c3a240 --- /dev/null +++ b/target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch @@ -0,0 +1,64 @@ +From 43ac751187131f91b043ecf611ec795422b42c6c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 4 Oct 2024 11:59:56 +0200 +Subject: [PATCH 54/78] target/loongarch: Use explicit little-endian LD/ST API +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The LoongArch architecture uses little endianness. Directly +use the little-endian LD/ST API. + +Mechanical change using: + + $ end=le; \ + for acc in uw w l q tul; do \ + sed -i -e "s/ld${acc}_p(/ld${acc}_${end}_p(/" \ + -e "s/st${acc}_p(/st${acc}_${end}_p(/" \ + $(git grep -wlE '(ld|st)t?u?[wlq]_p' target/loongarch/); \ + done + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Message-Id: <20241004163042.85922-13-philmd@linaro.org> +Signed-off-by: Xianglai Li +--- + target/loongarch/gdbstub.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c +index f8e3324bae..cc72680c38 100644 +--- a/target/loongarch/gdbstub.c ++++ b/target/loongarch/gdbstub.c +@@ -68,10 +68,10 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) + int length = 0; + + if (is_la64(env)) { +- tmp = ldq_p(mem_buf); ++ tmp = ldq_le_p(mem_buf); + read_length = 8; + } else { +- tmp = ldl_p(mem_buf); ++ tmp = ldl_le_p(mem_buf); + read_length = 4; + } + +@@ -104,13 +104,13 @@ static int loongarch_gdb_set_fpu(CPULoongArchState *env, + int length = 0; + + if (0 <= n && n < 32) { +- env->fpr[n].vreg.D(0) = ldq_p(mem_buf); ++ env->fpr[n].vreg.D(0) = ldq_le_p(mem_buf); + length = 8; + } else if (32 <= n && n < 40) { + env->cf[n - 32] = ldub_p(mem_buf); + length = 1; + } else if (n == 40) { +- env->fcsr0 = ldl_p(mem_buf); ++ env->fcsr0 = ldl_le_p(mem_buf); + length = 4; + } + return length; +-- +2.39.1 + diff --git a/target-loongarch-fix-Werror-maybe-uninitialized-fals.patch b/target-loongarch-fix-Werror-maybe-uninitialized-fals.patch new file mode 100644 index 0000000000000000000000000000000000000000..b29b7e3792dbb7cc4fbe8014e5f0830c36ca892c --- /dev/null +++ b/target-loongarch-fix-Werror-maybe-uninitialized-fals.patch @@ -0,0 +1,73 @@ +From 1b5bad7f9b10bba438fe12082c8aa29805c03092 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 24 Sep 2024 15:49:47 +0400 +Subject: [PATCH 53/78] target/loongarch: fix -Werror=maybe-uninitialized + false-positive +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../target/loongarch/gdbstub.c:55:20: error: ‘val’ may be used uninitialized [-Werror=maybe-uninitialized] + 55 | return gdb_get_reg32(mem_buf, val); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +../target/loongarch/gdbstub.c:39:18: note: ‘val’ was declared here + 39 | uint64_t val; + +Signed-off-by: Marc-André Lureau +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Xianglai Li +--- + target/loongarch/gdbstub.c | 29 +++++++++++++++-------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c +index 5fc2f19e96..f8e3324bae 100644 +--- a/target/loongarch/gdbstub.c ++++ b/target/loongarch/gdbstub.c +@@ -33,28 +33,29 @@ void write_fcc(CPULoongArchState *env, uint64_t val) + + int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) + { +- LoongArchCPU *cpu = LOONGARCH_CPU(cs); +- CPULoongArchState *env = &cpu->env; +- uint64_t val; +- +- if (0 <= n && n < 32) { +- val = env->gpr[n]; +- } else if (n == 32) { +- /* orig_a0 */ +- val = 0; +- } else if (n == 33) { +- val = env->pc; +- } else if (n == 34) { +- val = env->CSR_BADV; +- } ++ CPULoongArchState *env = cpu_env(cs); + + if (0 <= n && n <= 34) { ++ uint64_t val; ++ ++ if (n < 32) { ++ val = env->gpr[n]; ++ } else if (n == 32) { ++ /* orig_a0 */ ++ val = 0; ++ } else if (n == 33) { ++ val = env->pc; ++ } else /* if (n == 34) */ { ++ val = env->CSR_BADV; ++ } ++ + if (is_la64(env)) { + return gdb_get_reg64(mem_buf, val); + } else { + return gdb_get_reg32(mem_buf, val); + } + } ++ + return 0; + } + +-- +2.39.1 + diff --git a/target-loongarch-kvm-Add-software-breakpoint-support-sync-upstream.patch b/target-loongarch-kvm-Add-software-breakpoint-support-sync-upstream.patch new file mode 100644 index 0000000000000000000000000000000000000000..1b65cf8ce8c46ea336dd6482ff29d29ef07ccf46 --- /dev/null +++ b/target-loongarch-kvm-Add-software-breakpoint-support-sync-upstream.patch @@ -0,0 +1,39 @@ +From 9a6ef31fa2fcf1f1257fb849cc6cabe2b4c440e0 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Fri, 7 Jun 2024 11:50:16 +0800 +Subject: [PATCH 46/78] target/loongarch/kvm: Add software breakpoint support + +With KVM virtualization, debug exception is injected to guest kernel +rather than host for normal break intruction. Here hypercall +instruction with special code is used for sw breakpoint usage, +and detailed instruction comes from kvm kernel with user API +KVM_REG_LOONGARCH_DEBUG_INST. + +Now only software breakpoint is supported, and it is allowed to +insert/remove software breakpoint. We can debug guest kernel with gdb +method after kernel is loaded, hardware breakpoint will be added in later. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Tested-by: Song Gao +Message-Id: <20240607035016.2975799-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + configs/targets/loongarch64-softmmu.mak | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak +index f23780fdd8..0034c33620 100644 +--- a/configs/targets/loongarch64-softmmu.mak ++++ b/configs/targets/loongarch64-softmmu.mak +@@ -1,5 +1,6 @@ + TARGET_ARCH=loongarch64 + TARGET_BASE_ARCH=loongarch ++TARGET_KVM_HAVE_GUEST_DEBUG=y + TARGET_SUPPORTS_MTTCG=y + TARGET_XML_FILES= gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml + TARGET_NEED_FDT=y +-- +2.39.1 + diff --git a/target-loongarch-kvm-Add-vCPU-reset-function.patch b/target-loongarch-kvm-Add-vCPU-reset-function.patch new file mode 100644 index 0000000000000000000000000000000000000000..f5c5990ffb6e5d4d68dcb9034190108e1dc76abc --- /dev/null +++ b/target-loongarch-kvm-Add-vCPU-reset-function.patch @@ -0,0 +1,68 @@ +From ad00cc7da8ab03d6d612a3bd7ec0c4b7af594894 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Thu, 22 Aug 2024 10:28:27 +0800 +Subject: [PATCH 51/78] target/loongarch/kvm: Add vCPU reset function + +KVM provides interface KVM_REG_LOONGARCH_VCPU_RESET to reset vCPU, +it can be used to clear internal state about kvm kernel. vCPU reset +function is added here for kvm mode. + +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240822022827.2273534-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 2 +- + target/loongarch/kvm/kvm.c | 5 ++++- + target/loongarch/kvm/kvm_loongarch.h | 2 +- + 3 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 2038984d02..63d1f65608 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -608,7 +608,7 @@ static void loongarch_cpu_reset_hold(Object *obj) + memset(env->tlb, 0, sizeof(env->tlb)); + #endif + if (kvm_enabled()) { +- kvm_arch_reset_vcpu(env); ++ kvm_arch_reset_vcpu(cs); + } + #endif + +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 407d454919..90c8379c46 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -485,9 +485,12 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs) + return ret; + } + +-void kvm_arch_reset_vcpu(CPULoongArchState *env) ++void kvm_arch_reset_vcpu(CPUState *cs) + { ++ CPULoongArchState *env = cpu_env(cs); ++ + env->mp_state = KVM_MP_STATE_RUNNABLE; ++ kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, 0); + } + + static int kvm_loongarch_get_mpstate(CPUState *cs) +diff --git a/target/loongarch/kvm/kvm_loongarch.h b/target/loongarch/kvm/kvm_loongarch.h +index 551878a725..8482f9308d 100644 +--- a/target/loongarch/kvm/kvm_loongarch.h ++++ b/target/loongarch/kvm/kvm_loongarch.h +@@ -11,8 +11,8 @@ + #define QEMU_KVM_LOONGARCH_H + + int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level); +-void kvm_arch_reset_vcpu(CPULoongArchState *env); + int kvm_loongarch_put_pvtime(LoongArchCPU *cpu); + int kvm_loongarch_get_pvtime(LoongArchCPU *cpu); ++void kvm_arch_reset_vcpu(CPUState *cs); + + #endif +-- +2.39.1 + diff --git a/target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch b/target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1a483ed802989a6b592c06a468fff69b775b958 --- /dev/null +++ b/target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch @@ -0,0 +1,40 @@ +From 520e792f674a7ab192a9237519c4e0c8f50abc71 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Wed, 8 May 2024 10:47:32 +0800 +Subject: [PATCH 44/78] target/loongarch/kvm: Fix VM recovery from disk + failures + +vmstate does not save kvm_state_conter, +which can cause VM recovery from disk to fail. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Song Gao +Acked-by: Peter Xu +Message-Id: <20240508024732.3127792-1-gaosong@loongson.cn> +Signed-off-by: Xianglai Li +--- + target/loongarch/machine.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c +index 4bbf495d6b..97e1152ffd 100644 +--- a/target/loongarch/machine.c ++++ b/target/loongarch/machine.c +@@ -165,11 +165,11 @@ static const VMStateDescription vmstate_tlb = { + /* LoongArch CPU state */ + const VMStateDescription vmstate_loongarch_cpu = { + .name = "cpu", +- .version_id = 1, +- .minimum_version_id = 1, ++ .version_id = 2, ++ .minimum_version_id = 2, + .post_load = cpu_post_load, + .pre_save = cpu_pre_save, +- .fields = (VMStateField[]) { ++ .fields = (const VMStateField[]) { + VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32), + VMSTATE_UINTTL(env.pc, LoongArchCPU), + +-- +2.39.1 + diff --git a/target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch b/target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch new file mode 100644 index 0000000000000000000000000000000000000000..82b1b18c0a0dbddd0f093b56bdb53bf74a55c358 --- /dev/null +++ b/target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch @@ -0,0 +1,233 @@ +From b87b4782e8147fd481becd946ca909edaaa58b41 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 18 Sep 2024 16:23:15 +0800 +Subject: [PATCH 59/78] target/loongarch/kvm: Implement LoongArch PMU extension + +Implement PMU extension for LoongArch kvm mode. Use OnOffAuto type +variable pmu to check the PMU feature. If the PMU Feature is not supported +with KVM host, it reports error if there is pmu=on command line. + +If there is no any command line about pmu parameter, it checks whether +KVM host supports the PMU Feature and set the corresponding value in cpucfg. + +This patch is based on lbt patch located at + https://lore.kernel.org/qemu-devel/20240904061859.86615-1-maobibo@loongson.cn + +Co-developed-by: Song Gao +Signed-off-by: Bibo Mao +Reviewed-by: Song Gao +Message-Id: <20240918082315.2345034-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + target/loongarch/cpu.c | 63 +++++++-------------------- + target/loongarch/cpu.h | 2 + + target/loongarch/kvm/kvm.c | 41 +++++++++++++++++ + target/loongarch/loongarch-qmp-cmds.c | 2 +- + 4 files changed, 59 insertions(+), 49 deletions(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index a57067938d..2ee1d63989 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -695,58 +695,28 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp) + } + } + +-static bool loongarch_get_pmu(Object *obj, Error **errp) +-{ +- LoongArchCPU *cpu = LOONGARCH_CPU(obj); +- +- return !!(FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP)); +-} +- +-static void loongarch_set_pmu(Object *obj, bool value, Error **errp) +-{ +- LoongArchCPU *cpu = LOONGARCH_CPU(obj); +- +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, value); +-} +- +-static void loongarch_get_pmnum(Object *obj, Visitor *v, +- const char *name, void *opaque, +- Error **errp) ++static bool loongarch_get_lbt(Object *obj, Error **errp) + { +- LoongArchCPU *cpu = LOONGARCH_CPU(obj); +- uint32_t value = FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMNUM); +- +- visit_type_uint32(v, name, &value, errp); ++ return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF; + } + +-static void loongarch_set_pmnum(Object *obj, Visitor *v, +- const char *name, void *opaque, +- Error **errp) ++static void loongarch_set_lbt(Object *obj, bool value, Error **errp) + { + LoongArchCPU *cpu = LOONGARCH_CPU(obj); +- uint32_t *value= opaque; + +- if (!visit_type_uint32(v, name, value, errp)) { +- return; +- } +- if ((*value <= PMNUM_MAX) && (*value > 0)) { +- cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMNUM, *value -1); +- } else { +- error_report("Performance counter number need be in [1- %d]\n", PMNUM_MAX); +- exit(EXIT_FAILURE); +- } ++ cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; + } + +-static bool loongarch_get_lbt(Object *obj, Error **errp) ++static bool loongarch_get_pmu(Object *obj, Error **errp) + { +- return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF; ++ return LOONGARCH_CPU(obj)->pmu != ON_OFF_AUTO_OFF; + } + +-static void loongarch_set_lbt(Object *obj, bool value, Error **errp) ++static void loongarch_set_pmu(Object *obj, bool value, Error **errp) + { + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + +- cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; ++ cpu->pmu = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; + } + + void loongarch_cpu_post_init(Object *obj) +@@ -759,21 +729,18 @@ void loongarch_cpu_post_init(Object *obj) + loongarch_set_lasx); + + if (kvm_enabled()) { +- object_property_add_bool(obj, "pmu", loongarch_get_pmu, +- loongarch_set_pmu); +- if (FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP)) { +- uint32_t value = 4; +- object_property_add(obj, "pmnum", "uint32", +- loongarch_get_pmnum, +- loongarch_set_pmnum, NULL, +- (void *)&value); +- } +- + cpu->lbt = ON_OFF_AUTO_AUTO; + object_property_add_bool(obj, "lbt", loongarch_get_lbt, + loongarch_set_lbt); + object_property_set_description(obj, "lbt", + "Set off to disable Binary Tranlation."); ++ ++ cpu->pmu = ON_OFF_AUTO_AUTO; ++ object_property_add_bool(obj, "pmu", loongarch_get_pmu, ++ loongarch_set_pmu); ++ object_property_set_description(obj, "pmu", ++ "Set off to performance monitor unit."); ++ + } else { + cpu->lbt = ON_OFF_AUTO_OFF; + } +diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h +index 2f8c5cf2dd..8ff00d17e1 100644 +--- a/target/loongarch/cpu.h ++++ b/target/loongarch/cpu.h +@@ -289,6 +289,7 @@ typedef struct LoongArchTLB LoongArchTLB; + + enum loongarch_features { + LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */ ++ LOONGARCH_FEATURE_PMU, + }; + + typedef struct LoongArchBT { +@@ -407,6 +408,7 @@ struct ArchCPU { + QEMUTimer timer; + uint32_t phy_id; + OnOffAuto lbt; ++ OnOffAuto pmu; + + /* 'compatible' string for this CPU for Linux device trees */ + const char *dtb_compatible; +diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c +index 118f66f742..8b0f86a201 100644 +--- a/target/loongarch/kvm/kvm.c ++++ b/target/loongarch/kvm/kvm.c +@@ -870,9 +870,18 @@ static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature) + attr.attr = KVM_LOONGARCH_VM_FEAT_MIPSBT; + ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); + return (ret == 0); ++ ++ case LOONGARCH_FEATURE_PMU: ++ attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; ++ attr.attr = KVM_LOONGARCH_VM_FEAT_PMU; ++ ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); ++ return (ret == 0); ++ + default: + return false; + } ++ ++ return false; + } + + static int kvm_cpu_check_lbt(CPUState *cs, Error **errp) +@@ -896,6 +905,32 @@ static int kvm_cpu_check_lbt(CPUState *cs, Error **errp) + return 0; + } + ++static int kvm_cpu_check_pmu(CPUState *cs, Error **errp) ++{ ++ LoongArchCPU *cpu = LOONGARCH_CPU(cs); ++ CPULoongArchState *env = cpu_env(cs); ++ bool kvm_supported; ++ ++ kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PMU); ++ if (cpu->pmu == ON_OFF_AUTO_ON) { ++ if (!kvm_supported) { ++ error_setg(errp, "'pmu' feature not supported by KVM on the host"); ++ return -ENOTSUP; ++ } ++ } else if (cpu->pmu != ON_OFF_AUTO_AUTO) { ++ /* disable pmu if ON_OFF_AUTO_OFF is set */ ++ kvm_supported = false; ++ } ++ ++ if (kvm_supported) { ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMP, 1); ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMNUM, 3); ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMBITS, 63); ++ env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, UPM, 1); ++ } ++ return 0; ++} ++ + int kvm_arch_init_vcpu(CPUState *cs) + { + uint64_t val; +@@ -913,6 +948,12 @@ int kvm_arch_init_vcpu(CPUState *cs) + if (ret < 0) { + error_report_err(local_err); + } ++ ++ ret = kvm_cpu_check_pmu(cs, &local_err); ++ if (ret < 0) { ++ error_report_err(local_err); ++ } ++ + return ret; + } + +diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c +index 644b528824..dc78a3ffa2 100644 +--- a/target/loongarch/loongarch-qmp-cmds.c ++++ b/target/loongarch/loongarch-qmp-cmds.c +@@ -42,7 +42,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) + } + + static const char *cpu_model_advertised_features[] = { +- "lsx", "lasx", "lbt", "pmu", "pmnum", NULL ++ "lsx", "lasx", "lbt", "pmu", NULL + }; + + CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, +-- +2.39.1 + diff --git a/tests-libqos-Add-loongarch-virt-machine-node.patch b/tests-libqos-Add-loongarch-virt-machine-node.patch new file mode 100644 index 0000000000000000000000000000000000000000..31abdbcf06230a8a121800b2390ce906aba877ff --- /dev/null +++ b/tests-libqos-Add-loongarch-virt-machine-node.patch @@ -0,0 +1,183 @@ +From 254957f2de480901a063759d762d4b1eca5b5bb0 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 28 May 2024 16:20:53 +0800 +Subject: [PATCH 28/78] tests/libqos: Add loongarch virt machine node + +Add loongarch virt machine to the graph. It is a modified copy of +the existing riscv virtmachine in riscv-virt-machine.c + +It contains a generic-pcihost controller, and an extra function +loongarch_config_qpci_bus() to configure GPEX pci host controller +information, such as ecam and pio_base addresses. + +Also hotplug handle checking about TYPE_VIRTIO_IOMMU_PCI device is +added on loongarch virt machine, since virtio_mmu_pci device requires +it. + +Signed-off-by: Bibo Mao +Acked-by: Thomas Huth +Message-Id: <20240528082053.938564-1-maobibo@loongson.cn> +Signed-off-by: Song Gao +Signed-off-by: Xianglai Li +--- + hw/loongarch/virt.c | 2 + + tests/qtest/libqos/loongarch-virt-machine.c | 114 ++++++++++++++++++++ + tests/qtest/libqos/meson.build | 1 + + 3 files changed, 117 insertions(+) + create mode 100644 tests/qtest/libqos/loongarch-virt-machine.c + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 11ba879e52..f7874bccf9 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -47,6 +47,7 @@ + #include "sysemu/tpm.h" + #include "sysemu/block-backend.h" + #include "hw/block/flash.h" ++#include "hw/virtio/virtio-iommu.h" + #include "qemu/error-report.h" + + static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms) +@@ -1302,6 +1303,7 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine, + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (device_is_dynamic_sysbus(mc, dev) || ++ object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) || + memhp_type_supported(dev)) { + return HOTPLUG_HANDLER(machine); + } +diff --git a/tests/qtest/libqos/loongarch-virt-machine.c b/tests/qtest/libqos/loongarch-virt-machine.c +new file mode 100644 +index 0000000000..c12089c015 +--- /dev/null ++++ b/tests/qtest/libqos/loongarch-virt-machine.c +@@ -0,0 +1,114 @@ ++/* ++ * libqos driver framework ++ * ++ * Copyright (c) 2018 Emanuele Giuseppe Esposito ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License version 2.1 as published by the Free Software Foundation. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see ++ */ ++ ++#include "qemu/osdep.h" ++#include "../libqtest.h" ++#include "qemu/module.h" ++#include "libqos-malloc.h" ++#include "qgraph.h" ++#include "virtio-mmio.h" ++#include "generic-pcihost.h" ++#include "hw/pci/pci_regs.h" ++ ++#define LOONGARCH_PAGE_SIZE 0x1000 ++#define LOONGARCH_VIRT_RAM_ADDR 0x100000 ++#define LOONGARCH_VIRT_RAM_SIZE 0xFF00000 ++ ++#define LOONGARCH_VIRT_PIO_BASE 0x18000000 ++#define LOONGARCH_VIRT_PCIE_PIO_OFFSET 0x4000 ++#define LOONGARCH_VIRT_PCIE_PIO_LIMIT 0x10000 ++#define LOONGARCH_VIRT_PCIE_ECAM_BASE 0x20000000 ++#define LOONGARCH_VIRT_PCIE_MMIO32_BASE 0x40000000 ++#define LOONGARCH_VIRT_PCIE_MMIO32_LIMIT 0x80000000 ++ ++typedef struct QVirtMachine QVirtMachine; ++ ++struct QVirtMachine { ++ QOSGraphObject obj; ++ QGuestAllocator alloc; ++ QVirtioMMIODevice virtio_mmio; ++ QGenericPCIHost bridge; ++}; ++ ++static void virt_destructor(QOSGraphObject *obj) ++{ ++ QVirtMachine *machine = (QVirtMachine *) obj; ++ alloc_destroy(&machine->alloc); ++} ++ ++static void *virt_get_driver(void *object, const char *interface) ++{ ++ QVirtMachine *machine = object; ++ if (!g_strcmp0(interface, "memory")) { ++ return &machine->alloc; ++ } ++ ++ fprintf(stderr, "%s not present in loongarch/virtio\n", interface); ++ g_assert_not_reached(); ++} ++ ++static QOSGraphObject *virt_get_device(void *obj, const char *device) ++{ ++ QVirtMachine *machine = obj; ++ if (!g_strcmp0(device, "generic-pcihost")) { ++ return &machine->bridge.obj; ++ } else if (!g_strcmp0(device, "virtio-mmio")) { ++ return &machine->virtio_mmio.obj; ++ } ++ ++ fprintf(stderr, "%s not present in loongarch/virt\n", device); ++ g_assert_not_reached(); ++} ++ ++static void loongarch_config_qpci_bus(QGenericPCIBus *qpci) ++{ ++ qpci->gpex_pio_base = LOONGARCH_VIRT_PIO_BASE; ++ qpci->bus.pio_alloc_ptr = LOONGARCH_VIRT_PCIE_PIO_OFFSET; ++ qpci->bus.pio_limit = LOONGARCH_VIRT_PCIE_PIO_LIMIT; ++ qpci->bus.mmio_alloc_ptr = LOONGARCH_VIRT_PCIE_MMIO32_BASE; ++ qpci->bus.mmio_limit = LOONGARCH_VIRT_PCIE_MMIO32_LIMIT; ++ qpci->ecam_alloc_ptr = LOONGARCH_VIRT_PCIE_ECAM_BASE; ++} ++ ++static void *qos_create_machine_loongarch_virt(QTestState *qts) ++{ ++ QVirtMachine *machine = g_new0(QVirtMachine, 1); ++ ++ alloc_init(&machine->alloc, 0, ++ LOONGARCH_VIRT_RAM_ADDR, ++ LOONGARCH_VIRT_RAM_ADDR + LOONGARCH_VIRT_RAM_SIZE, ++ LOONGARCH_PAGE_SIZE); ++ ++ qos_create_generic_pcihost(&machine->bridge, qts, &machine->alloc); ++ loongarch_config_qpci_bus(&machine->bridge.pci); ++ ++ machine->obj.get_device = virt_get_device; ++ machine->obj.get_driver = virt_get_driver; ++ machine->obj.destructor = virt_destructor; ++ return machine; ++} ++ ++static void virt_machine_register_nodes(void) ++{ ++ qos_node_create_machine_args("loongarch64/virt", ++ qos_create_machine_loongarch_virt, ++ " -cpu la464"); ++ qos_node_contains("loongarch64/virt", "generic-pcihost", NULL); ++} ++ ++libqos_init(virt_machine_register_nodes); +diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build +index 90aae42a22..482c9b2aab 100644 +--- a/tests/qtest/libqos/meson.build ++++ b/tests/qtest/libqos/meson.build +@@ -60,6 +60,7 @@ libqos_srcs = files( + 'arm-xilinx-zynq-a9-machine.c', + 'ppc64_pseries-machine.c', + 'x86_64_pc-machine.c', ++ 'loongarch-virt-machine.c', + ) + + if have_virtfs +-- +2.39.1 +