From 9a2f1b5d0729e8a45785f192964c9a2fe0e143e9 Mon Sep 17 00:00:00 2001 From: Jiabo Feng Date: Thu, 12 Dec 2024 16:05:09 +0800 Subject: [PATCH] QEMU update to version 8.2.0-26: - fix compile error on loongarch - vdpa-dev: Fix initialisation order to restore VDUSE compatibility - tcg: Allow top bit of SIMD_DATA_BITS to be set in simd_desc() - migration: fix-possible-int-overflow - target/m68k: Map FPU exceptions to FPSR register - qemu-options: Fix CXL Fixed Memory Window interleave-granularity typo - hvf: arm: Fix encodings for ID_AA64PFR1_EL1 and debug System registers - hw/intc/arm_gic: Fix handling of NS view of GICC_APR - qio: Inherit follow_coroutine_ctx across TLS - target/riscv: Fix the element agnostic function problem - accel/tcg: Fix typo causing tb->page_addr[1] to not be recorded - tcg/loongarch64: Fix tcg_out_movi vs some pcrel pointers - migration: Fix file migration with fdset - ui/vnc: don't return an empty SASL mechlist to the client - target/arm: Fix FJCVTZS vs flush-to-zero - hw/ppc/e500: Prefer QOM cast - sphinx/qapidoc: Fix to generate doc for explicit, unboxed arguments - hw/ppc/e500: Remove unused "irqs" parameter - hw/ppc/e500: Add missing device tree properties to i2c controller node - hw/i386/amd_iommu: Don't leak memory in amdvi_update_iotlb() - hw/arm/mps2-tz.c: fix RX/TX interrupts order - target/i386: csv: Add support to migrate the incoming context for CSV3 guest - target/i386: csv: Add support to migrate the outgoing context for CSV3 guest - target/i386: csv: Add support to migrate the incoming page for CSV3 guest - target/i386: csv: Add support to migrate the outgoing page for CSV3 guest - linux-headers: update kernel headers to include CSV3 migration cmds - vfio: Only map shared region for CSV3 virtual machine - vga: Force full update for CSV3 guest - target/i386: csv: Load initial image to private memory for CSV3 guest - target/i386: csv: Do not register/unregister guest secure memory for CSV3 guest - target/i386: cpu: Populate CPUID 0x8000_001F when CSV3 is active - target/i386: csv: Add command to load vmcb to CSV3 guest memory - target/i386: csv: Add command to load data to CSV3 guest memory - target/i386: csv: Add command to initialize CSV3 context - target/i386: csv: Add CSV3 context - next-kbd: convert to use qemu_input_handler_register() - 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 - qemu/bswap: Undefine CPU_CONVERT() once done - exec/memop: Remove unused memop_big_endian() helper - hw/nvme: fix handling of over-committed queues - 9pfs: fix crash on 'Treaddir' request - hw/misc/psp: Pin the hugepage memory specified by mem2 during use for psp - hw/misc: support tkm use mem2 memory - hw/i386: add mem2 option for qemu - kvm: add support for guest physical bits - target/i386: add guest-phys-bits cpu property Signed-off-by: Jiabo Feng --- 9pfs-fix-crash-on-Treaddir-request.patch | 64 + ...mmon-KVM-vCPU-creation-parking-c-new.patch | 234 +++ ...l-Fixes-the-missing-break-in-vCPU-un.patch | 45 + ...po-causing-tb-page_addr-1-to-not-be-.patch | 52 + ...emove-unused-memop_big_endian-helper.patch | 39 + fix-compile-error-on-loongarch.patch | 27 + ...er-function-to-unregister-GDB-regist.patch | 85 ++ ...dings-for-ID_AA64PFR1_EL1-and-debug-.patch | 211 +++ ...l-dev-MMIO-region-len-macro-to-c-new.patch | 48 + ...GED-framework-to-support-vCPU-Ho-new.patch | 126 ++ ...PUs-AML-with-cpu-ctrl-dev-change-new.patch | 53 + ...mps2-tz.c-fix-RX-TX-interrupts-order.patch | 50 + ...-build.c-Migrate-SPCR-creation-to-co.patch | 236 +++ hw-i386-add-mem2-option-for-qemu.patch | 324 ++++ ...u-Don-t-leak-memory-in-amdvi_update_.patch | 50 + ...Fix-handling-of-NS-view-of-GICC_APR-.patch | 61 + hw-loongarch-Add-KVM-IPI-device-support.patch | 399 +++++ ...ngarch-Add-KVM-extioi-device-support.patch | 383 +++++ ...garch-Add-KVM-pch-msi-device-support.patch | 135 ++ ...garch-Add-KVM-pch-pic-device-support.patch | 486 ++++++ ...-VM-mode-in-IOCSR-feature-register-i.patch | 48 + ...oongarch-Add-acpi-SPCR-table-support.patch | 81 + ...arch-Add-cells-missing-from-rtc-node.patch | 55 + ...rch-Add-cells-missing-from-uart-node.patch | 51 + hw-loongarch-Add-init_cmdline.patch | 116 ++ hw-loongarch-Add-load-initrd.patch | 63 + hw-loongarch-Add-slave-cpu-boot_code.patch | 102 ++ ...ch-Change-the-tpm-support-by-default.patch | 46 + ...h-Fix-length-for-lowram-in-ACPI-SRAT.patch | 38 + hw-loongarch-Init-efi_boot_memmap-table.patch | 168 +++ hw-loongarch-Init-efi_fdt-table.patch | 104 ++ hw-loongarch-Init-efi_initrd-table.patch | 100 ++ hw-loongarch-Init-efi_system_table.patch | 124 ++ ...ngarch-Move-boot-functions-to-boot.c.patch | 389 +++++ ...fine-acpi-srat-table-for-numa-memory.patch | 107 ++ ...h-Refine-default-numa-id-calculation.patch | 56 + ...ine-fadt-memory-table-for-numa-memor.patch | 105 ++ hw-loongarch-Refine-fwcfg-memory-map.patch | 119 ++ ...rch-Refine-system-dram-memory-region.patch | 109 ++ ...ove-default-enable-with-VIRTIO_VGA-d.patch | 37 + ...move-minimum-and-default-memory-size.patch | 45 + ...ame-LOONGARCH_MACHINE-with-LOONGARCH.patch | 187 +++ ...ame-LoongArchMachineState-with-Loong.patch | 1323 +++++++++++++++++ ...t-Use-warn_report-when-no-kernel-fil.patch | 45 + ...arch-boot.c-fix-out-of-bound-reading.patch | 34 + hw-loongarch-clean-code.patch | 196 +++ ...-adds-Extend-I-O-Interrupt-Controlle.patch | 90 ++ ...t-adds-cpu-interrupt-controller-node.patch | 68 + ...oongarch-fdt-adds-pch_msi-Controller.patch | 92 ++ ...oongarch-fdt-adds-pch_pic-Controller.patch | 89 ++ hw-loongarch-fdt-adds-pcie-irq_map-node.patch | 136 ++ ...garch-fdt-remove-unused-irqchip-node.patch | 66 + hw-loongarch-fix-cpu-hotplug-reset.patch | 50 + hw-loongarch-move-memory-map-to-boot.c.patch | 112 ++ ...ngarch-virt-Add-CPU-topology-support.patch | 277 ++++ ...t-Add-FDT-table-support-with-acpi-ge.patch | 83 ++ ...arch-virt-Add-basic-CPU-plug-support.patch | 345 +++++ ...t-Add-description-for-virt-machine-t.patch | 44 + ...ngarch-virt-Remove-unused-assignment.patch | 58 + ...t-Update-the-ACPI-table-for-hotplug-.patch | 141 ++ ...t-Use-MemTxAttrs-interface-for-misc-.patch | 75 + ...ongarch-virt-pass-random-seed-to-fdt.patch | 65 + ...ch-virt-support-up-to-4-serial-ports.patch | 171 +++ ...the-hugepage-memory-specified-by-mem.patch | 212 +++ hw-misc-support-tkm-use-mem2-memory.patch | 123 ++ ...ix-handling-of-over-committed-queues.patch | 102 ++ ...missing-device-tree-properties-to-i2.patch | 44 + hw-ppc-e500-Prefer-QOM-cast.patch | 44 + ...pc-e500-Remove-unused-irqs-parameter.patch | 44 + kvm-add-support-for-guest-physical-bits.patch | 111 ++ ...ongarch-Add-kvm_para.h-and-unistd_64.patch | 38 + ...date-kernel-headers-to-include-CSV3-.patch | 79 + loongarch-switch-boards-to-default-y.patch | 59 + migration-Fix-file-migration-with-fdset.patch | 65 + migration-fix-possible-int-overflow.patch | 35 + ...t-to-use-qemu_input_handler_register.patch | 224 +++ ...er-function-to-destroy-CPU-AddressSp.patch | 91 ++ ...bswap-Undefine-CPU_CONVERT-once-done.patch | 37 + ...-CXL-Fixed-Memory-Window-interleave-.patch | 48 + qemu.spec | 248 ++- ...erit-follow_coroutine_ctx-across-TLS.patch | 121 ++ ...ix-to-generate-doc-for-explicit-unbo.patch | 156 ++ sync-loongarch-linux-headers.patch | 96 ++ target-arm-Fix-FJCVTZS-vs-flush-to-zero.patch | 106 ++ ...386-add-guest-phys-bits-cpu-property.patch | 106 ++ ...Populate-CPUID-0x8000_001F-when-CSV3.patch | 41 + target-i386-csv-Add-CSV3-context.patch | 85 ++ ...Add-command-to-initialize-CSV3-conte.patch | 201 +++ ...Add-command-to-load-data-to-CSV3-gue.patch | 166 +++ ...Add-command-to-load-vmcb-to-CSV3-gue.patch | 108 ++ ...support-to-migrate-the-incoming--new.patch | 110 ++ ...Add-support-to-migrate-the-incoming-.patch | 205 +++ ...support-to-migrate-the-outgoing--new.patch | 139 ++ ...Add-support-to-migrate-the-outgoing-.patch | 452 ++++++ ...Do-not-register-unregister-guest-sec.patch | 35 + ...Load-initial-image-to-private-memory.patch | 52 + ...-Add-TCG-macro-in-structure-CPUArchS.patch | 233 +++ ...-Add-compatible-support-about-VM-reb.patch | 49 + ...-Add-loongarch-vector-property-uncon.patch | 45 + ...-Add-loongson-binary-translation-fea.patch | 198 +++ ...-Add-steal-time-support-on-migration.patch | 150 ++ ...-Avoid-bits-shift-exceeding-width-of.patch | 41 + ...rch-Fix-cpu_reset-set-wrong-CSR_CRMD.patch | 41 + ...-Implement-lbt-registers-save-restor.patch | 190 +++ ...-Put-cpucfg-operation-before-CSR-reg.patch | 79 + ...-Remove-avail_64-in-trans_srai_w-and.patch | 55 + ...-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch | 54 + ...ngarch-Support-QMP-dump-guest-memory.patch | 236 +++ ...-Use-explicit-little-endian-LD-ST-AP.patch | 63 + ...-fix-Werror-maybe-uninitialized-fals.patch | 72 + ...-Add-software-breakpoint-support-new.patch | 38 + ...oongarch-kvm-Add-vCPU-reset-function.patch | 67 + ...-kvm-Fix-VM-recovery-from-disk-failu.patch | 38 + ...-kvm-Implement-LoongArch-PMU-extensi.patch | 232 +++ ...-Map-FPU-exceptions-to-FPSR-register.patch | 218 +++ ...-the-element-agnostic-function-probl.patch | 60 + ...t-of-SIMD_DATA_BITS-to-be-set-in-sim.patch | 69 + ...Fix-tcg_out_movi-vs-some-pcrel-point.patch | 77 + ...bqos-Add-loongarch-virt-machine-node.patch | 182 +++ ...urn-an-empty-SASL-mechlist-to-the-cl.patch | 47 + ...tialisation-order-to-restore-VDUSE-c.patch | 180 +++ ...ared-region-for-CSV3-virtual-machine.patch | 397 +++++ vga-Force-full-update-for-CSV3-guest.patch | 129 ++ 123 files changed, 15940 insertions(+), 1 deletion(-) create mode 100644 9pfs-fix-crash-on-Treaddir-request.patch create mode 100644 accel-kvm-Extract-common-KVM-vCPU-creation-parking-c-new.patch create mode 100644 accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch create mode 100644 accel-tcg-Fix-typo-causing-tb-page_addr-1-to-not-be-.patch create mode 100644 exec-memop-Remove-unused-memop_big_endian-helper.patch create mode 100644 fix-compile-error-on-loongarch.patch create mode 100644 gdbstub-Add-helper-function-to-unregister-GDB-regist.patch create mode 100644 hvf-arm-Fix-encodings-for-ID_AA64PFR1_EL1-and-debug-.patch create mode 100644 hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c-new.patch create mode 100644 hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho-new.patch create mode 100644 hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change-new.patch create mode 100644 hw-arm-mps2-tz.c-fix-RX-TX-interrupts-order.patch create mode 100644 hw-arm-virt-acpi-build.c-Migrate-SPCR-creation-to-co.patch create mode 100644 hw-i386-add-mem2-option-for-qemu.patch create mode 100644 hw-i386-amd_iommu-Don-t-leak-memory-in-amdvi_update_.patch create mode 100644 hw-intc-arm_gic-Fix-handling-of-NS-view-of-GICC_APR-.patch create mode 100644 hw-loongarch-Add-KVM-IPI-device-support.patch create mode 100644 hw-loongarch-Add-KVM-extioi-device-support.patch create mode 100644 hw-loongarch-Add-KVM-pch-msi-device-support.patch create mode 100644 hw-loongarch-Add-KVM-pch-pic-device-support.patch create mode 100644 hw-loongarch-Add-VM-mode-in-IOCSR-feature-register-i.patch create mode 100644 hw-loongarch-Add-acpi-SPCR-table-support.patch create mode 100644 hw-loongarch-Add-cells-missing-from-rtc-node.patch create mode 100644 hw-loongarch-Add-cells-missing-from-uart-node.patch create mode 100644 hw-loongarch-Add-init_cmdline.patch create mode 100644 hw-loongarch-Add-load-initrd.patch create mode 100644 hw-loongarch-Add-slave-cpu-boot_code.patch create mode 100644 hw-loongarch-Change-the-tpm-support-by-default.patch create mode 100644 hw-loongarch-Fix-length-for-lowram-in-ACPI-SRAT.patch create mode 100644 hw-loongarch-Init-efi_boot_memmap-table.patch create mode 100644 hw-loongarch-Init-efi_fdt-table.patch create mode 100644 hw-loongarch-Init-efi_initrd-table.patch create mode 100644 hw-loongarch-Init-efi_system_table.patch create mode 100644 hw-loongarch-Move-boot-functions-to-boot.c.patch create mode 100644 hw-loongarch-Refine-acpi-srat-table-for-numa-memory.patch create mode 100644 hw-loongarch-Refine-default-numa-id-calculation.patch create mode 100644 hw-loongarch-Refine-fadt-memory-table-for-numa-memor.patch create mode 100644 hw-loongarch-Refine-fwcfg-memory-map.patch create mode 100644 hw-loongarch-Refine-system-dram-memory-region.patch create mode 100644 hw-loongarch-Remove-default-enable-with-VIRTIO_VGA-d.patch create mode 100644 hw-loongarch-Remove-minimum-and-default-memory-size.patch create mode 100644 hw-loongarch-Rename-LOONGARCH_MACHINE-with-LOONGARCH.patch create mode 100644 hw-loongarch-Rename-LoongArchMachineState-with-Loong.patch create mode 100644 hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch create mode 100644 hw-loongarch-boot.c-fix-out-of-bound-reading.patch create mode 100644 hw-loongarch-clean-code.patch create mode 100644 hw-loongarch-fdt-adds-Extend-I-O-Interrupt-Controlle.patch create mode 100644 hw-loongarch-fdt-adds-cpu-interrupt-controller-node.patch create mode 100644 hw-loongarch-fdt-adds-pch_msi-Controller.patch create mode 100644 hw-loongarch-fdt-adds-pch_pic-Controller.patch create mode 100644 hw-loongarch-fdt-adds-pcie-irq_map-node.patch create mode 100644 hw-loongarch-fdt-remove-unused-irqchip-node.patch create mode 100644 hw-loongarch-fix-cpu-hotplug-reset.patch create mode 100644 hw-loongarch-move-memory-map-to-boot.c.patch create mode 100644 hw-loongarch-virt-Add-CPU-topology-support.patch create mode 100644 hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch create mode 100644 hw-loongarch-virt-Add-basic-CPU-plug-support.patch create mode 100644 hw-loongarch-virt-Add-description-for-virt-machine-t.patch create mode 100644 hw-loongarch-virt-Remove-unused-assignment.patch create mode 100644 hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch create mode 100644 hw-loongarch-virt-Use-MemTxAttrs-interface-for-misc-.patch create mode 100644 hw-loongarch-virt-pass-random-seed-to-fdt.patch create mode 100644 hw-loongarch-virt-support-up-to-4-serial-ports.patch create mode 100644 hw-misc-psp-Pin-the-hugepage-memory-specified-by-mem.patch create mode 100644 hw-misc-support-tkm-use-mem2-memory.patch create mode 100644 hw-nvme-fix-handling-of-over-committed-queues.patch create mode 100644 hw-ppc-e500-Add-missing-device-tree-properties-to-i2.patch create mode 100644 hw-ppc-e500-Prefer-QOM-cast.patch create mode 100644 hw-ppc-e500-Remove-unused-irqs-parameter.patch create mode 100644 kvm-add-support-for-guest-physical-bits.patch create mode 100644 linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch create mode 100644 linux-headers-update-kernel-headers-to-include-CSV3-.patch create mode 100644 loongarch-switch-boards-to-default-y.patch create mode 100644 migration-Fix-file-migration-with-fdset.patch create mode 100644 migration-fix-possible-int-overflow.patch create mode 100644 next-kbd-convert-to-use-qemu_input_handler_register.patch create mode 100644 physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch create mode 100644 qemu-bswap-Undefine-CPU_CONVERT-once-done.patch create mode 100644 qemu-options-Fix-CXL-Fixed-Memory-Window-interleave-.patch create mode 100644 qio-Inherit-follow_coroutine_ctx-across-TLS.patch create mode 100644 sphinx-qapidoc-Fix-to-generate-doc-for-explicit-unbo.patch create mode 100644 sync-loongarch-linux-headers.patch create mode 100644 target-arm-Fix-FJCVTZS-vs-flush-to-zero.patch create mode 100644 target-i386-add-guest-phys-bits-cpu-property.patch create mode 100644 target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch create mode 100644 target-i386-csv-Add-CSV3-context.patch create mode 100644 target-i386-csv-Add-command-to-initialize-CSV3-conte.patch create mode 100644 target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch create mode 100644 target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch create mode 100644 target-i386-csv-Add-support-to-migrate-the-incoming--new.patch create mode 100644 target-i386-csv-Add-support-to-migrate-the-incoming-.patch create mode 100644 target-i386-csv-Add-support-to-migrate-the-outgoing--new.patch create mode 100644 target-i386-csv-Add-support-to-migrate-the-outgoing-.patch create mode 100644 target-i386-csv-Do-not-register-unregister-guest-sec.patch create mode 100644 target-i386-csv-Load-initial-image-to-private-memory.patch create mode 100644 target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch create mode 100644 target-loongarch-Add-compatible-support-about-VM-reb.patch create mode 100644 target-loongarch-Add-loongarch-vector-property-uncon.patch create mode 100644 target-loongarch-Add-loongson-binary-translation-fea.patch create mode 100644 target-loongarch-Add-steal-time-support-on-migration.patch create mode 100644 target-loongarch-Avoid-bits-shift-exceeding-width-of.patch create mode 100644 target-loongarch-Fix-cpu_reset-set-wrong-CSR_CRMD.patch create mode 100644 target-loongarch-Implement-lbt-registers-save-restor.patch create mode 100644 target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch create mode 100644 target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch create mode 100644 target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch create mode 100644 target-loongarch-Support-QMP-dump-guest-memory.patch create mode 100644 target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch create mode 100644 target-loongarch-fix-Werror-maybe-uninitialized-fals.patch create mode 100644 target-loongarch-kvm-Add-software-breakpoint-support-new.patch create mode 100644 target-loongarch-kvm-Add-vCPU-reset-function.patch create mode 100644 target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch create mode 100644 target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch create mode 100644 target-m68k-Map-FPU-exceptions-to-FPSR-register.patch create mode 100644 target-riscv-Fix-the-element-agnostic-function-probl.patch create mode 100644 tcg-Allow-top-bit-of-SIMD_DATA_BITS-to-be-set-in-sim.patch create mode 100644 tcg-loongarch64-Fix-tcg_out_movi-vs-some-pcrel-point.patch create mode 100644 tests-libqos-Add-loongarch-virt-machine-node.patch create mode 100644 ui-vnc-don-t-return-an-empty-SASL-mechlist-to-the-cl.patch create mode 100644 vdpa-dev-Fix-initialisation-order-to-restore-VDUSE-c.patch create mode 100644 vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch create mode 100644 vga-Force-full-update-for-CSV3-guest.patch diff --git a/9pfs-fix-crash-on-Treaddir-request.patch b/9pfs-fix-crash-on-Treaddir-request.patch new file mode 100644 index 0000000..1609431 --- /dev/null +++ b/9pfs-fix-crash-on-Treaddir-request.patch @@ -0,0 +1,64 @@ +From 93e7987cb5a7b33c2d2e0a02b7f310955ca11851 Mon Sep 17 00:00:00 2001 +From: Christian Schoenebeck +Date: Tue, 5 Nov 2024 11:25:26 +0100 +Subject: [PATCH] 9pfs: fix crash on 'Treaddir' request + +A bad (broken or malicious) 9p client (guest) could cause QEMU host to +crash by sending a 9p 'Treaddir' request with a numeric file ID (FID) that +was previously opened for a file instead of an expected directory: + + #0 0x0000762aff8f4919 in __GI___rewinddir (dirp=0xf) at + ../sysdeps/unix/sysv/linux/rewinddir.c:29 + #1 0x0000557b7625fb40 in do_readdir_many (pdu=0x557bb67d2eb0, + fidp=0x557bb67955b0, entries=0x762afe9fff58, offset=0, maxsize=131072, + dostat=) at ../hw/9pfs/codir.c:101 + #2 v9fs_co_readdir_many (pdu=pdu@entry=0x557bb67d2eb0, + fidp=fidp@entry=0x557bb67955b0, entries=entries@entry=0x762afe9fff58, + offset=0, maxsize=131072, dostat=false) at ../hw/9pfs/codir.c:226 + #3 0x0000557b7625c1f9 in v9fs_do_readdir (pdu=0x557bb67d2eb0, + fidp=0x557bb67955b0, offset=, + max_count=) at ../hw/9pfs/9p.c:2488 + #4 v9fs_readdir (opaque=0x557bb67d2eb0) at ../hw/9pfs/9p.c:2602 + +That's because V9fsFidOpenState was declared as union type. So the +same memory region is used for either an open POSIX file handle (int), +or a POSIX DIR* pointer, etc., so 9p server incorrectly used the +previously opened (valid) POSIX file handle (0xf) as DIR* pointer, +eventually causing a crash in glibc's rewinddir() function. + +Root cause was therefore a missing check in 9p server's 'Treaddir' +request handler, which must ensure that the client supplied FID was +really opened as directory stream before trying to access the +aforementioned union and its DIR* member. + +Cc: qemu-stable@nongnu.org +Fixes: d62dbb51f7 ("virtio-9p: Add fidtype so that we can do type ...") +Reported-by: Akihiro Suda +Tested-by: Akihiro Suda +Signed-off-by: Christian Schoenebeck +Reviewed-by: Greg Kurz +Message-Id: +Signed-off-by: Zhongrui Tang +--- + hw/9pfs/9p.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c +index af636cfb2d..9a291d1b51 100644 +--- a/hw/9pfs/9p.c ++++ b/hw/9pfs/9p.c +@@ -2587,6 +2587,11 @@ static void coroutine_fn v9fs_readdir(void *opaque) + retval = -EINVAL; + goto out_nofid; + } ++ if (fidp->fid_type != P9_FID_DIR) { ++ warn_report_once("9p: bad client: T_readdir on non-directory stream"); ++ retval = -ENOTDIR; ++ goto out; ++ } + if (!fidp->fs.dir.stream) { + retval = -EINVAL; + goto out; +-- +2.41.0.windows.1 + diff --git a/accel-kvm-Extract-common-KVM-vCPU-creation-parking-c-new.patch b/accel-kvm-Extract-common-KVM-vCPU-creation-parking-c-new.patch new file mode 100644 index 0000000..eb822e3 --- /dev/null +++ b/accel-kvm-Extract-common-KVM-vCPU-creation-parking-c-new.patch @@ -0,0 +1,234 @@ +From 2464d0d6115e1794468ff455e3acdb98e0d71a31 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:56 +0100 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..b326f86 --- /dev/null +++ b/accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch @@ -0,0 +1,45 @@ +From 9bbc73e18d36d75c5dd842e478ed1f1b47ed4222 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 1 Aug 2024 10:15:03 +0100 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/accel-tcg-Fix-typo-causing-tb-page_addr-1-to-not-be-.patch b/accel-tcg-Fix-typo-causing-tb-page_addr-1-to-not-be-.patch new file mode 100644 index 0000000..382187c --- /dev/null +++ b/accel-tcg-Fix-typo-causing-tb-page_addr-1-to-not-be-.patch @@ -0,0 +1,52 @@ +From 378d79fa6b9410af702776ffa93865219f273380 Mon Sep 17 00:00:00 2001 +From: Anton Johansson +Date: Wed, 12 Jun 2024 15:30:31 +0200 +Subject: [PATCH] accel/tcg: Fix typo causing tb->page_addr[1] to not be + recorded +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For TBs crossing page boundaries, the 2nd page will never be +recorded/removed, as the index of the 2nd page is computed from the +address of the 1st page. This is due to a typo, fix it. + +Cc: qemu-stable@nongnu.org +Fixes: deba78709a ("accel/tcg: Always lock pages before translation") +Signed-off-by: Anton Johansson +Reviewed-by: Manos Pitsidianakis +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Alex Bennée +Message-Id: <20240612133031.15298-1-anjo@rev.ng> +Signed-off-by: Richard Henderson +(cherry picked from commit 3b279f73fa37bec8d3ba04a15f5153d6491cffaf) +Signed-off-by: zhujun2 +--- + accel/tcg/tb-maint.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c +index 3d2a896220..eb37f9e8a8 100644 +--- a/accel/tcg/tb-maint.c ++++ b/accel/tcg/tb-maint.c +@@ -712,7 +712,7 @@ static void tb_record(TranslationBlock *tb) + tb_page_addr_t paddr0 = tb_page_addr0(tb); + tb_page_addr_t paddr1 = tb_page_addr1(tb); + tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS; +- tb_page_addr_t pindex1 = paddr0 >> TARGET_PAGE_BITS; ++ tb_page_addr_t pindex1 = paddr1 >> TARGET_PAGE_BITS; + + assert(paddr0 != -1); + if (unlikely(paddr1 != -1) && pindex0 != pindex1) { +@@ -744,7 +744,7 @@ static void tb_remove(TranslationBlock *tb) + tb_page_addr_t paddr0 = tb_page_addr0(tb); + tb_page_addr_t paddr1 = tb_page_addr1(tb); + tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS; +- tb_page_addr_t pindex1 = paddr0 >> TARGET_PAGE_BITS; ++ tb_page_addr_t pindex1 = paddr1 >> TARGET_PAGE_BITS; + + assert(paddr0 != -1); + if (unlikely(paddr1 != -1) && pindex0 != pindex1) { +-- +2.41.0.windows.1 + diff --git a/exec-memop-Remove-unused-memop_big_endian-helper.patch b/exec-memop-Remove-unused-memop_big_endian-helper.patch new file mode 100644 index 0000000..8e4176f --- /dev/null +++ b/exec-memop-Remove-unused-memop_big_endian-helper.patch @@ -0,0 +1,39 @@ +From 9a12c439cb9d1e59175be4b96adf0732dca39db3 Mon Sep 17 00:00:00 2001 +From: Zhang Jiao +Date: Tue, 12 Nov 2024 13:30:29 +0800 +Subject: [PATCH] exec/memop: Remove unused memop_big_endian() helper +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 5caa0e1b1bf8597ea7277391b0e17e8584fad18f + +Last use of memop_big_endian() was removed in commit 592134617c9 +("accel/tcg: Reorg system mode store helpers"). + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Thomas Huth +Message-Id: <20241003234211.53644-3-philmd@linaro.org> +Signed-off-by: Zhang Jiao +--- + include/exec/memop.h | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/include/exec/memop.h b/include/exec/memop.h +index a86dc6743a..5b9064819c 100644 +--- a/include/exec/memop.h ++++ b/include/exec/memop.h +@@ -164,10 +164,4 @@ static inline MemOp size_memop(unsigned size) + return ctz32(size); + } + +-/* Big endianness from MemOp. */ +-static inline bool memop_big_endian(MemOp op) +-{ +- return (op & MO_BSWAP) == MO_BE; +-} +- + #endif +-- +2.41.0.windows.1 + diff --git a/fix-compile-error-on-loongarch.patch b/fix-compile-error-on-loongarch.patch new file mode 100644 index 0000000..9aef758 --- /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.41.0.windows.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 0000000..68e6fd1 --- /dev/null +++ b/gdbstub-Add-helper-function-to-unregister-GDB-regist.patch @@ -0,0 +1,85 @@ +From 7754cf384417295dc74add4e774c506d751671a9 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:15:02 +0100 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/hvf-arm-Fix-encodings-for-ID_AA64PFR1_EL1-and-debug-.patch b/hvf-arm-Fix-encodings-for-ID_AA64PFR1_EL1-and-debug-.patch new file mode 100644 index 0000000..a7f2fde --- /dev/null +++ b/hvf-arm-Fix-encodings-for-ID_AA64PFR1_EL1-and-debug-.patch @@ -0,0 +1,211 @@ +From ab7c657e05f896600c310c74e7584fc345ff235c Mon Sep 17 00:00:00 2001 +From: Zenghui Yu +Date: Thu, 23 May 2024 16:06:19 +0100 +Subject: [PATCH] hvf: arm: Fix encodings for ID_AA64PFR1_EL1 and debug System + registers + +We wrongly encoded ID_AA64PFR1_EL1 using {3,0,0,4,2} in hvf_sreg_match[] so +we fail to get the expected ARMCPRegInfo from cp_regs hash table with the +wrong key. + +Fix it with the correct encoding {3,0,0,4,1}. With that fixed, the Linux +guest can properly detect FEAT_SSBS2 on my M1 HW. + +All DBG{B,W}{V,C}R_EL1 registers are also wrongly encoded with op0 == 14. +It happens to work because HVF_SYSREG(CRn, CRm, 14, op1, op2) equals to +HVF_SYSREG(CRn, CRm, 2, op1, op2), by definition. But we shouldn't rely on +it. + +Cc: qemu-stable@nongnu.org +Fixes: a1477da3ddeb ("hvf: Add Apple Silicon support") +Signed-off-by: Zenghui Yu +Reviewed-by: Alexander Graf +Message-id: 20240503153453.54389-1-zenghui.yu@linux.dev +Signed-off-by: Peter Maydell +(cherry picked from commit 19ed42e8adc87a3c739f61608b66a046bb9237e2) +Signed-off-by: zhujun2 +--- + target/arm/hvf/hvf.c | 160 +++++++++++++++++++++---------------------- + 1 file changed, 80 insertions(+), 80 deletions(-) + +diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c +index b4e98a99e2..d7cc00a084 100644 +--- a/target/arm/hvf/hvf.c ++++ b/target/arm/hvf/hvf.c +@@ -392,85 +392,85 @@ struct hvf_sreg_match { + }; + + static struct hvf_sreg_match hvf_sreg_match[] = { +- { HV_SYS_REG_DBGBVR0_EL1, HVF_SYSREG(0, 0, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR0_EL1, HVF_SYSREG(0, 0, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR0_EL1, HVF_SYSREG(0, 0, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR0_EL1, HVF_SYSREG(0, 0, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR1_EL1, HVF_SYSREG(0, 1, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR1_EL1, HVF_SYSREG(0, 1, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR1_EL1, HVF_SYSREG(0, 1, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR1_EL1, HVF_SYSREG(0, 1, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR2_EL1, HVF_SYSREG(0, 2, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR2_EL1, HVF_SYSREG(0, 2, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR2_EL1, HVF_SYSREG(0, 2, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR2_EL1, HVF_SYSREG(0, 2, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR3_EL1, HVF_SYSREG(0, 3, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR3_EL1, HVF_SYSREG(0, 3, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR3_EL1, HVF_SYSREG(0, 3, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR3_EL1, HVF_SYSREG(0, 3, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR4_EL1, HVF_SYSREG(0, 4, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR4_EL1, HVF_SYSREG(0, 4, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR4_EL1, HVF_SYSREG(0, 4, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR4_EL1, HVF_SYSREG(0, 4, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR5_EL1, HVF_SYSREG(0, 5, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR5_EL1, HVF_SYSREG(0, 5, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR5_EL1, HVF_SYSREG(0, 5, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR5_EL1, HVF_SYSREG(0, 5, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR6_EL1, HVF_SYSREG(0, 6, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR6_EL1, HVF_SYSREG(0, 6, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR6_EL1, HVF_SYSREG(0, 6, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR6_EL1, HVF_SYSREG(0, 6, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR7_EL1, HVF_SYSREG(0, 7, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR7_EL1, HVF_SYSREG(0, 7, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR7_EL1, HVF_SYSREG(0, 7, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR7_EL1, HVF_SYSREG(0, 7, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR8_EL1, HVF_SYSREG(0, 8, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR8_EL1, HVF_SYSREG(0, 8, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR8_EL1, HVF_SYSREG(0, 8, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR8_EL1, HVF_SYSREG(0, 8, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR9_EL1, HVF_SYSREG(0, 9, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR9_EL1, HVF_SYSREG(0, 9, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR9_EL1, HVF_SYSREG(0, 9, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR9_EL1, HVF_SYSREG(0, 9, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR10_EL1, HVF_SYSREG(0, 10, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR10_EL1, HVF_SYSREG(0, 10, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR10_EL1, HVF_SYSREG(0, 10, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR10_EL1, HVF_SYSREG(0, 10, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR11_EL1, HVF_SYSREG(0, 11, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR11_EL1, HVF_SYSREG(0, 11, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR11_EL1, HVF_SYSREG(0, 11, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR11_EL1, HVF_SYSREG(0, 11, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR12_EL1, HVF_SYSREG(0, 12, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR12_EL1, HVF_SYSREG(0, 12, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR12_EL1, HVF_SYSREG(0, 12, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR12_EL1, HVF_SYSREG(0, 12, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR13_EL1, HVF_SYSREG(0, 13, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR13_EL1, HVF_SYSREG(0, 13, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR13_EL1, HVF_SYSREG(0, 13, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR13_EL1, HVF_SYSREG(0, 13, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR14_EL1, HVF_SYSREG(0, 14, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR14_EL1, HVF_SYSREG(0, 14, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR14_EL1, HVF_SYSREG(0, 14, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR14_EL1, HVF_SYSREG(0, 14, 14, 0, 7) }, +- +- { HV_SYS_REG_DBGBVR15_EL1, HVF_SYSREG(0, 15, 14, 0, 4) }, +- { HV_SYS_REG_DBGBCR15_EL1, HVF_SYSREG(0, 15, 14, 0, 5) }, +- { HV_SYS_REG_DBGWVR15_EL1, HVF_SYSREG(0, 15, 14, 0, 6) }, +- { HV_SYS_REG_DBGWCR15_EL1, HVF_SYSREG(0, 15, 14, 0, 7) }, ++ { HV_SYS_REG_DBGBVR0_EL1, HVF_SYSREG(0, 0, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR0_EL1, HVF_SYSREG(0, 0, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR0_EL1, HVF_SYSREG(0, 0, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR0_EL1, HVF_SYSREG(0, 0, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR1_EL1, HVF_SYSREG(0, 1, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR1_EL1, HVF_SYSREG(0, 1, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR1_EL1, HVF_SYSREG(0, 1, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR1_EL1, HVF_SYSREG(0, 1, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR2_EL1, HVF_SYSREG(0, 2, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR2_EL1, HVF_SYSREG(0, 2, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR2_EL1, HVF_SYSREG(0, 2, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR2_EL1, HVF_SYSREG(0, 2, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR3_EL1, HVF_SYSREG(0, 3, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR3_EL1, HVF_SYSREG(0, 3, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR3_EL1, HVF_SYSREG(0, 3, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR3_EL1, HVF_SYSREG(0, 3, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR4_EL1, HVF_SYSREG(0, 4, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR4_EL1, HVF_SYSREG(0, 4, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR4_EL1, HVF_SYSREG(0, 4, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR4_EL1, HVF_SYSREG(0, 4, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR5_EL1, HVF_SYSREG(0, 5, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR5_EL1, HVF_SYSREG(0, 5, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR5_EL1, HVF_SYSREG(0, 5, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR5_EL1, HVF_SYSREG(0, 5, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR6_EL1, HVF_SYSREG(0, 6, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR6_EL1, HVF_SYSREG(0, 6, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR6_EL1, HVF_SYSREG(0, 6, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR6_EL1, HVF_SYSREG(0, 6, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR7_EL1, HVF_SYSREG(0, 7, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR7_EL1, HVF_SYSREG(0, 7, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR7_EL1, HVF_SYSREG(0, 7, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR7_EL1, HVF_SYSREG(0, 7, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR8_EL1, HVF_SYSREG(0, 8, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR8_EL1, HVF_SYSREG(0, 8, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR8_EL1, HVF_SYSREG(0, 8, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR8_EL1, HVF_SYSREG(0, 8, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR9_EL1, HVF_SYSREG(0, 9, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR9_EL1, HVF_SYSREG(0, 9, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR9_EL1, HVF_SYSREG(0, 9, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR9_EL1, HVF_SYSREG(0, 9, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR10_EL1, HVF_SYSREG(0, 10, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR10_EL1, HVF_SYSREG(0, 10, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR10_EL1, HVF_SYSREG(0, 10, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR10_EL1, HVF_SYSREG(0, 10, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR11_EL1, HVF_SYSREG(0, 11, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR11_EL1, HVF_SYSREG(0, 11, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR11_EL1, HVF_SYSREG(0, 11, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR11_EL1, HVF_SYSREG(0, 11, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR12_EL1, HVF_SYSREG(0, 12, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR12_EL1, HVF_SYSREG(0, 12, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR12_EL1, HVF_SYSREG(0, 12, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR12_EL1, HVF_SYSREG(0, 12, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR13_EL1, HVF_SYSREG(0, 13, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR13_EL1, HVF_SYSREG(0, 13, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR13_EL1, HVF_SYSREG(0, 13, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR13_EL1, HVF_SYSREG(0, 13, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR14_EL1, HVF_SYSREG(0, 14, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR14_EL1, HVF_SYSREG(0, 14, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR14_EL1, HVF_SYSREG(0, 14, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR14_EL1, HVF_SYSREG(0, 14, 2, 0, 7) }, ++ ++ { HV_SYS_REG_DBGBVR15_EL1, HVF_SYSREG(0, 15, 2, 0, 4) }, ++ { HV_SYS_REG_DBGBCR15_EL1, HVF_SYSREG(0, 15, 2, 0, 5) }, ++ { HV_SYS_REG_DBGWVR15_EL1, HVF_SYSREG(0, 15, 2, 0, 6) }, ++ { HV_SYS_REG_DBGWCR15_EL1, HVF_SYSREG(0, 15, 2, 0, 7) }, + + #ifdef SYNC_NO_RAW_REGS + /* +@@ -482,7 +482,7 @@ static struct hvf_sreg_match hvf_sreg_match[] = { + { HV_SYS_REG_MPIDR_EL1, HVF_SYSREG(0, 0, 3, 0, 5) }, + { HV_SYS_REG_ID_AA64PFR0_EL1, HVF_SYSREG(0, 4, 3, 0, 0) }, + #endif +- { HV_SYS_REG_ID_AA64PFR1_EL1, HVF_SYSREG(0, 4, 3, 0, 2) }, ++ { HV_SYS_REG_ID_AA64PFR1_EL1, HVF_SYSREG(0, 4, 3, 0, 1) }, + { HV_SYS_REG_ID_AA64DFR0_EL1, HVF_SYSREG(0, 5, 3, 0, 0) }, + { HV_SYS_REG_ID_AA64DFR1_EL1, HVF_SYSREG(0, 5, 3, 0, 1) }, + { HV_SYS_REG_ID_AA64ISAR0_EL1, HVF_SYSREG(0, 6, 3, 0, 0) }, +-- +2.41.0.windows.1 + diff --git a/hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c-new.patch b/hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c-new.patch new file mode 100644 index 0000000..effea19 --- /dev/null +++ b/hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c-new.patch @@ -0,0 +1,48 @@ +From a8416845f721aa5ba03446b3ccf83b096b7a0d77 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:57 +0100 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho-new.patch b/hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho-new.patch new file mode 100644 index 0000000..939734a --- /dev/null +++ b/hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho-new.patch @@ -0,0 +1,126 @@ +From ac96f216155002d0c874ff88e301e83495093085 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:14:58 +0100 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change-new.patch b/hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change-new.patch new file mode 100644 index 0000000..731f61b --- /dev/null +++ b/hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change-new.patch @@ -0,0 +1,53 @@ +From 16d44ddb63becd559cc2185549c4b18d26feab60 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:15:00 +0100 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/hw-arm-mps2-tz.c-fix-RX-TX-interrupts-order.patch b/hw-arm-mps2-tz.c-fix-RX-TX-interrupts-order.patch new file mode 100644 index 0000000..aa349bf --- /dev/null +++ b/hw-arm-mps2-tz.c-fix-RX-TX-interrupts-order.patch @@ -0,0 +1,50 @@ +From 322f39889ff60a6fda87d7d95a6f233efb558e8a Mon Sep 17 00:00:00 2001 +From: Marco Palumbi +Date: Thu, 1 Aug 2024 10:15:02 +0100 +Subject: [PATCH] hw/arm/mps2-tz.c: fix RX/TX interrupts order + +The order of the RX and TX interrupts are swapped. +This commit fixes the order as per the following documents: + * https://developer.arm.com/documentation/dai0505/latest/ + * https://developer.arm.com/documentation/dai0521/latest/ + * https://developer.arm.com/documentation/dai0524/latest/ + * https://developer.arm.com/documentation/dai0547/latest/ + +Cc: qemu-stable@nongnu.org +Signed-off-by: Marco Palumbi +Message-id: 20240730073123.72992-1-marco@palumbi.it +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +(cherry picked from commit 5a558be93ad628e5bed6e0ee062870f49251725c) +Signed-off-by: zhujun2 +--- + hw/arm/mps2-tz.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c +index 668db5ed61..9d9c263ef8 100644 +--- a/hw/arm/mps2-tz.c ++++ b/hw/arm/mps2-tz.c +@@ -435,7 +435,7 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque, + const char *name, hwaddr size, + const int *irqs, const PPCExtraData *extradata) + { +- /* The irq[] array is tx, rx, combined, in that order */ ++ /* The irq[] array is rx, tx, combined, in that order */ + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); + CMSDKAPBUART *uart = opaque; + int i = uart - &mms->uart[0]; +@@ -447,8 +447,8 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque, + qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", mmc->apb_periph_frq); + sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal); + s = SYS_BUS_DEVICE(uart); +- sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0])); +- sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqs[1])); ++ sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[1])); ++ sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqs[0])); + sysbus_connect_irq(s, 2, qdev_get_gpio_in(orgate_dev, i * 2)); + sysbus_connect_irq(s, 3, qdev_get_gpio_in(orgate_dev, i * 2 + 1)); + sysbus_connect_irq(s, 4, get_sse_irq_in(mms, irqs[2])); +-- +2.41.0.windows.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 0000000..065b749 --- /dev/null +++ b/hw-arm-virt-acpi-build.c-Migrate-SPCR-creation-to-co.patch @@ -0,0 +1,236 @@ +From 478c205000b3df3710a7d30f3e3e5bd4f35b0156 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 +--- + 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 bf9c59f544..b0b68efa02 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -2016,6 +2016,59 @@ static 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.2 Cache Type Structure (Type 1) +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 179600d4fe..bc637b8619 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -550,48 +550,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); + } + + /* +@@ -1149,7 +1135,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 b1f389fb4b..7a8b708cda 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 7281c281f6..c0b852cbd2 100644 +--- a/include/hw/acpi/aml-build.h ++++ b/include/hw/acpi/aml-build.h +@@ -548,4 +548,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.41.0.windows.1 + diff --git a/hw-i386-add-mem2-option-for-qemu.patch b/hw-i386-add-mem2-option-for-qemu.patch new file mode 100644 index 0000000..eef09e8 --- /dev/null +++ b/hw-i386-add-mem2-option-for-qemu.patch @@ -0,0 +1,324 @@ +From d29bc8738131dcaaa1a1ae2870ea29b59a137f30 Mon Sep 17 00:00:00 2001 +From: xiongmengbiao +Date: Wed, 29 May 2024 00:05:44 +0800 +Subject: [PATCH] hw/i386: add mem2 option for qemu + +The '-mem2' option is used to create a set of hugepages +of memory and map them to a fixed address range of the guest. + +This allows some devices to easily obtain continuous host +physical address ranges for performing DMA operations. + +Signed-off-by: xiongmengbiao +--- + hw/i386/pc.c | 121 ++++++++++++++++++++++++++++++++++++++++++++ + include/hw/boards.h | 2 + + qemu-options.hx | 12 +++++ + system/vl.c | 76 ++++++++++++++++++++++++++++ + 4 files changed, 211 insertions(+) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 29b9964733..204e34db86 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -743,6 +743,111 @@ void xen_load_linux(PCMachineState *pcms) + x86ms->fw_cfg = fw_cfg; + } + ++static int try_create_2MB_page(uint32_t page_num) ++{ ++ char nr_hp_num_s[256] = {0}; ++ char free_hp_num_s[256] = {0}; ++ const char *nr_hugepages_dir = "/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages"; ++ const char *free_hugepages_dir = "/sys/kernel/mm/hugepages/hugepages-2048kB/free_hugepages"; ++ int nr_hp_num = -1, free_hp_num = -1, ret = -1; ++ int nr_fd = qemu_open_old(nr_hugepages_dir, O_RDWR); ++ int free_fd = qemu_open_old(free_hugepages_dir, O_RDONLY); ++ ++ if (nr_fd < 0 || free_fd < 0) { ++ error_report("%s: qemu_open failed: %s\n", __func__, strerror(errno)); ++ goto end; ++ } ++ ++ if (read(nr_fd, nr_hp_num_s, 256) < 0) ++ goto end; ++ if (read(free_fd, free_hp_num_s, 256) < 0) ++ goto end; ++ ++ nr_hp_num = atoi(nr_hp_num_s); ++ free_hp_num = atoi(free_hp_num_s); ++ if (nr_hp_num < 0 || free_hp_num < 0) ++ goto end; ++ ++ if (page_num <= free_hp_num) { ++ ret = 0; ++ goto end; ++ } ++ ++ nr_hp_num += (page_num - free_hp_num); ++ snprintf (nr_hp_num_s, 256, "%d", nr_hp_num); ++ if (write(nr_fd, nr_hp_num_s, strlen(nr_hp_num_s)) < 0) ++ goto end; ++ ++ ret = 0; ++end: ++ if (nr_fd >= 0) ++ close(nr_fd); ++ if (free_fd >= 0) ++ close(free_fd); ++ return ret; ++} ++ ++#define HUGEPAGE_NUM_MAX 128 ++#define HUGEPAGE_SIZE (1024*1024*2) ++static void mem2_init(MachineState *ms, MemoryRegion *system_memory) ++{ ++ MemoryRegion *mem2_mr; ++ char mr_name[128] = {0}; ++ void *ram = NULL; ++ int ret = 0, lock_fd; ++ const char *lock_file = "/sys/kernel/mm/hugepages/hugepages-2048kB/nr_overcommit_hugepages"; ++ uint32_t page_num = ms->ram2_size / HUGEPAGE_SIZE, i; ++ ++ if (HUGEPAGE_NUM_MAX < page_num) { ++ error_report("\"-mem2 'size='\" needs to Less than %dM\n", ++ (HUGEPAGE_SIZE * HUGEPAGE_NUM_MAX) / (1024 * 1024)); ++ exit(EXIT_FAILURE); ++ } ++ ++ // Apply for hugepages from OS and use them, which needs to be synchronized ++ lock_fd = qemu_open_old(lock_file, O_WRONLY); ++ if (lock_fd < 0) { ++ error_report("%s: open %s failed: %s\n", __func__, lock_file, strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ ++ while (qemu_lock_fd(lock_fd, 0, 0, true)) { ++ if (errno != EACCES && errno != EAGAIN) { ++ error_report("qemu_lock_fd failed: %s\n", strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ } ++ ++ /** try to create hugepage. ++ * If there are enough free hugepages, then do nothing. ++ */ ++ ret = try_create_2MB_page(page_num); ++ if (ret) { ++ error_report("%s: Failed to allocate hugepage\n", __func__); ++ goto unlock; ++ } ++ ++ for (i = 0; i < page_num; ++i) { ++ mem2_mr = g_malloc(sizeof(*mem2_mr)); ++ ram = mmap(NULL, HUGEPAGE_SIZE, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0); ++ if (ram == MAP_FAILED) { ++ error_report("%s: mmap failed: %s", __func__, strerror(errno)); ++ goto unlock; ++ } ++ ++ sprintf(mr_name, "mem2-%d", i); ++ memory_region_init_ram_ptr(mem2_mr, NULL, mr_name, HUGEPAGE_SIZE, ram); ++ memory_region_add_subregion(system_memory, ms->ram2_base + (i * HUGEPAGE_SIZE), mem2_mr); ++ } ++ ++ ret = 0; ++unlock: ++ qemu_unlock_fd(lock_fd, 0, 0); ++ if (ret) ++ exit(EXIT_FAILURE); ++} ++ + #define PC_ROM_MIN_VGA 0xc0000 + #define PC_ROM_MIN_OPTION 0xc8000 + #define PC_ROM_MAX 0xe0000 +@@ -965,6 +1070,22 @@ void pc_memory_init(PCMachineState *pcms, + E820_RAM); + } + ++ if (machine->ram2_size && machine->ram2_base) { ++ if (0x100000000ULL + x86ms->above_4g_mem_size > machine->ram2_base) { ++ error_report("\"-mem2 'base'\" needs to greater 0x%llx\n", ++ 0x100000000ULL + x86ms->above_4g_mem_size); ++ exit(EXIT_FAILURE); ++ } ++ if (machine->ram2_base & (HUGEPAGE_SIZE - 1) || ++ machine->ram2_size & (HUGEPAGE_SIZE - 1)) { ++ error_report("\"-mem2 'base|size'\" needs to aligned to 0x%x\n", HUGEPAGE_SIZE); ++ exit(EXIT_FAILURE); ++ } ++ ++ mem2_init(machine, system_memory); ++ e820_add_entry(machine->ram2_base, machine->ram2_size, E820_RAM); ++ } ++ + if (pcms->sgx_epc.size != 0) { + e820_add_entry(pcms->sgx_epc.base, pcms->sgx_epc.size, E820_RESERVED); + } +diff --git a/include/hw/boards.h b/include/hw/boards.h +index da85f86efb..8ac8cad2a2 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -389,6 +389,8 @@ struct MachineState { + + ram_addr_t ram_size; + ram_addr_t maxram_size; ++ ram_addr_t ram2_base; ++ ram_addr_t ram2_size; + uint64_t ram_slots; + BootConfiguration boot_config; + char *kernel_filename; +diff --git a/qemu-options.hx b/qemu-options.hx +index 42fd09e4de..bc8e66a037 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -5845,6 +5845,18 @@ SRST + (qemu) qom-set /objects/iothread1 poll-max-ns 100000 + ERST + ++DEF("mem2", HAS_ARG, QEMU_OPTION_mem2, ++ "-mem2 base=addr[G],size=n[MG]\n" ++ " Map guest memory using host hugepages\n" ++ " base: starting position of guest physical address\n" ++ " size: the size of mmaped memory\n" ++ "NOTE: Both `base` and `size` need to be aligned according to 2MB\n", ++ QEMU_ARCH_I386) ++SRST ++``-mem2 base=addr[G],size=n[MG]`` ++ Map the host's large page memory at the specified guest address ++ so that some devices can use larger contiguous physical memory. ++ERST + + HXCOMM This is the last statement. Insert new options before this line! + +diff --git a/system/vl.c b/system/vl.c +index 8e3357c578..a1e5e68773 100644 +--- a/system/vl.c ++++ b/system/vl.c +@@ -173,6 +173,8 @@ static QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list); + static BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); + static bool nographic = false; + static int mem_prealloc; /* force preallocation of physical target memory */ ++static ram_addr_t ram2_base; ++static ram_addr_t ram2_size; + static const char *vga_model = NULL; + static DisplayOptions dpy; + static int num_serial_hds; +@@ -504,6 +506,23 @@ static QemuOptsList qemu_action_opts = { + }, + }; + ++static QemuOptsList qemu_mem2_opts = { ++ .name = "mem2", ++ .merge_lists = true, ++ .head = QTAILQ_HEAD_INITIALIZER(qemu_mem2_opts.head), ++ .desc = { ++ { ++ .name = "base", ++ .type = QEMU_OPT_SIZE, ++ }, ++ { ++ .name = "size", ++ .type = QEMU_OPT_SIZE, ++ }, ++ { /* end of list */ } ++ }, ++}; ++ + const char *qemu_get_vm_name(void) + { + return qemu_name; +@@ -1932,6 +1951,9 @@ static void qemu_apply_machine_options(QDict *qdict) + { + object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal); + ++ current_machine->ram2_size = ram2_size; ++ current_machine->ram2_base = ram2_base; ++ + if (semihosting_enabled(false) && !semihosting_get_argc()) { + /* fall back to the -kernel/-append */ + semihosting_arg_fallback(current_machine->kernel_filename, current_machine->kernel_cmdline); +@@ -2094,11 +2116,57 @@ static void parse_memory_options(void) + loc_pop(&loc); + } + ++static void set_mem2_options(void) ++{ ++ uint64_t sz, base; ++ const char *mem_str; ++ QemuOpts *opts = qemu_find_opts_singleton("mem2"); ++ Location loc; ++ ++ loc_push_none(&loc); ++ qemu_opts_loc_restore(opts); ++ ++ mem_str = qemu_opt_get(opts, "base"); ++ if (mem_str) { ++ if (!*mem_str) { ++ error_report("missing 'base' option value"); ++ exit(EXIT_FAILURE); ++ } ++ ++ base = qemu_opt_get_size(opts, "base", ram2_base); ++ ram2_base = base; ++ } ++ ++ mem_str = qemu_opt_get(opts, "size"); ++ if (mem_str) { ++ if (!*mem_str) { ++ error_report("missing 'base' option value"); ++ exit(EXIT_FAILURE); ++ } ++ ++ sz = qemu_opt_get_size(opts, "size", ram2_size); ++ ram2_size = sz; ++ } ++ ++ if (ram2_base && !ram2_size){ ++ error_report("missing 'size' option value"); ++ exit(EXIT_FAILURE); ++ } ++ if (!ram2_base && ram2_size){ ++ error_report("missing 'base' option value"); ++ exit(EXIT_FAILURE); ++ } ++ ++ loc_pop(&loc); ++} ++ + static void qemu_create_machine(QDict *qdict) + { + MachineClass *machine_class = select_machine(qdict, &error_fatal); + object_set_machine_compat_props(machine_class->compat_props); + ++ set_mem2_options(); ++ + current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class))); + object_property_add_child(object_get_root(), "machine", + OBJECT(current_machine)); +@@ -2777,6 +2845,7 @@ void qemu_init(int argc, char **argv) + qemu_add_opts(&qemu_semihosting_config_opts); + qemu_add_opts(&qemu_fw_cfg_opts); + qemu_add_opts(&qemu_action_opts); ++ qemu_add_opts(&qemu_mem2_opts); + qemu_add_run_with_opts(); + module_call_init(MODULE_INIT_OPTS); + +@@ -3596,6 +3665,13 @@ void qemu_init(int argc, char **argv) + case QEMU_OPTION_nouserconfig: + /* Nothing to be parsed here. Especially, do not error out below. */ + break; ++ case QEMU_OPTION_mem2: ++ opts = qemu_opts_parse_noisily(qemu_find_opts("mem2"), ++ optarg, false); ++ if (!opts) { ++ exit(EXIT_FAILURE); ++ } ++ break; + #if defined(CONFIG_POSIX) + case QEMU_OPTION_runas: + if (!os_set_runas(optarg)) { +-- +2.41.0.windows.1 + diff --git a/hw-i386-amd_iommu-Don-t-leak-memory-in-amdvi_update_.patch b/hw-i386-amd_iommu-Don-t-leak-memory-in-amdvi_update_.patch new file mode 100644 index 0000000..b6e73f0 --- /dev/null +++ b/hw-i386-amd_iommu-Don-t-leak-memory-in-amdvi_update_.patch @@ -0,0 +1,50 @@ +From 1b0d08faf1daaed39809ed1a3516eaa0f7d61534 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Wed, 31 Jul 2024 18:00:19 +0100 +Subject: [PATCH] hw/i386/amd_iommu: Don't leak memory in amdvi_update_iotlb() + +In amdvi_update_iotlb() we will only put a new entry in the hash +table if to_cache.perm is not IOMMU_NONE. However we allocate the +memory for the new AMDVIIOTLBEntry and for the hash table key +regardless. This means that in the IOMMU_NONE case we will leak the +memory we alloacted. + +Move the allocations into the if() to the point where we know we're +going to add the item to the hash table. + +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2452 +Signed-off-by: Peter Maydell +Message-Id: <20240731170019.3590563-1-peter.maydell@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 9a45b0761628cc59267b3283a85d15294464ac31) +Signed-off-by: zhujun2 +--- + hw/i386/amd_iommu.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c +index 4203144da9..12742b1433 100644 +--- a/hw/i386/amd_iommu.c ++++ b/hw/i386/amd_iommu.c +@@ -346,12 +346,12 @@ static void amdvi_update_iotlb(AMDVIState *s, uint16_t devid, + uint64_t gpa, IOMMUTLBEntry to_cache, + uint16_t domid) + { +- AMDVIIOTLBEntry *entry = g_new(AMDVIIOTLBEntry, 1); +- uint64_t *key = g_new(uint64_t, 1); +- uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K; +- + /* don't cache erroneous translations */ + if (to_cache.perm != IOMMU_NONE) { ++ AMDVIIOTLBEntry *entry = g_new(AMDVIIOTLBEntry, 1); ++ uint64_t *key = g_new(uint64_t, 1); ++ uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K; ++ + trace_amdvi_cache_update(domid, PCI_BUS_NUM(devid), PCI_SLOT(devid), + PCI_FUNC(devid), gpa, to_cache.translated_addr); + +-- +2.41.0.windows.1 + diff --git a/hw-intc-arm_gic-Fix-handling-of-NS-view-of-GICC_APR-.patch b/hw-intc-arm_gic-Fix-handling-of-NS-view-of-GICC_APR-.patch new file mode 100644 index 0000000..6f311c4 --- /dev/null +++ b/hw-intc-arm_gic-Fix-handling-of-NS-view-of-GICC_APR-.patch @@ -0,0 +1,61 @@ +From 20541823659dc78a6a7be427f8fc03ccc58c88d1 Mon Sep 17 00:00:00 2001 +From: Andrey Shumilin +Date: Thu, 23 May 2024 16:06:20 +0100 +Subject: [PATCH] hw/intc/arm_gic: Fix handling of NS view of GICC_APR +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In gic_cpu_read() and gic_cpu_write(), we delegate the handling of +reading and writing the Non-Secure view of the GICC_APR registers +to functions gic_apr_ns_view() and gic_apr_write_ns_view(). +Unfortunately we got the order of the arguments wrong, swapping the +CPU number and the register number (which the compiler doesn't catch +because they're both integers). + +Most guests probably didn't notice this bug because directly +accessing the APR registers is typically something only done by +firmware when it is doing state save for going into a sleep mode. + +Correct the mismatched call arguments. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Cc: qemu-stable@nongnu.org +Fixes: 51fd06e0ee ("hw/intc/arm_gic: Fix handling of GICC_APR, GICC_NSAPR registers") +Signed-off-by: Andrey Shumilin +[PMM: Rewrote commit message] +Signed-off-by: Peter Maydell +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Alex Bennée +(cherry picked from commit daafa78b297291fea36fb4daeed526705fa7c035) +Signed-off-by: zhujun2 +--- + hw/intc/arm_gic.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c +index dfe7a0a729..f0582f7a49 100644 +--- a/hw/intc/arm_gic.c ++++ b/hw/intc/arm_gic.c +@@ -1663,7 +1663,7 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, + *data = s->h_apr[gic_get_vcpu_real_id(cpu)]; + } else if (gic_cpu_ns_access(s, cpu, attrs)) { + /* NS view of GICC_APR is the top half of GIC_NSAPR */ +- *data = gic_apr_ns_view(s, regno, cpu); ++ *data = gic_apr_ns_view(s, cpu, regno); + } else { + *data = s->apr[regno][cpu]; + } +@@ -1751,7 +1751,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, + s->h_apr[gic_get_vcpu_real_id(cpu)] = value; + } else if (gic_cpu_ns_access(s, cpu, attrs)) { + /* NS view of GICC_APR is the top half of GIC_NSAPR */ +- gic_apr_write_ns_view(s, regno, cpu, value); ++ gic_apr_write_ns_view(s, cpu, regno, value); + } else { + s->apr[regno][cpu] = value; + } +-- +2.41.0.windows.1 + 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 0000000..f8e8012 --- /dev/null +++ b/hw-loongarch-Add-KVM-IPI-device-support.patch @@ -0,0 +1,399 @@ +From 24e4e6742bdc8d804760e84f4e4bde5460e1e024 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 09:29:00 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..7381a6e --- /dev/null +++ b/hw-loongarch-Add-KVM-extioi-device-support.patch @@ -0,0 +1,383 @@ +From 833cdea8037d9124cd2e0328739de1b85aaec2a2 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 09:50:50 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..2cf2489 --- /dev/null +++ b/hw-loongarch-Add-KVM-pch-msi-device-support.patch @@ -0,0 +1,135 @@ +From 24bd774f8146247c7ac6071492f6016140a97267 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 22:18:50 +0800 +Subject: [PATCH] hw/loongarch: Add KVM pch msi device support + +Added pch_msi interrupt controller handling +during kernel emulation of irq chip. + +Signed-off-by: gaosong +--- + 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.41.0.windows.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 0000000..5c15ac3 --- /dev/null +++ b/hw-loongarch-Add-KVM-pch-pic-device-support.patch @@ -0,0 +1,486 @@ +From 30f88e80a47d9bcde08c44c0d752c22c11f2224c Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 10:13:29 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..bc3a65a --- /dev/null +++ b/hw-loongarch-Add-VM-mode-in-IOCSR-feature-register-i.patch @@ -0,0 +1,48 @@ +From 0437c11a20b3c66882770e468518d33ff71a932a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 14 May 2024 10:51:09 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..5abc679 --- /dev/null +++ b/hw-loongarch-Add-acpi-SPCR-table-support.patch @@ -0,0 +1,81 @@ +From fe22e0efe4c1c99fc876a42446cb2c87f9457afb Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sat, 7 Sep 2024 15:30:37 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..f3c96bb --- /dev/null +++ b/hw-loongarch-Add-cells-missing-from-rtc-node.patch @@ -0,0 +1,55 @@ +From 7266141c658cd00426922534a7de4dd5d89486b2 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:51 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..74a01ac --- /dev/null +++ b/hw-loongarch-Add-cells-missing-from-uart-node.patch @@ -0,0 +1,51 @@ +From 33994eff45e75e91acf0a4753fec77ad0027e4dd Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:50 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-Add-init_cmdline.patch b/hw-loongarch-Add-init_cmdline.patch new file mode 100644 index 0000000..c38bbf2 --- /dev/null +++ b/hw-loongarch-Add-init_cmdline.patch @@ -0,0 +1,116 @@ +From 206b799cb8c218c744f4dcdaf161d11f14c21e0f Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:38 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-Add-load-initrd.patch b/hw-loongarch-Add-load-initrd.patch new file mode 100644 index 0000000..ebe4b3c --- /dev/null +++ b/hw-loongarch-Add-load-initrd.patch @@ -0,0 +1,63 @@ +From 02c5f52da7f9458c0fc41e43f181f6e9b7101b57 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:36 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..af113d1 --- /dev/null +++ b/hw-loongarch-Add-slave-cpu-boot_code.patch @@ -0,0 +1,102 @@ +From 2e3e7bcf92284f41c08fce29f6c6d45849721e71 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:37 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..3ed77e9 --- /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] 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.41.0.windows.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 0000000..47fc840 --- /dev/null +++ b/hw-loongarch-Fix-length-for-lowram-in-ACPI-SRAT.patch @@ -0,0 +1,38 @@ +From 087201cd62e71801855775c3aa6395c7e1c00cee Mon Sep 17 00:00:00 2001 +From: Jiaxun Yang +Date: Tue, 20 Aug 2024 19:42:33 +0100 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..87813b2 --- /dev/null +++ b/hw-loongarch-Init-efi_boot_memmap-table.patch @@ -0,0 +1,168 @@ +From 0245881108803abedf50e954d34ebcfff294d1c3 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:40 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-Init-efi_fdt-table.patch b/hw-loongarch-Init-efi_fdt-table.patch new file mode 100644 index 0000000..647cdd0 --- /dev/null +++ b/hw-loongarch-Init-efi_fdt-table.patch @@ -0,0 +1,104 @@ +From 605b2b372f972fffa2d198d8dee4cf37f335559d Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:42 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-Init-efi_initrd-table.patch b/hw-loongarch-Init-efi_initrd-table.patch new file mode 100644 index 0000000..4699707 --- /dev/null +++ b/hw-loongarch-Init-efi_initrd-table.patch @@ -0,0 +1,100 @@ +From ad674827da4ab972a30d51818f7768de47336984 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:41 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-Init-efi_system_table.patch b/hw-loongarch-Init-efi_system_table.patch new file mode 100644 index 0000000..f85b973 --- /dev/null +++ b/hw-loongarch-Init-efi_system_table.patch @@ -0,0 +1,124 @@ +From 65ae44689bfa6a1b697fea6ec0e72027fdddee95 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:39 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..65ea998 --- /dev/null +++ b/hw-loongarch-Move-boot-functions-to-boot.c.patch @@ -0,0 +1,389 @@ +From 2414b74bec88f4db58040a683191d3c3828f81ab Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:35 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..c9ac810 --- /dev/null +++ b/hw-loongarch-Refine-acpi-srat-table-for-numa-memory.patch @@ -0,0 +1,107 @@ +From 1c9b7b7e76a63738721ac1092fdfff12ae87993a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:22 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..191e7d3 --- /dev/null +++ b/hw-loongarch-Refine-default-numa-id-calculation.patch @@ -0,0 +1,56 @@ +From a9f9a4a0a60596f2e738e6e434c20a3f5266fa17 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 19 Mar 2024 10:26:06 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..246d74f --- /dev/null +++ b/hw-loongarch-Refine-fadt-memory-table-for-numa-memor.patch @@ -0,0 +1,105 @@ +From d39247ec5d4ef52a4b9422aaecccc284cbd1a5dd Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:23 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-Refine-fwcfg-memory-map.patch b/hw-loongarch-Refine-fwcfg-memory-map.patch new file mode 100644 index 0000000..4bc92e6 --- /dev/null +++ b/hw-loongarch-Refine-fwcfg-memory-map.patch @@ -0,0 +1,119 @@ +From 88b12e40d6a479dfb376fb6a91ef24e07a59d33a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:24 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..aab29e5 --- /dev/null +++ b/hw-loongarch-Refine-system-dram-memory-region.patch @@ -0,0 +1,109 @@ +From 1a7f567308756a2a26020802b24fe7fd106cf84a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:25 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..86fbfec --- /dev/null +++ b/hw-loongarch-Remove-default-enable-with-VIRTIO_VGA-d.patch @@ -0,0 +1,37 @@ +From 94fa0b75c098ca6fc987f103760c1e07695ffd1a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Fri, 23 Aug 2024 15:30:50 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..aed20b6 --- /dev/null +++ b/hw-loongarch-Remove-minimum-and-default-memory-size.patch @@ -0,0 +1,45 @@ +From 858f16ea09fbbac9966ca73b6b86d290a36be6f5 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 15 May 2024 17:39:26 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..5e8a7ba --- /dev/null +++ b/hw-loongarch-Rename-LOONGARCH_MACHINE-with-LOONGARCH.patch @@ -0,0 +1,187 @@ +From 8e2986a6fc5dda2afbe33f723efdacd01f147b7a Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 8 May 2024 11:11:06 +0800 +Subject: [PATCH] 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é +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-Rename-LoongArchMachineState-with-Loong.patch b/hw-loongarch-Rename-LoongArchMachineState-with-Loong.patch new file mode 100644 index 0000000..660c54f --- /dev/null +++ b/hw-loongarch-Rename-LoongArchMachineState-with-Loong.patch @@ -0,0 +1,1323 @@ +From a501582ef5e986bfa9dc198c63582b3e35332643 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 8 May 2024 11:11:07 +0800 +Subject: [PATCH] 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é +--- + 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.41.0.windows.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 0000000..4e597b3 --- /dev/null +++ b/hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch @@ -0,0 +1,45 @@ +From b7217c8f9b3f1d611485bad1263e109484a743e3 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Wed, 30 Oct 2024 09:23:59 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..aef06ad --- /dev/null +++ b/hw-loongarch-boot.c-fix-out-of-bound-reading.patch @@ -0,0 +1,34 @@ +From f9cc704bbcf8bb8a06095289921dc88944d0fe94 Mon Sep 17 00:00:00 2001 +From: Dmitry Frolov +Date: Fri, 28 Jun 2024 15:39:10 +0300 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-clean-code.patch b/hw-loongarch-clean-code.patch new file mode 100644 index 0000000..2158d94 --- /dev/null +++ b/hw-loongarch-clean-code.patch @@ -0,0 +1,196 @@ +From 4a74147e1b2e276eb2ad2855bafc3c0136bc18a3 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 22:34:57 +0800 +Subject: [PATCH] hw/loongarch: clean code + +remove some unused code + +Signed-off-by: gaosong +--- + 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.41.0.windows.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 0000000..63d4139 --- /dev/null +++ b/hw-loongarch-fdt-adds-Extend-I-O-Interrupt-Controlle.patch @@ -0,0 +1,90 @@ +From ed42940a2d943fd0e666e46bbc9b599b9ed1bd75 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:45 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..113d7d6 --- /dev/null +++ b/hw-loongarch-fdt-adds-cpu-interrupt-controller-node.patch @@ -0,0 +1,68 @@ +From cd506fbf0d9a00aa0f25de1e7bd26ad4335c8257 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:44 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..cfad23a --- /dev/null +++ b/hw-loongarch-fdt-adds-pch_msi-Controller.patch @@ -0,0 +1,92 @@ +From ea34d3896abfaf67cdf7fdb3cb205cc5a0e2e708 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:47 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..830cea5 --- /dev/null +++ b/hw-loongarch-fdt-adds-pch_pic-Controller.patch @@ -0,0 +1,89 @@ +From 78222abb3bde044b4520f23c6fc2f0f0bd805d2a Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:46 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..99b66fa --- /dev/null +++ b/hw-loongarch-fdt-adds-pcie-irq_map-node.patch @@ -0,0 +1,136 @@ +From 1325effbd595781b9ab75dceab9f87944156c606 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:48 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..846e4d8 --- /dev/null +++ b/hw-loongarch-fdt-remove-unused-irqchip-node.patch @@ -0,0 +1,66 @@ +From e87697c72641ab2209d4004f573f47283d118235 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 26 Apr 2024 17:15:49 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-fix-cpu-hotplug-reset.patch b/hw-loongarch-fix-cpu-hotplug-reset.patch new file mode 100644 index 0000000..fb1e85d --- /dev/null +++ b/hw-loongarch-fix-cpu-hotplug-reset.patch @@ -0,0 +1,50 @@ +From f3f7b49a8a323ebfe2be176985336aaf2c97c6c2 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Mon, 9 Sep 2024 04:14:49 +0800 +Subject: [PATCH] hw/loongarch: fix cpu hotplug reset + +Signed-off-by: gaosong +--- + 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.41.0.windows.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 0000000..4c6dfd2 --- /dev/null +++ b/hw-loongarch-move-memory-map-to-boot.c.patch @@ -0,0 +1,112 @@ +From 5e4d612de23539499b9a22986bebe9a3007edae1 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Tue, 7 May 2024 16:51:35 +0200 +Subject: [PATCH] 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é +--- + .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.41.0.windows.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 0000000..8751bc1 --- /dev/null +++ b/hw-loongarch-virt-Add-CPU-topology-support.patch @@ -0,0 +1,277 @@ +From 8d440efd992fd6be0aca55118a9b60c224f6eade Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 23 Oct 2024 15:13:10 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..9d9f026 --- /dev/null +++ b/hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch @@ -0,0 +1,83 @@ +From fa276847efb3fd47a730d279f1b14705fe3991b1 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 18 Sep 2024 09:42:06 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..849d792 --- /dev/null +++ b/hw-loongarch-virt-Add-basic-CPU-plug-support.patch @@ -0,0 +1,345 @@ +From 212ea93178ad1e65e625ec6942ee9aff93dd5321 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 23 Oct 2024 15:13:11 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..562b976 --- /dev/null +++ b/hw-loongarch-virt-Add-description-for-virt-machine-t.patch @@ -0,0 +1,44 @@ +From 080ca7865257d70b6be671cbc17a97c5ebffbd68 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Fri, 13 Sep 2024 17:52:02 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/hw-loongarch-virt-Remove-unused-assignment.patch b/hw-loongarch-virt-Remove-unused-assignment.patch new file mode 100644 index 0000000..2faca66 --- /dev/null +++ b/hw-loongarch-virt-Remove-unused-assignment.patch @@ -0,0 +1,58 @@ +From 5e0ec61ac98a025124912fc47552550b471ab638 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 12 Jun 2024 11:36:37 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..c6cd1aa --- /dev/null +++ b/hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch @@ -0,0 +1,141 @@ +From a3728999125cd9fc9e3e841b66a1677663933c27 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 23 Oct 2024 15:13:12 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..f8b95f7 --- /dev/null +++ b/hw-loongarch-virt-Use-MemTxAttrs-interface-for-misc-.patch @@ -0,0 +1,75 @@ +From b63b7b0b6c9bed8e1a316f3838aab7db2e8f2037 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Tue, 28 May 2024 16:38:54 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..9df973d --- /dev/null +++ b/hw-loongarch-virt-pass-random-seed-to-fdt.patch @@ -0,0 +1,65 @@ +From 573f3bec8137caf829457620380d794165c96a92 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 5 Sep 2024 17:33:16 +0200 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..80d3fac --- /dev/null +++ b/hw-loongarch-virt-support-up-to-4-serial-ports.patch @@ -0,0 +1,171 @@ +From 04895c794652c5da1ece0cad82741bed9aa8ad02 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sat, 7 Sep 2024 16:34:39 +0200 +Subject: [PATCH] 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> +--- + 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.41.0.windows.1 + diff --git a/hw-misc-psp-Pin-the-hugepage-memory-specified-by-mem.patch b/hw-misc-psp-Pin-the-hugepage-memory-specified-by-mem.patch new file mode 100644 index 0000000..bf29af8 --- /dev/null +++ b/hw-misc-psp-Pin-the-hugepage-memory-specified-by-mem.patch @@ -0,0 +1,212 @@ +From ddaa38853d386e5b9f9fa1c3813048872c8ad687 Mon Sep 17 00:00:00 2001 +From: niuyongwen +Date: Sun, 29 Sep 2024 09:45:15 +0800 +Subject: [PATCH] hw/misc/psp: Pin the hugepage memory specified by mem2 during + use for psp + +Signed-off-by: niuyongwen +--- + hw/misc/psp.c | 138 +++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 121 insertions(+), 17 deletions(-) + +diff --git a/hw/misc/psp.c b/hw/misc/psp.c +index 4eb5ca0e0b..03e8663027 100644 +--- a/hw/misc/psp.c ++++ b/hw/misc/psp.c +@@ -17,6 +17,7 @@ + #include "sysemu/runstate.h" + #include "exec/memory.h" + #include "exec/address-spaces.h" ++#include "exec/ramblock.h" + #include "hw/i386/e820_memory_layout.h" + #include + +@@ -38,6 +39,8 @@ struct PSPDevState { + * the TKM module uses different key spaces based on different vids. + */ + uint32_t vid; ++ /* pinned hugepage numbers */ ++ int hp_num; + }; + + #define PSP_DEV_PATH "/dev/hygon_psp_config" +@@ -45,6 +48,8 @@ struct PSPDevState { + #define PSP_IOC_MUTEX_ENABLE _IOWR(HYGON_PSP_IOC_TYPE, 1, NULL) + #define PSP_IOC_MUTEX_DISABLE _IOWR(HYGON_PSP_IOC_TYPE, 2, NULL) + #define PSP_IOC_VPSP_OPT _IOWR(HYGON_PSP_IOC_TYPE, 3, NULL) ++#define PSP_IOC_PIN_USER_PAGE _IOWR(HYGON_PSP_IOC_TYPE, 4, NULL) ++#define PSP_IOC_UNPIN_USER_PAGE _IOWR(HYGON_PSP_IOC_TYPE, 5, NULL) + + enum VPSP_DEV_CTRL_OPCODE { + VPSP_OP_VID_ADD, +@@ -69,6 +74,109 @@ struct psp_dev_ctrl { + } __attribute__ ((packed)) data; + }; + ++static MemoryRegion *find_memory_region_by_name(MemoryRegion *root, const char *name) { ++ MemoryRegion *subregion; ++ MemoryRegion *result; ++ ++ if (strcmp(root->name, name) == 0) ++ return root; ++ ++ QTAILQ_FOREACH(subregion, &root->subregions, subregions_link) { ++ result = find_memory_region_by_name(subregion, name); ++ if (result) { ++ return result; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int pin_user_hugepage(int fd, uint64_t vaddr) ++{ ++ int ret; ++ ++ ret = ioctl(fd, PSP_IOC_PIN_USER_PAGE, vaddr); ++ /* 22: Invalid argument, some old kernel doesn't support this ioctl command */ ++ if (ret != 0 && errno == EINVAL) { ++ ret = 0; ++ } ++ return ret; ++} ++ ++static int unpin_user_hugepage(int fd, uint64_t vaddr) ++{ ++ int ret; ++ ++ ret = ioctl(fd, PSP_IOC_UNPIN_USER_PAGE, vaddr); ++ /* 22: Invalid argument, some old kernel doesn't support this ioctl command */ ++ if (ret != 0 && errno == EINVAL) { ++ ret = 0; ++ } ++ return ret; ++} ++ ++static int pin_psp_user_hugepages(struct PSPDevState *state, MemoryRegion *root) ++{ ++ int ret = 0; ++ char mr_name[128] = {0}; ++ int i, pinned_num; ++ MemoryRegion *find_mr = NULL; ++ ++ for (i = 0 ; i < state->hp_num; ++i) { ++ sprintf(mr_name, "mem2-%d", i); ++ find_mr = find_memory_region_by_name(root, mr_name); ++ if (!find_mr) { ++ error_report("fail to find memory region by name %s.", mr_name); ++ ret = -ENOMEM; ++ goto end; ++ } ++ ++ ret = pin_user_hugepage(state->dev_fd, (uint64_t)find_mr->ram_block->host); ++ if (ret) { ++ error_report("fail to pin_user_hugepage, ret: %d.", ret); ++ goto end; ++ } ++ } ++end: ++ if (ret) { ++ pinned_num = i; ++ for (i = 0 ; i < pinned_num; ++i) { ++ sprintf(mr_name, "mem2-%d", i); ++ find_mr = find_memory_region_by_name(root, mr_name); ++ if (!find_mr) { ++ continue; ++ } ++ unpin_user_hugepage(state->dev_fd, (uint64_t)find_mr->ram_block->host); ++ } ++ ++ } ++ return ret; ++} ++ ++static int unpin_psp_user_hugepages(struct PSPDevState *state, MemoryRegion *root) ++{ ++ int ret = 0; ++ char mr_name[128] = {0}; ++ int i; ++ MemoryRegion *find_mr = NULL; ++ ++ for (i = 0 ; i < state->hp_num; ++i) { ++ sprintf(mr_name, "mem2-%d", i); ++ find_mr = find_memory_region_by_name(root, mr_name); ++ if (!find_mr) { ++ continue; ++ } ++ ++ ret = unpin_user_hugepage(state->dev_fd, (uint64_t)find_mr->ram_block->host); ++ if (ret) { ++ error_report("fail to unpin_user_hugepage, ret: %d.", ret); ++ goto end; ++ } ++ } ++end: ++ return ret; ++} ++ + static void psp_dev_destroy(PSPDevState *state) + { + struct psp_dev_ctrl ctrl = { 0 }; +@@ -77,6 +185,11 @@ static void psp_dev_destroy(PSPDevState *state) + ctrl.op = VPSP_OP_VID_DEL; + if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { + error_report("VPSP_OP_VID_DEL: %d", -errno); ++ } ++ ++ /* Unpin hugepage memory */ ++ if (unpin_psp_user_hugepages(state, get_system_memory())) { ++ error_report("unpin_psp_user_hugepages failed"); + } else { + state->enabled = false; + } +@@ -99,23 +212,6 @@ static void psp_dev_shutdown_notify(Notifier *notifier, void *data) + psp_dev_destroy(state); + } + +-static MemoryRegion *find_memory_region_by_name(MemoryRegion *root, const char *name) { +- MemoryRegion *subregion; +- MemoryRegion *result; +- +- if (strcmp(root->name, name) == 0) +- return root; +- +- QTAILQ_FOREACH(subregion, &root->subregions, subregions_link) { +- result = find_memory_region_by_name(subregion, name); +- if (result) { +- return result; +- } +- } +- +- return NULL; +-} +- + static void psp_dev_realize(DeviceState *dev, Error **errp) + { + int i; +@@ -150,6 +246,8 @@ static void psp_dev_realize(DeviceState *dev, Error **errp) + ram2_end = find_mr->addr + find_mr->size - 1; + } + ++ state->hp_num = i; ++ + if (ram2_start != ram2_end) { + ctrl.op = VPSP_OP_SET_GPA; + ctrl.data.gpa.gpa_start = ram2_start; +@@ -159,6 +257,12 @@ static void psp_dev_realize(DeviceState *dev, Error **errp) + ram2_start, ram2_end, -errno); + goto del_vid; + } ++ ++ /* Pin hugepage memory */ ++ if(pin_psp_user_hugepages(state, root_mr)) { ++ error_setg(errp, "pin_psp_user_hugepages failed."); ++ goto del_vid; ++ } + } + + state->enabled = true; +-- +2.41.0.windows.1 + diff --git a/hw-misc-support-tkm-use-mem2-memory.patch b/hw-misc-support-tkm-use-mem2-memory.patch new file mode 100644 index 0000000..eb9329b --- /dev/null +++ b/hw-misc-support-tkm-use-mem2-memory.patch @@ -0,0 +1,123 @@ +From 884c4d6bc101454f0e0f3c779bc1155024b056c3 Mon Sep 17 00:00:00 2001 +From: xiongmengbiao +Date: Wed, 29 May 2024 15:18:55 +0800 +Subject: [PATCH] hw/misc: support tkm use mem2 memory + +Signed-off-by: xiongmengbiao +--- + hw/misc/psp.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 63 insertions(+), 1 deletion(-) + +diff --git a/hw/misc/psp.c b/hw/misc/psp.c +index 6ff2ceec10..4eb5ca0e0b 100644 +--- a/hw/misc/psp.c ++++ b/hw/misc/psp.c +@@ -15,6 +15,9 @@ + #include "migration/vmstate.h" + #include "hw/qdev-properties.h" + #include "sysemu/runstate.h" ++#include "exec/memory.h" ++#include "exec/address-spaces.h" ++#include "hw/i386/e820_memory_layout.h" + #include + + #define TYPE_PSP_DEV "psp" +@@ -46,14 +49,24 @@ struct PSPDevState { + enum VPSP_DEV_CTRL_OPCODE { + VPSP_OP_VID_ADD, + VPSP_OP_VID_DEL, ++ VPSP_OP_SET_DEFAULT_VID_PERMISSION, ++ VPSP_OP_GET_DEFAULT_VID_PERMISSION, ++ VPSP_OP_SET_GPA, + }; + + struct psp_dev_ctrl { + unsigned char op; ++ unsigned char resv[3]; + union { + unsigned int vid; ++ // Set or check the permissions for the default VID ++ unsigned int def_vid_perm; ++ struct { ++ uint64_t gpa_start; ++ uint64_t gpa_end; ++ } gpa; + unsigned char reserved[128]; +- } data; ++ } __attribute__ ((packed)) data; + }; + + static void psp_dev_destroy(PSPDevState *state) +@@ -86,10 +99,32 @@ static void psp_dev_shutdown_notify(Notifier *notifier, void *data) + psp_dev_destroy(state); + } + ++static MemoryRegion *find_memory_region_by_name(MemoryRegion *root, const char *name) { ++ MemoryRegion *subregion; ++ MemoryRegion *result; ++ ++ if (strcmp(root->name, name) == 0) ++ return root; ++ ++ QTAILQ_FOREACH(subregion, &root->subregions, subregions_link) { ++ result = find_memory_region_by_name(subregion, name); ++ if (result) { ++ return result; ++ } ++ } ++ ++ return NULL; ++} ++ + static void psp_dev_realize(DeviceState *dev, Error **errp) + { ++ int i; ++ char mr_name[128] = {0}; + struct psp_dev_ctrl ctrl = { 0 }; + PSPDevState *state = PSP_DEV(dev); ++ MemoryRegion *root_mr = get_system_memory(); ++ MemoryRegion *find_mr = NULL; ++ uint64_t ram2_start = 0, ram2_end = 0; + + state->dev_fd = qemu_open_old(PSP_DEV_PATH, O_RDWR); + if (state->dev_fd < 0) { +@@ -104,9 +139,36 @@ static void psp_dev_realize(DeviceState *dev, Error **errp) + goto end; + } + ++ for (i = 0 ;; ++i) { ++ sprintf(mr_name, "mem2-%d", i); ++ find_mr = find_memory_region_by_name(root_mr, mr_name); ++ if (!find_mr) ++ break; ++ ++ if (!ram2_start) ++ ram2_start = find_mr->addr; ++ ram2_end = find_mr->addr + find_mr->size - 1; ++ } ++ ++ if (ram2_start != ram2_end) { ++ ctrl.op = VPSP_OP_SET_GPA; ++ ctrl.data.gpa.gpa_start = ram2_start; ++ ctrl.data.gpa.gpa_end = ram2_end; ++ if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { ++ error_setg(errp, "psp_dev_realize VPSP_OP_SET_GPA (start 0x%lx, end 0x%lx), return %d", ++ ram2_start, ram2_end, -errno); ++ goto del_vid; ++ } ++ } ++ + state->enabled = true; + state->shutdown_notifier.notify = psp_dev_shutdown_notify; + qemu_register_shutdown_notifier(&state->shutdown_notifier); ++ ++ return; ++del_vid: ++ ctrl.op = VPSP_OP_VID_DEL; ++ ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl); + end: + return; + } +-- +2.41.0.windows.1 + diff --git a/hw-nvme-fix-handling-of-over-committed-queues.patch b/hw-nvme-fix-handling-of-over-committed-queues.patch new file mode 100644 index 0000000..f4db2e7 --- /dev/null +++ b/hw-nvme-fix-handling-of-over-committed-queues.patch @@ -0,0 +1,102 @@ +From c4423b70160eb7ae91dac9f2cf61513758ee017d Mon Sep 17 00:00:00 2001 +From: Klaus Jensen +Date: Tue, 29 Oct 2024 13:15:19 +0100 +Subject: [PATCH] hw/nvme: fix handling of over-committed queues + +If a host chooses to use the SQHD "hint" in the CQE to know if there is +room in the submission queue for additional commands, it may result in a +situation where there are not enough internal resources (struct +NvmeRequest) available to process the command. For a lack of a better +term, the host may "over-commit" the device (i.e., it may have more +inflight commands than the queue size). + +For example, assume a queue with N entries. The host submits N commands +and all are picked up for processing, advancing the head and emptying +the queue. Regardless of which of these N commands complete first, the +SQHD field of that CQE will indicate to the host that the queue is +empty, which allows the host to issue N commands again. However, if the +device has not posted CQEs for all the previous commands yet, the device +will have less than N resources available to process the commands, so +queue processing is suspended. + +And here lies an 11 year latent bug. In the absense of any additional +tail updates on the submission queue, we never schedule the processing +bottom-half again unless we observe a head update on an associated full +completion queue. This has been sufficient to handle N-to-1 SQ/CQ setups +(in the absense of over-commit of course). Incidentially, that "kick all +associated SQs" mechanism can now be killed since we now just schedule +queue processing when we return a processing resource to a non-empty +submission queue, which happens to cover both edge cases. However, we +must retain kicking the CQ if it was previously full. + +So, apparently, no previous driver tested with hw/nvme has ever used +SQHD (e.g., neither the Linux NVMe driver or SPDK uses it). But then OSv +shows up with the driver that actually does. I salute you. + +Fixes: f3c507adcd7b ("NVMe: Initial commit for new storage interface") +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2388 +Reported-by: Waldemar Kozaczuk +Reviewed-by: Keith Busch +Signed-off-by: Klaus Jensen +Signed-off-by: Zhongrui Tang +--- + hw/nvme/ctrl.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index 104aebc5ea..29445938d5 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -1516,9 +1516,16 @@ static void nvme_post_cqes(void *opaque) + stl_le_p(&n->bar.csts, NVME_CSTS_FAILED); + break; + } ++ + QTAILQ_REMOVE(&cq->req_list, req, entry); ++ + nvme_inc_cq_tail(cq); + nvme_sg_unmap(&req->sg); ++ ++ if (QTAILQ_EMPTY(&sq->req_list) && !nvme_sq_empty(sq)) { ++ qemu_bh_schedule(sq->bh); ++ } ++ + QTAILQ_INSERT_TAIL(&sq->req_list, req, entry); + } + if (cq->tail != cq->head) { +@@ -7575,7 +7582,6 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) + /* Completion queue doorbell write */ + + uint16_t new_head = val & 0xffff; +- int start_sqs; + NvmeCQueue *cq; + + qid = (addr - (0x1000 + (1 << 2))) >> 3; +@@ -7626,18 +7632,15 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) + + trace_pci_nvme_mmio_doorbell_cq(cq->cqid, new_head); + +- start_sqs = nvme_cq_full(cq) ? 1 : 0; ++ /* scheduled deferred cqe posting if queue was previously full */ ++ if (nvme_cq_full(cq)) { ++ qemu_bh_schedule(cq->bh); ++ } ++ + cq->head = new_head; + if (!qid && n->dbbuf_enabled) { + stl_le_pci_dma(pci, cq->db_addr, cq->head, MEMTXATTRS_UNSPECIFIED); + } +- if (start_sqs) { +- NvmeSQueue *sq; +- QTAILQ_FOREACH(sq, &cq->sq_list, entry) { +- qemu_bh_schedule(sq->bh); +- } +- qemu_bh_schedule(cq->bh); +- } + + if (cq->tail == cq->head) { + if (cq->irq_enabled) { +-- +2.41.0.windows.1 + diff --git a/hw-ppc-e500-Add-missing-device-tree-properties-to-i2.patch b/hw-ppc-e500-Add-missing-device-tree-properties-to-i2.patch new file mode 100644 index 0000000..267e540 --- /dev/null +++ b/hw-ppc-e500-Add-missing-device-tree-properties-to-i2.patch @@ -0,0 +1,44 @@ +From e025c40fac7d6cc5b4752c392a9c66a074dcaa0b Mon Sep 17 00:00:00 2001 +From: Zhang Jiao +Date: Thu, 14 Nov 2024 14:24:58 +0800 +Subject: [PATCH] hw/ppc/e500: Add missing device tree properties to i2c + controller node +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from b5d65592d931d07d4f4bcb915d018ec9598058b4 + +When compiling a decompiled device tree blob created with dumpdtb, dtc complains +with: + + /soc@e0000000/i2c@3000: incorrect #address-cells for I2C bus + /soc@e0000000/i2c@3000: incorrect #size-cells for I2C bus + +Fix this by adding the missing device tree properties. + +Reviewed-by: Cédric Le Goater +Signed-off-by: Bernhard Beschow +Message-ID: <20241103133412.73536-6-shentey@gmail.com> +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Zhang Jiao +--- + hw/ppc/e500.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c +index 384226296b..8d394d749a 100644 +--- a/hw/ppc/e500.c ++++ b/hw/ppc/e500.c +@@ -203,6 +203,8 @@ static void dt_i2c_create(void *fdt, const char *soc, const char *mpic, + qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0); + qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2); + qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic); ++ qemu_fdt_setprop_cell(fdt, i2c, "#size-cells", 0); ++ qemu_fdt_setprop_cell(fdt, i2c, "#address-cells", 1); + qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c); + + g_free(i2c); +-- +2.41.0.windows.1 + diff --git a/hw-ppc-e500-Prefer-QOM-cast.patch b/hw-ppc-e500-Prefer-QOM-cast.patch new file mode 100644 index 0000000..3008c30 --- /dev/null +++ b/hw-ppc-e500-Prefer-QOM-cast.patch @@ -0,0 +1,44 @@ +From b85c8374d8b78a6ec1c250bb7562423e6f5d89a0 Mon Sep 17 00:00:00 2001 +From: Zhang Jiao +Date: Thu, 14 Nov 2024 15:12:32 +0800 +Subject: [PATCH] hw/ppc/e500: Prefer QOM cast +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from c620b4ee92ed3664a3d98e0fbb0b651e19fba5b6 + +Reviewed-by: BALATON Zoltan +Signed-off-by: Bernhard Beschow +Message-ID: <20241103133412.73536-4-shentey@gmail.com> +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Zhang Jiao +--- + hw/ppc/e500.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c +index 384226296b..df5a20d3ec 100644 +--- a/hw/ppc/e500.c ++++ b/hw/ppc/e500.c +@@ -1024,7 +1024,7 @@ void ppce500_init(MachineState *machine) + sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ)); + memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET, + sysbus_mmio_get_region(s, 0)); +- i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); ++ i2c = I2C_BUS(qdev_get_child_bus(dev, "i2c")); + i2c_slave_create_simple(i2c, "ds1338", RTC_REGS_OFFSET); + + /* eSDHC */ +@@ -1073,7 +1073,7 @@ void ppce500_init(MachineState *machine) + memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET, + sysbus_mmio_get_region(s, 0)); + +- pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); ++ pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0")); + if (!pci_bus) + printf("couldn't create PCI controller!\n"); + +-- +2.41.0.windows.1 + diff --git a/hw-ppc-e500-Remove-unused-irqs-parameter.patch b/hw-ppc-e500-Remove-unused-irqs-parameter.patch new file mode 100644 index 0000000..4b88149 --- /dev/null +++ b/hw-ppc-e500-Remove-unused-irqs-parameter.patch @@ -0,0 +1,44 @@ +From 239e256d5510b9aaa3e099359dcda54970e2f08a Mon Sep 17 00:00:00 2001 +From: Zhang Jiao +Date: Thu, 14 Nov 2024 14:40:02 +0800 +Subject: [PATCH] hw/ppc/e500: Remove unused "irqs" parameter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 2a309354ac5decf78763c9de999bfb42c8612069 + +Reviewed-by: BALATON Zoltan +Signed-off-by: Bernhard Beschow +Message-ID: <20241103133412.73536-5-shentey@gmail.com> +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: Zhang Jiao +--- + hw/ppc/e500.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c +index 384226296b..8ab1ccc969 100644 +--- a/hw/ppc/e500.c ++++ b/hw/ppc/e500.c +@@ -832,7 +832,7 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms, + } + + static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc, +- IrqLines *irqs, Error **errp) ++ Error **errp) + { + #ifdef CONFIG_KVM + DeviceState *dev; +@@ -872,7 +872,7 @@ static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms, + Error *err = NULL; + + if (kvm_kernel_irqchip_allowed()) { +- dev = ppce500_init_mpic_kvm(pmc, irqs, &err); ++ dev = ppce500_init_mpic_kvm(pmc, &err); + } + if (kvm_kernel_irqchip_required() && !dev) { + error_reportf_err(err, +-- +2.41.0.windows.1 + diff --git a/kvm-add-support-for-guest-physical-bits.patch b/kvm-add-support-for-guest-physical-bits.patch new file mode 100644 index 0000000..ce70df9 --- /dev/null +++ b/kvm-add-support-for-guest-physical-bits.patch @@ -0,0 +1,111 @@ +From a2383a2a0537750794223f21156241b1b1e78d2e Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 18 Mar 2024 16:53:35 +0100 +Subject: [PATCH] kvm: add support for guest physical bits + +commit 0d08c423688edcca857f88dab20f1fc56de2b281 upstream. + +Query kvm for supported guest physical address bits, in cpuid +function 80000008, eax[23:16]. Usually this is identical to host +physical address bits. With NPT or EPT being used this might be +restricted to 48 (max 4-level paging address space size) even if +the host cpu supports more physical address bits. + +When set pass this to the guest, using cpuid too. Guest firmware +can use this to figure how big the usable guest physical address +space is, so PCI bar mapping are actually reachable. + +Intel-SIG: commit 0d08c423688e kvm: add support for guest physical bits + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Message-ID: <20240318155336.156197-2-kraxel@redhat.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jason Zeng +--- + target/i386/kvm/kvm-cpu.c | 50 ++++++++++++++++++++++++++++++++------- + 1 file changed, 42 insertions(+), 8 deletions(-) + +diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c +index 9c791b7b05..f76972e47e 100644 +--- a/target/i386/kvm/kvm-cpu.c ++++ b/target/i386/kvm/kvm-cpu.c +@@ -18,10 +18,32 @@ + #include "kvm_i386.h" + #include "hw/core/accel-cpu.h" + ++static void kvm_set_guest_phys_bits(CPUState *cs) ++{ ++ X86CPU *cpu = X86_CPU(cs); ++ uint32_t eax, guest_phys_bits; ++ ++ eax = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x80000008, 0, R_EAX); ++ guest_phys_bits = (eax >> 16) & 0xff; ++ if (!guest_phys_bits) { ++ return; ++ } ++ cpu->guest_phys_bits = guest_phys_bits; ++ if (cpu->guest_phys_bits > cpu->phys_bits) { ++ cpu->guest_phys_bits = cpu->phys_bits; ++ } ++ ++ if (cpu->host_phys_bits && cpu->host_phys_bits_limit && ++ cpu->guest_phys_bits > cpu->host_phys_bits_limit) { ++ cpu->guest_phys_bits = cpu->host_phys_bits_limit; ++ } ++} ++ + static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) + { + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; ++ bool ret; + + /* + * The realize order is important, since x86_cpu_realize() checks if +@@ -32,13 +54,15 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) + * + * realize order: + * +- * x86_cpu_realize(): +- * -> x86_cpu_expand_features() +- * -> cpu_exec_realizefn(): +- * -> accel_cpu_common_realize() +- * kvm_cpu_realizefn() -> host_cpu_realizefn() +- * -> cpu_common_realizefn() +- * -> check/update ucode_rev, phys_bits, mwait ++ * x86_cpu_realizefn(): ++ * x86_cpu_expand_features() ++ * cpu_exec_realizefn(): ++ * accel_cpu_common_realize() ++ * kvm_cpu_realizefn() ++ * host_cpu_realizefn() ++ * kvm_set_guest_phys_bits() ++ * check/update ucode_rev, phys_bits, guest_phys_bits, mwait ++ * cpu_common_realizefn() (via xcc->parent_realize) + */ + if (cpu->max_features) { + if (enable_cpu_pm && kvm_has_waitpkg()) { +@@ -50,7 +74,17 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) + MSR_IA32_UCODE_REV); + } + } +- return host_cpu_realizefn(cs, errp); ++ ret = host_cpu_realizefn(cs, errp); ++ if (!ret) { ++ return ret; ++ } ++ ++ if ((env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) && ++ cpu->guest_phys_bits == -1) { ++ kvm_set_guest_phys_bits(cs); ++ } ++ ++ return true; + } + + static bool lmce_supported(void) +-- +2.41.0.windows.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 0000000..78c0e06 --- /dev/null +++ b/linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch @@ -0,0 +1,38 @@ +From 734b877ee97c73c7cbeeb02c560b9b4e6a8c0dda Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Thu, 17 Oct 2024 10:07:07 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/linux-headers-update-kernel-headers-to-include-CSV3-.patch b/linux-headers-update-kernel-headers-to-include-CSV3-.patch new file mode 100644 index 0000000..24af321 --- /dev/null +++ b/linux-headers-update-kernel-headers-to-include-CSV3-.patch @@ -0,0 +1,79 @@ +From 454079664e1492eeb9b90d1d05598e84dc436f11 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 09:25:19 +0800 +Subject: [PATCH] linux-headers: update kernel headers to include CSV3 + migration cmds + +Four new migration commands are added to support CSV3 migration. + +KVM_CSV3_SEND_ENCRYPT_DATA/KVM_CSV3_RECEIVE_ENCRYPT_DATA cmds are +used to migrate guest's pages. + +KVM_CSV3_SEND_ENCRYPT_CONTEXT/KVM_CSV3_RECEIVE_ENCRYPT_CONTEXT cmds +are used to migration guest's runtime context. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 8487d0889b..8543db844e 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2115,6 +2115,12 @@ enum csv3_cmd_id { + KVM_CSV3_INIT = KVM_CSV3_NR_MIN, + KVM_CSV3_LAUNCH_ENCRYPT_DATA, + KVM_CSV3_LAUNCH_ENCRYPT_VMCB, ++ KVM_CSV3_SEND_ENCRYPT_DATA, ++ KVM_CSV3_SEND_ENCRYPT_CONTEXT, ++ KVM_CSV3_RECEIVE_ENCRYPT_DATA, ++ KVM_CSV3_RECEIVE_ENCRYPT_CONTEXT, ++ ++ KVM_CSV3_NR_MAX, + }; + + struct kvm_csv3_launch_encrypt_data { +@@ -2127,6 +2133,38 @@ struct kvm_csv3_init_data { + __u64 nodemask; + }; + ++struct kvm_csv3_send_encrypt_data { ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 guest_addr_data; ++ __u32 guest_addr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ ++struct kvm_csv3_send_encrypt_context { ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ ++struct kvm_csv3_receive_encrypt_data { ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 guest_addr_data; ++ __u32 guest_addr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ ++struct kvm_csv3_receive_encrypt_context { ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ + #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) + #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) + #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) +-- +2.41.0.windows.1 + diff --git a/loongarch-switch-boards-to-default-y.patch b/loongarch-switch-boards-to-default-y.patch new file mode 100644 index 0000000..7c614df --- /dev/null +++ b/loongarch-switch-boards-to-default-y.patch @@ -0,0 +1,59 @@ +From 0e0326de88282a601ea5178d421242d5b77afbfa Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 25 Jan 2024 13:36:37 +0100 +Subject: [PATCH] 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 +--- + .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.41.0.windows.1 + diff --git a/migration-Fix-file-migration-with-fdset.patch b/migration-Fix-file-migration-with-fdset.patch new file mode 100644 index 0000000..f8f9c95 --- /dev/null +++ b/migration-Fix-file-migration-with-fdset.patch @@ -0,0 +1,65 @@ +From 6c76354fdfbebca55e080fea5ae6bfc8a3db2d91 Mon Sep 17 00:00:00 2001 +From: Fabiano Rosas +Date: Mon, 17 Jun 2024 15:57:17 -0300 +Subject: [PATCH] migration: Fix file migration with fdset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When the "file:" migration support was added we missed the special +case in the qemu_open_old implementation that allows for a particular +file name format to be used to refer to a set of file descriptors that +have been previously provided to QEMU via the add-fd QMP command. + +When using this fdset feature, we should not truncate the migration +file because being given an fd means that the management layer is in +control of the file and will likely already have some data written to +it. This is further indicated by the presence of the 'offset' +argument, which indicates the start of the region where QEMU is +allowed to write. + +Fix the issue by replacing the O_TRUNC flag on open by an ftruncate +call, which will take the offset into consideration. + +Fixes: 385f510df5 ("migration: file URI offset") +Suggested-by: Daniel P. Berrangé +Reviewed-by: Prasad Pandit +Reviewed-by: Peter Xu +Reviewed-by: Daniel P. Berrangé +Signed-off-by: Fabiano Rosas +(cherry picked from commit 6d3279655ac49b806265f08415165f471d33e032) +Signed-off-by: Michael Tokarev +Signed-off-by: zhujun2 +--- + migration/file.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/migration/file.c b/migration/file.c +index 5d4975f43e..fb3f743e54 100644 +--- a/migration/file.c ++++ b/migration/file.c +@@ -46,12 +46,19 @@ void file_start_outgoing_migration(MigrationState *s, + + trace_migration_file_outgoing(filename); + +- fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY | O_TRUNC, +- 0600, errp); ++ fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY, 0600, errp); + if (!fioc) { + return; + } + ++ if (ftruncate(fioc->fd, offset)) { ++ error_setg_errno(errp, errno, ++ "failed to truncate migration file to offset %" PRIx64, ++ offset); ++ object_unref(OBJECT(fioc)); ++ return; ++ } ++ + ioc = QIO_CHANNEL(fioc); + if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) { + return; +-- +2.41.0.windows.1 + diff --git a/migration-fix-possible-int-overflow.patch b/migration-fix-possible-int-overflow.patch new file mode 100644 index 0000000..71b7875 --- /dev/null +++ b/migration-fix-possible-int-overflow.patch @@ -0,0 +1,35 @@ +From 254c67a88ab54fdfe1eb55d7efaf4386a9597cd0 Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Sat, 16 Nov 2024 17:38:50 +0800 +Subject: [PATCH] migration: fix-possible-int-overflow + +stat64_add() takes uint64_t as 2nd argument, but both +"p->next_packet_size" and "p->packet_len" are uint32_t. +Thus, theyr sum may overflow uint32_t. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Signed-off-by: Dmitry Frolov +Link: https://lore.kernel.org/r/20241113140509.325732-2-frolov@swemel.ru +Signed-off-by: Peter Xu +Signed-off-by: Zhongrui Tang +--- + migration/multifd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/migration/multifd.c b/migration/multifd.c +index 7d373a245e..f3bf6888c0 100644 +--- a/migration/multifd.c ++++ b/migration/multifd.c +@@ -735,7 +735,7 @@ static void *multifd_send_thread(void *opaque) + } + + stat64_add(&mig_stats.multifd_bytes, +- p->next_packet_size + p->packet_len); ++ (uint64_t)p->next_packet_size + p->packet_len); + p->next_packet_size = 0; + qemu_mutex_lock(&p->mutex); + p->pending_job--; +-- +2.41.0.windows.1 + diff --git a/next-kbd-convert-to-use-qemu_input_handler_register.patch b/next-kbd-convert-to-use-qemu_input_handler_register.patch new file mode 100644 index 0000000..5c601fd --- /dev/null +++ b/next-kbd-convert-to-use-qemu_input_handler_register.patch @@ -0,0 +1,224 @@ +From 91e07a78026caafa181134beeb8c5b79157718ad Mon Sep 17 00:00:00 2001 +From: Mark Cave-Ayland +Date: Wed, 6 Nov 2024 12:09:27 +0000 +Subject: [PATCH] next-kbd: convert to use qemu_input_handler_register() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Convert the next-kbd device from the legacy UI qemu_add_kbd_event_handler() +function to use qemu_input_handler_register(). + +Signed-off-by: Mark Cave-Ayland +Reviewed-by: Thomas Huth +Reviewed-by: Daniel P. Berrangé +Message-ID: <20241106120928.242443-2-mark.cave-ayland@ilande.co.uk> +[thuth: Removed the NEXTKBD_NO_KEY definition - replaced by 0 now] +Signed-off-by: Thomas Huth +Signed-off-by: Zhongrui Tang +--- + hw/m68k/next-kbd.c | 158 +++++++++++++++++++++++++++++---------------- + 1 file changed, 103 insertions(+), 55 deletions(-) + +diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c +index 0c348c18cf..880ebe3602 100644 +--- a/hw/m68k/next-kbd.c ++++ b/hw/m68k/next-kbd.c +@@ -68,7 +68,6 @@ struct NextKBDState { + uint16_t shift; + }; + +-static void queue_code(void *opaque, int code); + + /* lots of magic numbers here */ + static uint32_t kbd_read_byte(void *opaque, hwaddr addr) +@@ -166,68 +165,70 @@ static const MemoryRegionOps kbd_ops = { + .endianness = DEVICE_NATIVE_ENDIAN, + }; + +-static void nextkbd_event(void *opaque, int ch) +-{ +- /* +- * Will want to set vars for caps/num lock +- * if (ch & 0x80) -> key release +- * there's also e0 escaped scancodes that might need to be handled +- */ +- queue_code(opaque, ch); +-} +- +-static const unsigned char next_keycodes[128] = { +- 0x00, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x50, 0x4F, +- 0x4E, 0x1E, 0x1F, 0x20, 0x1D, 0x1C, 0x1B, 0x00, +- 0x42, 0x43, 0x44, 0x45, 0x48, 0x47, 0x46, 0x06, +- 0x07, 0x08, 0x00, 0x00, 0x2A, 0x00, 0x39, 0x3A, +- 0x3B, 0x3C, 0x3D, 0x40, 0x3F, 0x3E, 0x2D, 0x2C, +- 0x2B, 0x26, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34, +- 0x35, 0x37, 0x36, 0x2e, 0x2f, 0x30, 0x00, 0x00, +- 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ++static const int qcode_to_nextkbd_keycode[] = { ++ [Q_KEY_CODE_ESC] = 0x49, ++ [Q_KEY_CODE_1] = 0x4a, ++ [Q_KEY_CODE_2] = 0x4b, ++ [Q_KEY_CODE_3] = 0x4c, ++ [Q_KEY_CODE_4] = 0x4d, ++ [Q_KEY_CODE_5] = 0x50, ++ [Q_KEY_CODE_6] = 0x4f, ++ [Q_KEY_CODE_7] = 0x4e, ++ [Q_KEY_CODE_8] = 0x1e, ++ [Q_KEY_CODE_9] = 0x1f, ++ [Q_KEY_CODE_0] = 0x20, ++ [Q_KEY_CODE_MINUS] = 0x1d, ++ [Q_KEY_CODE_EQUAL] = 0x1c, ++ [Q_KEY_CODE_BACKSPACE] = 0x1b, ++ ++ [Q_KEY_CODE_Q] = 0x42, ++ [Q_KEY_CODE_W] = 0x43, ++ [Q_KEY_CODE_E] = 0x44, ++ [Q_KEY_CODE_R] = 0x45, ++ [Q_KEY_CODE_T] = 0x48, ++ [Q_KEY_CODE_Y] = 0x47, ++ [Q_KEY_CODE_U] = 0x46, ++ [Q_KEY_CODE_I] = 0x06, ++ [Q_KEY_CODE_O] = 0x07, ++ [Q_KEY_CODE_P] = 0x08, ++ [Q_KEY_CODE_RET] = 0x2a, ++ [Q_KEY_CODE_A] = 0x39, ++ [Q_KEY_CODE_S] = 0x3a, ++ ++ [Q_KEY_CODE_D] = 0x3b, ++ [Q_KEY_CODE_F] = 0x3c, ++ [Q_KEY_CODE_G] = 0x3d, ++ [Q_KEY_CODE_H] = 0x40, ++ [Q_KEY_CODE_J] = 0x3f, ++ [Q_KEY_CODE_K] = 0x3e, ++ [Q_KEY_CODE_L] = 0x2d, ++ [Q_KEY_CODE_SEMICOLON] = 0x2c, ++ [Q_KEY_CODE_APOSTROPHE] = 0x2b, ++ [Q_KEY_CODE_GRAVE_ACCENT] = 0x26, ++ [Q_KEY_CODE_Z] = 0x31, ++ [Q_KEY_CODE_X] = 0x32, ++ [Q_KEY_CODE_C] = 0x33, ++ [Q_KEY_CODE_V] = 0x34, ++ ++ [Q_KEY_CODE_B] = 0x35, ++ [Q_KEY_CODE_N] = 0x37, ++ [Q_KEY_CODE_M] = 0x36, ++ [Q_KEY_CODE_COMMA] = 0x2e, ++ [Q_KEY_CODE_DOT] = 0x2f, ++ [Q_KEY_CODE_SLASH] = 0x30, ++ ++ [Q_KEY_CODE_SPC] = 0x38, + }; + +-static void queue_code(void *opaque, int code) ++static void nextkbd_put_keycode(NextKBDState *s, int keycode) + { +- NextKBDState *s = NEXTKBD(opaque); + KBDQueue *q = &s->queue; +- int key = code & KD_KEYMASK; +- int release = code & 0x80; +- static int ext; +- +- if (code == 0xE0) { +- ext = 1; +- } +- +- if (code == 0x2A || code == 0x1D || code == 0x36) { +- if (code == 0x2A) { +- s->shift = KD_LSHIFT; +- } else if (code == 0x36) { +- s->shift = KD_RSHIFT; +- ext = 0; +- } else if (code == 0x1D && !ext) { +- s->shift = KD_LCOMM; +- } else if (code == 0x1D && ext) { +- ext = 0; +- s->shift = KD_RCOMM; +- } +- return; +- } else if (code == (0x2A | 0x80) || code == (0x1D | 0x80) || +- code == (0x36 | 0x80)) { +- s->shift = 0; +- return; +- } + + if (q->count >= KBD_QUEUE_SIZE) { + return; + } + +- q->data[q->wptr] = next_keycodes[key] | release; +- ++ q->data[q->wptr] = keycode; + if (++q->wptr == KBD_QUEUE_SIZE) { + q->wptr = 0; + } +@@ -241,6 +242,53 @@ static void queue_code(void *opaque, int code) + /* s->update_irq(s->update_arg, 1); */ + } + ++static void nextkbd_event(DeviceState *dev, QemuConsole *src, InputEvent *evt) ++{ ++ NextKBDState *s = NEXTKBD(dev); ++ int qcode, keycode; ++ bool key_down = evt->u.key.data->down; ++ ++ qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key); ++ if (qcode >= ARRAY_SIZE(qcode_to_nextkbd_keycode)) { ++ return; ++ } ++ ++ /* Shift key currently has no keycode, so handle separately */ ++ if (qcode == Q_KEY_CODE_SHIFT) { ++ if (key_down) { ++ s->shift |= KD_LSHIFT; ++ } else { ++ s->shift &= ~KD_LSHIFT; ++ } ++ } ++ ++ if (qcode == Q_KEY_CODE_SHIFT_R) { ++ if (key_down) { ++ s->shift |= KD_RSHIFT; ++ } else { ++ s->shift &= ~KD_RSHIFT; ++ } ++ } ++ ++ keycode = qcode_to_nextkbd_keycode[qcode]; ++ if (!keycode) { ++ return; ++ } ++ ++ /* If key release event, create keyboard break code */ ++ if (!key_down) { ++ keycode |= 0x80; ++ } ++ ++ nextkbd_put_keycode(s, keycode); ++} ++ ++static const QemuInputHandler nextkbd_handler = { ++ .name = "QEMU NeXT Keyboard", ++ .mask = INPUT_EVENT_MASK_KEY, ++ .event = nextkbd_event, ++}; ++ + static void nextkbd_reset(DeviceState *dev) + { + NextKBDState *nks = NEXTKBD(dev); +@@ -256,7 +304,7 @@ static void nextkbd_realize(DeviceState *dev, Error **errp) + memory_region_init_io(&s->mr, OBJECT(dev), &kbd_ops, s, "next.kbd", 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); + +- qemu_add_kbd_event_handler(nextkbd_event, s); ++ qemu_input_handler_register(dev, &nextkbd_handler); + } + + static const VMStateDescription nextkbd_vmstate = { +-- +2.41.0.windows.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 0000000..185e9f8 --- /dev/null +++ b/physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch @@ -0,0 +1,91 @@ +From 7efd5d829730d0481659cda91f725df3b141f469 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 16 Jul 2024 12:15:01 +0100 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/qemu-bswap-Undefine-CPU_CONVERT-once-done.patch b/qemu-bswap-Undefine-CPU_CONVERT-once-done.patch new file mode 100644 index 0000000..7240ff2 --- /dev/null +++ b/qemu-bswap-Undefine-CPU_CONVERT-once-done.patch @@ -0,0 +1,37 @@ +From 4fc36060bec2ac7de500068211b1282c38e3e073 Mon Sep 17 00:00:00 2001 +From: Zhang Jiao +Date: Tue, 12 Nov 2024 14:05:45 +0800 +Subject: [PATCH] qemu/bswap: Undefine CPU_CONVERT() once done +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 1d73353f236209e9b5987d7c6b30b2a32b739210 + +Better undefined macros once we are done with them, +like we do few lines later with DO_STN_LDN_P(). + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Thomas Huth +Message-Id: <20241003234211.53644-2-philmd@linaro.org> +Signed-off-by: Zhang Jiao +--- + include/qemu/bswap.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h +index 933a66ee87..49e4944457 100644 +--- a/include/qemu/bswap.h ++++ b/include/qemu/bswap.h +@@ -138,6 +138,8 @@ CPU_CONVERT(le, 16, uint16_t) + CPU_CONVERT(le, 32, uint32_t) + CPU_CONVERT(le, 64, uint64_t) + ++#undef CPU_CONVERT ++ + /* + * Same as cpu_to_le{16,32,64}, except that gcc will figure the result is + * a compile-time constant if you pass in a constant. So this can be +-- +2.41.0.windows.1 + diff --git a/qemu-options-Fix-CXL-Fixed-Memory-Window-interleave-.patch b/qemu-options-Fix-CXL-Fixed-Memory-Window-interleave-.patch new file mode 100644 index 0000000..bdc8e67 --- /dev/null +++ b/qemu-options-Fix-CXL-Fixed-Memory-Window-interleave-.patch @@ -0,0 +1,48 @@ +From 34fc72b12cc4887cb2b551b171f6a76c860b6997 Mon Sep 17 00:00:00 2001 +From: Yuquan Wang +Date: Sun, 7 Apr 2024 16:35:39 +0800 +Subject: [PATCH] qemu-options: Fix CXL Fixed Memory Window + interleave-granularity typo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix the unit typo of interleave-granularity of CXL Fixed Memory +Window in qemu-option.hx. + +Fixes: 03b39fcf64 ("hw/cxl: Make the CFMW a machine parameter.") +Signed-off-by: Yuquan Wang wangyuquan1236@phytium.com.cn +Message-ID: <20240407083539.1488172-2-wangyuquan1236@phytium.com.cn> +[PMD: Reworded] +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit aa88f99c87c0e5d195d6d96190374650553ea61f) +Signed-off-by: zhujun2 +--- + qemu-options.hx | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/qemu-options.hx b/qemu-options.hx +index 9829b1020a..4df4dcea21 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -149,14 +149,14 @@ SRST + platform and configuration dependent. + + ``interleave-granularity=granularity`` sets the granularity of +- interleave. Default 256KiB. Only 256KiB, 512KiB, 1024KiB, 2048KiB +- 4096KiB, 8192KiB and 16384KiB granularities supported. ++ interleave. Default 256 (bytes). Only 256, 512, 1k, 2k, ++ 4k, 8k and 16k granularities supported. + + Example: + + :: + +- -machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512k ++ -machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512 + ERST + + DEF("M", HAS_ARG, QEMU_OPTION_M, +-- +2.41.0.windows.1 + diff --git a/qemu.spec b/qemu.spec index ae2bdd3..1df57e5 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 25 +Release: 26 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 @@ -441,6 +441,128 @@ Patch0424: target-i386-sev-Add-support-for-reuse-ASID-for-diffe.patch Patch0425: Add-virtCCA-Coda-annotation.patch Patch0426: cvm-Add-support-for-TEE-based-national-encryption-ac.patch Patch0427: hw-arm-virt-Keep-Guest-L1-cache-type-consistent-with.patch +Patch0428: target-i386-add-guest-phys-bits-cpu-property.patch +Patch0429: kvm-add-support-for-guest-physical-bits.patch +Patch0430: hw-i386-add-mem2-option-for-qemu.patch +Patch0431: hw-misc-support-tkm-use-mem2-memory.patch +Patch0432: hw-misc-psp-Pin-the-hugepage-memory-specified-by-mem.patch +Patch0433: 9pfs-fix-crash-on-Treaddir-request.patch +Patch0434: hw-nvme-fix-handling-of-over-committed-queues.patch +Patch0435: exec-memop-Remove-unused-memop_big_endian-helper.patch +Patch0436: qemu-bswap-Undefine-CPU_CONVERT-once-done.patch +Patch0437: hw-loongarch-Move-boot-functions-to-boot.c.patch +Patch0438: hw-loongarch-Add-load-initrd.patch +Patch0439: hw-loongarch-Add-slave-cpu-boot_code.patch +Patch0440: hw-loongarch-Add-init_cmdline.patch +Patch0441: hw-loongarch-Init-efi_system_table.patch +Patch0442: hw-loongarch-Init-efi_boot_memmap-table.patch +Patch0443: hw-loongarch-Init-efi_initrd-table.patch +Patch0444: hw-loongarch-Init-efi_fdt-table.patch +Patch0445: hw-loongarch-fdt-adds-cpu-interrupt-controller-node.patch +Patch0446: hw-loongarch-fdt-adds-Extend-I-O-Interrupt-Controlle.patch +Patch0447: hw-loongarch-fdt-adds-pch_pic-Controller.patch +Patch0448: hw-loongarch-fdt-adds-pch_msi-Controller.patch +Patch0449: hw-loongarch-fdt-adds-pcie-irq_map-node.patch +Patch0450: hw-loongarch-fdt-remove-unused-irqchip-node.patch +Patch0451: hw-loongarch-Add-cells-missing-from-uart-node.patch +Patch0452: hw-loongarch-Add-cells-missing-from-rtc-node.patch +Patch0453: loongarch-switch-boards-to-default-y.patch +Patch0454: hw-loongarch-move-memory-map-to-boot.c.patch +Patch0455: hw-loongarch-Rename-LOONGARCH_MACHINE-with-LOONGARCH.patch +Patch0456: hw-loongarch-Rename-LoongArchMachineState-with-Loong.patch +Patch0457: hw-loongarch-Refine-default-numa-id-calculation.patch +Patch0458: hw-loongarch-Add-VM-mode-in-IOCSR-feature-register-i.patch +Patch0459: hw-loongarch-Refine-acpi-srat-table-for-numa-memory.patch +Patch0460: hw-loongarch-Refine-fadt-memory-table-for-numa-memor.patch +Patch0461: hw-loongarch-Refine-fwcfg-memory-map.patch +Patch0462: hw-loongarch-Refine-system-dram-memory-region.patch +Patch0463: hw-loongarch-Remove-minimum-and-default-memory-size.patch +Patch0464: tests-libqos-Add-loongarch-virt-machine-node.patch +Patch0465: hw-loongarch-virt-Use-MemTxAttrs-interface-for-misc-.patch +Patch0466: hw-loongarch-boot.c-fix-out-of-bound-reading.patch +Patch0467: hw-loongarch-Change-the-tpm-support-by-default.patch +Patch0468: hw-loongarch-virt-Remove-unused-assignment.patch +Patch0469: hw-loongarch-Fix-length-for-lowram-in-ACPI-SRAT.patch +Patch0470: hw-loongarch-Remove-default-enable-with-VIRTIO_VGA-d.patch +Patch0471: hw-loongarch-virt-support-up-to-4-serial-ports.patch +Patch0472: hw-loongarch-virt-pass-random-seed-to-fdt.patch +Patch0473: hw-loongarch-Add-acpi-SPCR-table-support.patch +Patch0474: hw-loongarch-virt-Add-description-for-virt-machine-t.patch +Patch0475: hw-loongarch-virt-Add-FDT-table-support-with-acpi-ge.patch +Patch0476: hw-arm-virt-acpi-build.c-Migrate-SPCR-creation-to-co.patch +Patch0477: target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch +Patch0478: target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch +Patch0479: target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch +Patch0480: target-loongarch-Add-loongarch-vector-property-uncon.patch +Patch0481: target-loongarch-kvm-Add-software-breakpoint-support-new.patch +Patch0482: target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch +Patch0483: target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch +Patch0484: target-loongarch-Fix-cpu_reset-set-wrong-CSR_CRMD.patch +Patch0485: target-loongarch-Add-compatible-support-about-VM-reb.patch +Patch0486: target-loongarch-kvm-Add-vCPU-reset-function.patch +Patch0487: target-loongarch-Support-QMP-dump-guest-memory.patch +Patch0488: target-loongarch-fix-Werror-maybe-uninitialized-fals.patch +Patch0489: target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch +Patch0490: target-loongarch-Avoid-bits-shift-exceeding-width-of.patch +Patch0491: sync-loongarch-linux-headers.patch +Patch0492: target-loongarch-Add-loongson-binary-translation-fea.patch +Patch0493: target-loongarch-Implement-lbt-registers-save-restor.patch +Patch0494: target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch +Patch0495: linux-headers-loongarch-Add-kvm_para.h-and-unistd_64.patch +Patch0496: target-loongarch-Add-steal-time-support-on-migration.patch +Patch0497: accel-kvm-Extract-common-KVM-vCPU-creation-parking-c-new.patch +Patch0498: hw-acpi-Move-CPU-ctrl-dev-MMIO-region-len-macro-to-c-new.patch +Patch0499: hw-acpi-Update-ACPI-GED-framework-to-support-vCPU-Ho-new.patch +Patch0500: hw-acpi-Update-CPUs-AML-with-cpu-ctrl-dev-change-new.patch +Patch0501: physmem-Add-helper-function-to-destroy-CPU-AddressSp.patch +Patch0502: gdbstub-Add-helper-function-to-unregister-GDB-regist.patch +Patch0503: accel-kvm-kvm-all-Fixes-the-missing-break-in-vCPU-un.patch +Patch0504: hw-loongarch-virt-Add-CPU-topology-support.patch +Patch0505: hw-loongarch-virt-Add-basic-CPU-plug-support.patch +Patch0506: hw-loongarch-virt-Update-the-ACPI-table-for-hotplug-.patch +Patch0507: hw-loongarch-Add-KVM-IPI-device-support.patch +Patch0508: hw-loongarch-Add-KVM-extioi-device-support.patch +Patch0509: hw-loongarch-Add-KVM-pch-pic-device-support.patch +Patch0510: hw-loongarch-Add-KVM-pch-msi-device-support.patch +Patch0511: hw-loongarch-clean-code.patch +Patch0512: hw-loongarch-boot-Use-warn_report-when-no-kernel-fil.patch +Patch0513: hw-loongarch-fix-cpu-hotplug-reset.patch +Patch0514: next-kbd-convert-to-use-qemu_input_handler_register.patch +Patch0515: target-i386-csv-Add-CSV3-context.patch +Patch0516: target-i386-csv-Add-command-to-initialize-CSV3-conte.patch +Patch0517: target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch +Patch0518: target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch +Patch0519: target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch +Patch0520: target-i386-csv-Do-not-register-unregister-guest-sec.patch +Patch0521: target-i386-csv-Load-initial-image-to-private-memory.patch +Patch0522: vga-Force-full-update-for-CSV3-guest.patch +Patch0523: vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch +Patch0524: linux-headers-update-kernel-headers-to-include-CSV3-.patch +Patch0525: target-i386-csv-Add-support-to-migrate-the-outgoing-.patch +Patch0526: target-i386-csv-Add-support-to-migrate-the-incoming-.patch +Patch0527: target-i386-csv-Add-support-to-migrate-the-outgoing--new.patch +Patch0528: target-i386-csv-Add-support-to-migrate-the-incoming--new.patch +Patch0529: hw-arm-mps2-tz.c-fix-RX-TX-interrupts-order.patch +Patch0530: hw-i386-amd_iommu-Don-t-leak-memory-in-amdvi_update_.patch +Patch0531: hw-ppc-e500-Add-missing-device-tree-properties-to-i2.patch +Patch0532: hw-ppc-e500-Remove-unused-irqs-parameter.patch +Patch0533: sphinx-qapidoc-Fix-to-generate-doc-for-explicit-unbo.patch +Patch0534: hw-ppc-e500-Prefer-QOM-cast.patch +Patch0535: target-arm-Fix-FJCVTZS-vs-flush-to-zero.patch +Patch0536: ui-vnc-don-t-return-an-empty-SASL-mechlist-to-the-cl.patch +Patch0537: migration-Fix-file-migration-with-fdset.patch +Patch0538: tcg-loongarch64-Fix-tcg_out_movi-vs-some-pcrel-point.patch +Patch0539: accel-tcg-Fix-typo-causing-tb-page_addr-1-to-not-be-.patch +Patch0540: target-riscv-Fix-the-element-agnostic-function-probl.patch +Patch0541: qio-Inherit-follow_coroutine_ctx-across-TLS.patch +Patch0542: hw-intc-arm_gic-Fix-handling-of-NS-view-of-GICC_APR-.patch +Patch0543: hvf-arm-Fix-encodings-for-ID_AA64PFR1_EL1-and-debug-.patch +Patch0544: qemu-options-Fix-CXL-Fixed-Memory-Window-interleave-.patch +Patch0545: target-m68k-Map-FPU-exceptions-to-FPSR-register.patch +Patch0546: migration-fix-possible-int-overflow.patch +Patch0547: tcg-Allow-top-bit-of-SIMD_DATA_BITS-to-be-set-in-sim.patch +Patch0548: vdpa-dev-Fix-initialisation-order-to-restore-VDUSE-c.patch +Patch0549: fix-compile-error-on-loongarch.patch BuildRequires: flex BuildRequires: gcc @@ -1038,6 +1160,130 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Thu Dec 12 2024 Jiabo Feng - 11:8.2.0-26 +- fix compile error on loongarch +- vdpa-dev: Fix initialisation order to restore VDUSE compatibility +- tcg: Allow top bit of SIMD_DATA_BITS to be set in simd_desc() +- migration: fix-possible-int-overflow +- target/m68k: Map FPU exceptions to FPSR register +- qemu-options: Fix CXL Fixed Memory Window interleave-granularity typo +- hvf: arm: Fix encodings for ID_AA64PFR1_EL1 and debug System registers +- hw/intc/arm_gic: Fix handling of NS view of GICC_APR +- qio: Inherit follow_coroutine_ctx across TLS +- target/riscv: Fix the element agnostic function problem +- accel/tcg: Fix typo causing tb->page_addr[1] to not be recorded +- tcg/loongarch64: Fix tcg_out_movi vs some pcrel pointers +- migration: Fix file migration with fdset +- ui/vnc: don't return an empty SASL mechlist to the client +- target/arm: Fix FJCVTZS vs flush-to-zero +- hw/ppc/e500: Prefer QOM cast +- sphinx/qapidoc: Fix to generate doc for explicit, unboxed arguments +- hw/ppc/e500: Remove unused "irqs" parameter +- hw/ppc/e500: Add missing device tree properties to i2c controller node +- hw/i386/amd_iommu: Don't leak memory in amdvi_update_iotlb() +- hw/arm/mps2-tz.c: fix RX/TX interrupts order +- target/i386: csv: Add support to migrate the incoming context for CSV3 guest +- target/i386: csv: Add support to migrate the outgoing context for CSV3 guest +- target/i386: csv: Add support to migrate the incoming page for CSV3 guest +- target/i386: csv: Add support to migrate the outgoing page for CSV3 guest +- linux-headers: update kernel headers to include CSV3 migration cmds +- vfio: Only map shared region for CSV3 virtual machine +- vga: Force full update for CSV3 guest +- target/i386: csv: Load initial image to private memory for CSV3 guest +- target/i386: csv: Do not register/unregister guest secure memory for CSV3 guest +- target/i386: cpu: Populate CPUID 0x8000_001F when CSV3 is active +- target/i386: csv: Add command to load vmcb to CSV3 guest memory +- target/i386: csv: Add command to load data to CSV3 guest memory +- target/i386: csv: Add command to initialize CSV3 context +- target/i386: csv: Add CSV3 context +- next-kbd: convert to use qemu_input_handler_register() +- 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 +- qemu/bswap: Undefine CPU_CONVERT() once done +- exec/memop: Remove unused memop_big_endian() helper +- hw/nvme: fix handling of over-committed queues +- 9pfs: fix crash on 'Treaddir' request +- hw/misc/psp: Pin the hugepage memory specified by mem2 during use for psp +- hw/misc: support tkm use mem2 memory +- hw/i386: add mem2 option for qemu +- kvm: add support for guest physical bits +- target/i386: add guest-phys-bits cpu property + * Sat Nov 30 2024 Jiabo Feng - 11:8.2.0-25 - hw/arm/virt:Keep Guest L1 cache type consistent with KVM - cvm : Add support for TEE-based national encryption acceleration. diff --git a/qio-Inherit-follow_coroutine_ctx-across-TLS.patch b/qio-Inherit-follow_coroutine_ctx-across-TLS.patch new file mode 100644 index 0000000..81909d5 --- /dev/null +++ b/qio-Inherit-follow_coroutine_ctx-across-TLS.patch @@ -0,0 +1,121 @@ +From 4dccc6603af2cd3deefb6ac94c3e7aec4b60485d Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Fri, 17 May 2024 21:50:14 -0500 +Subject: [PATCH] qio: Inherit follow_coroutine_ctx across TLS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since qemu 8.2, the combination of NBD + TLS + iothread crashes on an +assertion failure: + +qemu-kvm: ../io/channel.c:534: void qio_channel_restart_read(void *): Assertion `qemu_get_current_aio_context() == qemu_coroutine_get_aio_context(co)' failed. + +It turns out that when we removed AioContext locking, we did so by +having NBD tell its qio channels that it wanted to opt in to +qio_channel_set_follow_coroutine_ctx(); but while we opted in on the +main channel, we did not opt in on the TLS wrapper channel. +qemu-iotests has coverage of NBD+iothread and NBD+TLS, but apparently +no coverage of NBD+TLS+iothread, or we would have noticed this +regression sooner. (I'll add that in the next patch) + +But while we could manually opt in to the TLS channel in nbd/server.c +(a one-line change), it is more generic if all qio channels that wrap +other channels inherit the follow status, in the same way that they +inherit feature bits. + +CC: Stefan Hajnoczi +CC: Daniel P. Berrangé +CC: qemu-stable@nongnu.org +Fixes: https://issues.redhat.com/browse/RHEL-34786 +Fixes: 06e0f098 ("io: follow coroutine AioContext in qio_channel_yield()", v8.2.0) +Signed-off-by: Eric Blake +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Daniel P. Berrangé +Message-ID: <20240518025246.791593-5-eblake@redhat.com> +(cherry picked from commit 199e84de1c903ba5aa1f7256310bbc4a20dd930b) +Signed-off-by: zhujun2 +--- + io/channel-tls.c | 26 +++++++++++++++----------- + io/channel-websock.c | 1 + + 2 files changed, 16 insertions(+), 11 deletions(-) + +diff --git a/io/channel-tls.c b/io/channel-tls.c +index 58fe1aceee..a8ad89c3d1 100644 +--- a/io/channel-tls.c ++++ b/io/channel-tls.c +@@ -69,37 +69,40 @@ qio_channel_tls_new_server(QIOChannel *master, + const char *aclname, + Error **errp) + { +- QIOChannelTLS *ioc; ++ QIOChannelTLS *tioc; ++ QIOChannel *ioc; + +- ioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS)); ++ tioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS)); ++ ioc = QIO_CHANNEL(tioc); + +- ioc->master = master; ++ tioc->master = master; ++ ioc->follow_coroutine_ctx = master->follow_coroutine_ctx; + if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) { +- qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SHUTDOWN); ++ qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); + } + object_ref(OBJECT(master)); + +- ioc->session = qcrypto_tls_session_new( ++ tioc->session = qcrypto_tls_session_new( + creds, + NULL, + aclname, + QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, + errp); +- if (!ioc->session) { ++ if (!tioc->session) { + goto error; + } + + qcrypto_tls_session_set_callbacks( +- ioc->session, ++ tioc->session, + qio_channel_tls_write_handler, + qio_channel_tls_read_handler, +- ioc); ++ tioc); + +- trace_qio_channel_tls_new_server(ioc, master, creds, aclname); +- return ioc; ++ trace_qio_channel_tls_new_server(tioc, master, creds, aclname); ++ return tioc; + + error: +- object_unref(OBJECT(ioc)); ++ object_unref(OBJECT(tioc)); + return NULL; + } + +@@ -116,6 +119,7 @@ qio_channel_tls_new_client(QIOChannel *master, + ioc = QIO_CHANNEL(tioc); + + tioc->master = master; ++ ioc->follow_coroutine_ctx = master->follow_coroutine_ctx; + if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) { + qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); + } +diff --git a/io/channel-websock.c b/io/channel-websock.c +index a12acc27cf..de39f0d182 100644 +--- a/io/channel-websock.c ++++ b/io/channel-websock.c +@@ -883,6 +883,7 @@ qio_channel_websock_new_server(QIOChannel *master) + ioc = QIO_CHANNEL(wioc); + + wioc->master = master; ++ ioc->follow_coroutine_ctx = master->follow_coroutine_ctx; + if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) { + qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); + } +-- +2.41.0.windows.1 + diff --git a/sphinx-qapidoc-Fix-to-generate-doc-for-explicit-unbo.patch b/sphinx-qapidoc-Fix-to-generate-doc-for-explicit-unbo.patch new file mode 100644 index 0000000..9388ea1 --- /dev/null +++ b/sphinx-qapidoc-Fix-to-generate-doc-for-explicit-unbo.patch @@ -0,0 +1,156 @@ +From c7fe47e4aab35c1817c4c53f0025a741a9e2ad57 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 28 Jun 2024 13:27:56 +0200 +Subject: [PATCH] sphinx/qapidoc: Fix to generate doc for explicit, unboxed + arguments + +When a command's arguments are specified as an explicit type T, +generated documentation points to the members of T. + +Example: + + ## + # @announce-self: + # + # Trigger generation of broadcast RARP frames to update network + [...] + ## + { 'command': 'announce-self', 'boxed': true, + 'data' : 'AnnounceParameters'} + +generates + + "announce-self" (Command) + ------------------------- + + Trigger generation of broadcast RARP frames to update network + [...] + + Arguments + ~~~~~~~~~ + + The members of "AnnounceParameters" + +Except when the command takes its arguments unboxed , i.e. it doesn't +have 'boxed': true, we generate *nothing*. A few commands have a +reference in their doc comment to compensate, but most don't. + +Example: + + ## + # @blockdev-snapshot-sync: + # + # Takes a synchronous snapshot of a block device. + # + # For the arguments, see the documentation of BlockdevSnapshotSync. + [...] + ## + { 'command': 'blockdev-snapshot-sync', + 'data': 'BlockdevSnapshotSync', + 'allow-preconfig': true } + +generates + + "blockdev-snapshot-sync" (Command) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Takes a synchronous snapshot of a block device. + + For the arguments, see the documentation of BlockdevSnapshotSync. + [...] + +Same for event data. + +Fix qapidoc.py to generate the reference regardless of boxing. Delete +now redundant references in the doc comments. + +Fixes: 4078ee5469e5 (docs/sphinx: Add new qapi-doc Sphinx extension) +Cc: qemu-stable@nongnu.org +Signed-off-by: Markus Armbruster +Message-ID: <20240628112756.794237-1-armbru@redhat.com> +Reviewed-by: John Snow +(cherry picked from commit e389929d19a543ea5b34d02553b355f9f1c03162) +Signed-off-by: zhujun2 +--- + docs/sphinx/qapidoc.py | 12 +++++------- + qapi/block-core.json | 7 ------- + 2 files changed, 5 insertions(+), 14 deletions(-) + +diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py +index 658c288f8f..3d19853444 100644 +--- a/docs/sphinx/qapidoc.py ++++ b/docs/sphinx/qapidoc.py +@@ -229,15 +229,15 @@ def _nodes_for_enum_values(self, doc): + section += dlnode + return [section] + +- def _nodes_for_arguments(self, doc, boxed_arg_type): ++ def _nodes_for_arguments(self, doc, arg_type): + """Return list of doctree nodes for the arguments section""" +- if boxed_arg_type: ++ if arg_type and not arg_type.is_implicit(): + assert not doc.args + section = self._make_section('Arguments') + dlnode = nodes.definition_list() + dlnode += self._make_dlitem( + [nodes.Text('The members of '), +- nodes.literal('', boxed_arg_type.name)], ++ nodes.literal('', arg_type.name)], + None) + section += dlnode + return [section] +@@ -341,8 +341,7 @@ def visit_command(self, name, info, ifcond, features, arg_type, + allow_preconfig, coroutine): + doc = self._cur_doc + self._add_doc('Command', +- self._nodes_for_arguments(doc, +- arg_type if boxed else None) ++ self._nodes_for_arguments(doc, arg_type) + + self._nodes_for_features(doc) + + self._nodes_for_sections(doc) + + self._nodes_for_if_section(ifcond)) +@@ -350,8 +349,7 @@ def visit_command(self, name, info, ifcond, features, arg_type, + def visit_event(self, name, info, ifcond, features, arg_type, boxed): + doc = self._cur_doc + self._add_doc('Event', +- self._nodes_for_arguments(doc, +- arg_type if boxed else None) ++ self._nodes_for_arguments(doc, arg_type) + + self._nodes_for_features(doc) + + self._nodes_for_sections(doc) + + self._nodes_for_if_section(ifcond)) +diff --git a/qapi/block-core.json b/qapi/block-core.json +index ded6f0f6d2..0fa184698a 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1662,8 +1662,6 @@ + # + # Takes a synchronous snapshot of a block device. + # +-# For the arguments, see the documentation of BlockdevSnapshotSync. +-# + # Returns: + # - nothing on success + # - If @device is not a valid block device, DeviceNotFound +@@ -1693,8 +1691,6 @@ + # device, the block device changes to using 'overlay' as its new + # active image. + # +-# For the arguments, see the documentation of BlockdevSnapshot. +-# + # Features: + # + # @allow-write-only-overlay: If present, the check whether this +@@ -6037,9 +6033,6 @@ + # string, or a snapshot with name already exists, the operation will + # fail. + # +-# For the arguments, see the documentation of +-# BlockdevSnapshotInternal. +-# + # Returns: + # - nothing on success + # - If @device is not a valid block device, GenericError +-- +2.41.0.windows.1 + diff --git a/sync-loongarch-linux-headers.patch b/sync-loongarch-linux-headers.patch new file mode 100644 index 0000000..c5e999b --- /dev/null +++ b/sync-loongarch-linux-headers.patch @@ -0,0 +1,96 @@ +From 23cede66eaa62e8ec559cfa538a59e72375c9fa8 Mon Sep 17 00:00:00 2001 +From: gaosong +Date: Sun, 8 Sep 2024 03:28:16 +0800 +Subject: [PATCH] sync loongarch linux-headers + +Signed-off-by: gaosong +--- + 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.41.0.windows.1 + diff --git a/target-arm-Fix-FJCVTZS-vs-flush-to-zero.patch b/target-arm-Fix-FJCVTZS-vs-flush-to-zero.patch new file mode 100644 index 0000000..9bd34d7 --- /dev/null +++ b/target-arm-Fix-FJCVTZS-vs-flush-to-zero.patch @@ -0,0 +1,106 @@ +From 148e01eba8041bad93081a19a240034bb8138988 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Tue, 25 Jun 2024 11:35:26 -0700 +Subject: [PATCH] target/arm: Fix FJCVTZS vs flush-to-zero + +Input denormals cause the Javascript inexact bit +(output to Z) to be set. + +Cc: qemu-stable@nongnu.org +Fixes: 6c1f6f2733a ("target/arm: Implement ARMv8.3-JSConv") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2375 +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Message-id: 20240625183536.1672454-4-richard.henderson@linaro.org +[PMM: fixed hardcoded tab in test case] +Signed-off-by: Peter Maydell +(cherry picked from commit 7619129f0d4a14d918227c5c47ad7433662e9ccc) +Signed-off-by: zhujun2 +--- + target/arm/vfp_helper.c | 18 +++++++++--------- + tests/tcg/aarch64/Makefile.target | 3 ++- + tests/tcg/aarch64/test-2375.c | 21 +++++++++++++++++++++ + 3 files changed, 32 insertions(+), 10 deletions(-) + create mode 100644 tests/tcg/aarch64/test-2375.c + +diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c +index 3e5e37abbe..ff59bc5522 100644 +--- a/target/arm/vfp_helper.c ++++ b/target/arm/vfp_helper.c +@@ -1121,8 +1121,8 @@ const FloatRoundMode arm_rmode_to_sf_map[] = { + uint64_t HELPER(fjcvtzs)(float64 value, void *vstatus) + { + float_status *status = vstatus; +- uint32_t inexact, frac; +- uint32_t e_old, e_new; ++ uint32_t frac, e_old, e_new; ++ bool inexact; + + e_old = get_float_exception_flags(status); + set_float_exception_flags(0, status); +@@ -1130,13 +1130,13 @@ uint64_t HELPER(fjcvtzs)(float64 value, void *vstatus) + e_new = get_float_exception_flags(status); + set_float_exception_flags(e_old | e_new, status); + +- if (value == float64_chs(float64_zero)) { +- /* While not inexact for IEEE FP, -0.0 is inexact for JavaScript. */ +- inexact = 1; +- } else { +- /* Normal inexact or overflow or NaN */ +- inexact = e_new & (float_flag_inexact | float_flag_invalid); +- } ++ /* Normal inexact, denormal with flush-to-zero, or overflow or NaN */ ++ inexact = e_new & (float_flag_inexact | ++ float_flag_input_denormal | ++ float_flag_invalid); ++ ++ /* While not inexact for IEEE FP, -0.0 is inexact for JavaScript. */ ++ inexact |= value == float64_chs(float64_zero); + + /* Pack the result and the env->ZF representation of Z together. */ + return deposit64(frac, 32, 32, inexact); +diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target +index cded1d01fc..6d593c6392 100644 +--- a/tests/tcg/aarch64/Makefile.target ++++ b/tests/tcg/aarch64/Makefile.target +@@ -40,8 +40,9 @@ endif + + # Pauth Tests + ifneq ($(CROSS_CC_HAS_ARMV8_3),) +-AARCH64_TESTS += pauth-1 pauth-2 pauth-4 pauth-5 ++AARCH64_TESTS += pauth-1 pauth-2 pauth-4 pauth-5 test-2375 + pauth-%: CFLAGS += -march=armv8.3-a ++test-2375: CFLAGS += -march=armv8.3-a + run-pauth-1: QEMU_OPTS += -cpu max + run-pauth-2: QEMU_OPTS += -cpu max + # Choose a cpu with FEAT_Pauth but without FEAT_FPAC for pauth-[45]. +diff --git a/tests/tcg/aarch64/test-2375.c b/tests/tcg/aarch64/test-2375.c +new file mode 100644 +index 0000000000..84c7e7de71 +--- /dev/null ++++ b/tests/tcg/aarch64/test-2375.c +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* Copyright (c) 2024 Linaro Ltd */ ++/* See https://gitlab.com/qemu-project/qemu/-/issues/2375 */ ++ ++#include ++ ++int main(void) ++{ ++ int r, z; ++ ++ asm("msr fpcr, %2\n\t" ++ "fjcvtzs %w0, %d3\n\t" ++ "cset %1, eq" ++ : "=r"(r), "=r"(z) ++ : "r"(0x01000000L), /* FZ = 1 */ ++ "w"(0xfcff00L)); /* denormal */ ++ ++ assert(r == 0); ++ assert(z == 0); ++ return 0; ++} +-- +2.41.0.windows.1 + diff --git a/target-i386-add-guest-phys-bits-cpu-property.patch b/target-i386-add-guest-phys-bits-cpu-property.patch new file mode 100644 index 0000000..c2f5b0e --- /dev/null +++ b/target-i386-add-guest-phys-bits-cpu-property.patch @@ -0,0 +1,106 @@ +From b6bfee023b15f25c1db077df7bfd2e9212cda762 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 18 Mar 2024 16:53:36 +0100 +Subject: [PATCH] target/i386: add guest-phys-bits cpu property + +commit 513ba32dccc659c80722b3a43233b26eaa50309a upstream. + +Allows to set guest-phys-bits (cpuid leaf 80000008, eax[23:16]) +via -cpu $model,guest-phys-bits=$nr. + +Intel-SIG: commit 513ba32dccc6 target/i386: add guest-phys-bits cpu property + +Signed-off-by: Gerd Hoffmann +Message-ID: <20240318155336.156197-3-kraxel@redhat.com> +Reviewed-by: Zhao Liu +Signed-off-by: Paolo Bonzini +[jz: compatible property for 9.0 machines not included] +Signed-off-by: Jason Zeng +--- + target/i386/cpu.c | 22 ++++++++++++++++++++++ + target/i386/cpu.h | 8 ++++++++ + 2 files changed, 30 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index ca7e5337b0..93f88b7bf8 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6827,6 +6827,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { + /* 64 bit processor */ + *eax |= (cpu_x86_virtual_addr_width(env) << 8); ++ *eax |= (cpu->guest_phys_bits << 16); + } + *ebx = env->features[FEAT_8000_0008_EBX]; + if (cs->nr_cores * cs->nr_threads > 1) { +@@ -7603,6 +7604,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + goto out; + } + ++ if (cpu->guest_phys_bits == -1) { ++ /* ++ * If it was not set by the user, or by the accelerator via ++ * cpu_exec_realizefn, clear. ++ */ ++ cpu->guest_phys_bits = 0; ++ } ++ + if (cpu->ucode_rev == 0) { + /* + * The default is the same as KVM's. Note that this check +@@ -7653,6 +7662,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + if (cpu->phys_bits == 0) { + cpu->phys_bits = TCG_PHYS_ADDR_BITS; + } ++ if (cpu->guest_phys_bits && ++ (cpu->guest_phys_bits > cpu->phys_bits || ++ cpu->guest_phys_bits < 32)) { ++ error_setg(errp, "guest-phys-bits should be between 32 and %u " ++ " (but is %u)", ++ cpu->phys_bits, cpu->guest_phys_bits); ++ return; ++ } + } else { + /* For 32 bit systems don't use the user set value, but keep + * phys_bits consistent with what we tell the guest. +@@ -7661,6 +7678,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + error_setg(errp, "phys-bits is not user-configurable in 32 bit"); + return; + } ++ if (cpu->guest_phys_bits != 0) { ++ error_setg(errp, "guest-phys-bits is not user-configurable in 32 bit"); ++ return; ++ } + + if (env->features[FEAT_1_EDX] & (CPUID_PSE36 | CPUID_PAE)) { + cpu->phys_bits = 36; +@@ -8167,6 +8188,7 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_BOOL("x-force-features", X86CPU, force_features, false), + DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), + DEFINE_PROP_UINT32("phys-bits", X86CPU, phys_bits, 0), ++ DEFINE_PROP_UINT32("guest-phys-bits", X86CPU, guest_phys_bits, -1), + DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false), + DEFINE_PROP_UINT8("host-phys-bits-limit", X86CPU, host_phys_bits_limit, 0), + DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, false), +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 34f9615b98..d6fdcc04ca 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2029,6 +2029,14 @@ struct ArchCPU { + /* Number of physical address bits supported */ + uint32_t phys_bits; + ++ /* ++ * Number of guest physical address bits available. Usually this is ++ * identical to host physical address bits. With NPT or EPT 4-level ++ * paging, guest physical address space might be restricted to 48 bits ++ * even if the host cpu supports more physical address bits. ++ */ ++ uint32_t guest_phys_bits; ++ + /* in order to simplify APIC support, we leave this pointer to the + user */ + struct DeviceState *apic_state; +-- +2.41.0.windows.1 + diff --git a/target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch b/target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch new file mode 100644 index 0000000..7336234 --- /dev/null +++ b/target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch @@ -0,0 +1,41 @@ +From 120d0b9e5c92de91c69fb9fbea038b51c820013d Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Tue, 24 Aug 2021 17:31:28 +0800 +Subject: [PATCH] target/i386: cpu: Populate CPUID 0x8000_001F when CSV3 is + active + +On Hygon platform, bit 30 of EAX indicates whether +this feature is supported in hardware. + +When CSV3 is active, CPUID 0x8000_001F provides +information for it. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + target/i386/cpu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index ca7e5337b0..36f7ad6460 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -29,6 +29,7 @@ + #include "hvf/hvf-i386.h" + #include "kvm/kvm_i386.h" + #include "sev.h" ++#include "csv.h" + #include "qapi/error.h" + #include "qemu/error-report.h" + #include "qapi/qapi-visit-machine.h" +@@ -6943,6 +6944,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (sev_enabled()) { + *eax = 0x2; + *eax |= sev_es_enabled() ? 0x8 : 0; ++ *eax |= csv3_enabled() ? 0x40000000 : 0; /* bit 30 for CSV3 */ + *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */ + *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */ + } +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Add-CSV3-context.patch b/target-i386-csv-Add-CSV3-context.patch new file mode 100644 index 0000000..3e12a69 --- /dev/null +++ b/target-i386-csv-Add-CSV3-context.patch @@ -0,0 +1,85 @@ +From 54648e0e5a45acf2e472430ee83bb8dfa057fb30 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Tue, 24 Aug 2021 14:57:28 +0800 +Subject: [PATCH] target/i386: csv: Add CSV3 context + +CSV/CSV2/CSV3 are the secure virtualization features on Hygon CPUs. +The CSV and CSV2 are compatible with the AMD SEV and SEV-ES, +respectively. From CSV3, we introduced more secure features to +protect the guest, users can bit 6 of the guest policy to run a +CSV3 guest. + +Add the context and the build option. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + target/i386/csv.c | 11 +++++++++++ + target/i386/csv.h | 17 +++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 88fb05ac37..9a1de04db7 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -18,3 +18,14 @@ + #include "csv.h" + + bool csv_kvm_cpu_reset_inhibit; ++ ++Csv3GuestState csv3_guest = { 0 }; ++ ++bool ++csv3_enabled(void) ++{ ++ if (!is_hygon_cpu()) ++ return false; ++ ++ return sev_es_enabled() && (csv3_guest.policy & GUEST_POLICY_CSV3_BIT); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 05e7fd8dc1..ea87c1ba27 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -14,6 +14,9 @@ + #ifndef I386_CSV_H + #define I386_CSV_H + ++#include "qapi/qapi-commands-misc-target.h" ++ ++#define GUEST_POLICY_CSV3_BIT (1 << 6) + #define GUEST_POLICY_REUSE_ASID (1 << 7) + + #ifdef CONFIG_CSV +@@ -40,9 +43,12 @@ static bool __attribute__((unused)) is_hygon_cpu(void) + return false; + } + ++bool csv3_enabled(void); ++ + #else + + #define is_hygon_cpu() (false) ++#define csv3_enabled() (false) + + #endif + +@@ -66,4 +72,15 @@ int csv_load_queued_incoming_pages(QEMUFile *f); + int csv_save_outgoing_cpu_state(QEMUFile *f, uint64_t *bytes_sent); + int csv_load_incoming_cpu_state(QEMUFile *f); + ++/* CSV3 */ ++struct Csv3GuestState { ++ uint32_t policy; ++ int sev_fd; ++ void *state; ++}; ++ ++typedef struct Csv3GuestState Csv3GuestState; ++ ++extern struct Csv3GuestState csv3_guest; ++ + #endif +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Add-command-to-initialize-CSV3-conte.patch b/target-i386-csv-Add-command-to-initialize-CSV3-conte.patch new file mode 100644 index 0000000..04aea45 --- /dev/null +++ b/target-i386-csv-Add-command-to-initialize-CSV3-conte.patch @@ -0,0 +1,201 @@ +From 4ce59de673b1b190cde76c458ac9e92a6413172d Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 11:07:41 +0800 +Subject: [PATCH] target/i386: csv: Add command to initialize CSV3 context + +When CSV3 is enabled, KVM_CSV3_INIT command is used to initialize +the platform, which is implemented by reusing the SEV API framework +and extending the functionality. + +The KVM_CSV3_INIT command should be performed earlier than +any other command. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 11 +++++++++ + target/i386/csv-sysemu-stub.c | 5 ++++ + target/i386/csv.c | 45 +++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 4 ++++ + target/i386/sev.c | 17 +++++++++++++ + target/i386/sev.h | 7 ++++++ + 6 files changed, 89 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 8dc00808ec..90869068c8 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2108,6 +2108,17 @@ struct kvm_csv_init { + __u32 len; + }; + ++/* CSV3 command */ ++enum csv3_cmd_id { ++ KVM_CSV3_NR_MIN = 0xc0, ++ ++ KVM_CSV3_INIT = KVM_CSV3_NR_MIN, ++}; ++ ++struct kvm_csv3_init_data { ++ __u64 nodemask; ++}; ++ + #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) + #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) + #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index 5874e4cc1d..72f0f5c772 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -14,3 +14,8 @@ + #include "qemu/osdep.h" + #include "sev.h" + #include "csv.h" ++ ++int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) ++{ ++ return 0; ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 9a1de04db7..fd3ea291ca 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -12,6 +12,13 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/error-report.h" ++ ++#include ++ ++#ifdef CONFIG_NUMA ++#include ++#endif + + #include "cpu.h" + #include "sev.h" +@@ -21,6 +28,44 @@ bool csv_kvm_cpu_reset_inhibit; + + Csv3GuestState csv3_guest = { 0 }; + ++int ++csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) ++{ ++ int fw_error; ++ int ret; ++ struct kvm_csv3_init_data data = { 0 }; ++ ++#ifdef CONFIG_NUMA ++ int mode; ++ unsigned long nodemask; ++ ++ /* Set flags as 0 to retrieve the default NUMA policy. */ ++ ret = get_mempolicy(&mode, &nodemask, sizeof(nodemask) * 8, NULL, 0); ++ if (ret == 0 && mode == MPOL_BIND) ++ data.nodemask = nodemask; ++#endif ++ ++ if (!ops || !ops->sev_ioctl || !ops->fw_error_to_str) ++ return -1; ++ ++ csv3_guest.policy = policy; ++ if (csv3_enabled()) { ++ ret = ops->sev_ioctl(fd, KVM_CSV3_INIT, &data, &fw_error); ++ if (ret) { ++ csv3_guest.policy = 0; ++ error_report("%s: Fail to initialize ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, ops->fw_error_to_str(fw_error)); ++ return -1; ++ } ++ ++ csv3_guest.sev_fd = fd; ++ csv3_guest.state = state; ++ csv3_guest.sev_ioctl = ops->sev_ioctl; ++ csv3_guest.fw_error_to_str = ops->fw_error_to_str; ++ } ++ return 0; ++} ++ + bool + csv3_enabled(void) + { +diff --git a/target/i386/csv.h b/target/i386/csv.h +index ea87c1ba27..4096e8658b 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -15,6 +15,7 @@ + #define I386_CSV_H + + #include "qapi/qapi-commands-misc-target.h" ++#include "sev.h" + + #define GUEST_POLICY_CSV3_BIT (1 << 6) + #define GUEST_POLICY_REUSE_ASID (1 << 7) +@@ -77,10 +78,13 @@ struct Csv3GuestState { + uint32_t policy; + int sev_fd; + void *state; ++ int (*sev_ioctl)(int fd, int cmd, void *data, int *error); ++ const char *(*fw_error_to_str)(int code); + }; + + typedef struct Csv3GuestState Csv3GuestState; + + extern struct Csv3GuestState csv3_guest; ++extern int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); + + #endif +diff --git a/target/i386/sev.c b/target/i386/sev.c +index af61ca5ba8..1c453b3148 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1225,6 +1225,18 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + goto err; + } + ++ /* Support CSV3 */ ++ if (!ret && cmd == KVM_SEV_ES_INIT) { ++ ret = csv3_init(sev_guest->policy, sev->sev_fd, (void *)&sev->state, &sev_ops); ++ if (ret) { ++ error_setg(errp, "%s: failed to init csv3 context", __func__); ++ goto err; ++ } ++ /* The CSV3 guest is not resettable */ ++ if (csv3_enabled()) ++ csv_kvm_cpu_reset_inhibit = true; ++ } ++ + /* + * The LAUNCH context is used for new guest, if its an incoming guest + * then RECEIVE context will be created after the connection is established. +@@ -2635,6 +2647,11 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) + return ret; + } + ++struct sev_ops sev_ops = { ++ .sev_ioctl = sev_ioctl, ++ .fw_error_to_str = fw_error_to_str, ++}; ++ + static void + sev_register_types(void) + { +diff --git a/target/i386/sev.h b/target/i386/sev.h +index 0bfe3879ef..e91431e0f7 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -80,4 +80,11 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); + + extern bool sev_kvm_has_msr_ghcb; + ++struct sev_ops { ++ int (*sev_ioctl)(int fd, int cmd, void *data, int *error); ++ const char *(*fw_error_to_str)(int code); ++}; ++ ++extern struct sev_ops sev_ops; ++ + #endif +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch b/target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch new file mode 100644 index 0000000..3923d48 --- /dev/null +++ b/target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch @@ -0,0 +1,166 @@ +From 53cba8da8fb18cc9a463ec1f57990e8558cd4008 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 09:59:16 +0800 +Subject: [PATCH] target/i386: csv: Add command to load data to CSV3 guest + memory + +The KVM_CSV3_LAUNCH_ENCRYPT_DATA command is used to load data to an +encrypted guest memory in an isolated memory region that guest owns. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 7 ++++ + target/i386/csv-sysemu-stub.c | 5 +++ + target/i386/csv.c | 69 +++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 2 + + target/i386/trace-events | 3 ++ + 5 files changed, 86 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 90869068c8..dd6d9c2e07 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2113,6 +2113,13 @@ enum csv3_cmd_id { + KVM_CSV3_NR_MIN = 0xc0, + + KVM_CSV3_INIT = KVM_CSV3_NR_MIN, ++ KVM_CSV3_LAUNCH_ENCRYPT_DATA, ++}; ++ ++struct kvm_csv3_launch_encrypt_data { ++ __u64 gpa; ++ __u64 uaddr; ++ __u32 len; + }; + + struct kvm_csv3_init_data { +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index 72f0f5c772..b0ccbd2f18 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -19,3 +19,8 @@ int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + { + return 0; + } ++ ++int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) ++{ ++ g_assert_not_reached(); ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index fd3ea291ca..2a596681b8 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -13,6 +13,7 @@ + + #include "qemu/osdep.h" + #include "qemu/error-report.h" ++#include "qapi/error.h" + + #include + +@@ -20,6 +21,7 @@ + #include + #endif + ++#include "trace.h" + #include "cpu.h" + #include "sev.h" + #include "csv.h" +@@ -74,3 +76,70 @@ csv3_enabled(void) + + return sev_es_enabled() && (csv3_guest.policy & GUEST_POLICY_CSV3_BIT); + } ++ ++static bool ++csv3_check_state(SevState state) ++{ ++ return *((SevState *)csv3_guest.state) == state; ++} ++ ++static int ++csv3_ioctl(int cmd, void *data, int *error) ++{ ++ if (csv3_guest.sev_ioctl) ++ return csv3_guest.sev_ioctl(csv3_guest.sev_fd, cmd, data, error); ++ else ++ return -1; ++} ++ ++static const char * ++fw_error_to_str(int code) ++{ ++ if (csv3_guest.fw_error_to_str) ++ return csv3_guest.fw_error_to_str(code); ++ else ++ return NULL; ++} ++ ++static int ++csv3_launch_encrypt_data(uint64_t gpa, uint8_t *addr, uint64_t len) ++{ ++ int ret, fw_error; ++ struct kvm_csv3_launch_encrypt_data update; ++ ++ if (!addr || !len) { ++ return 1; ++ } ++ ++ update.gpa = (__u64)gpa; ++ update.uaddr = (__u64)(unsigned long)addr; ++ update.len = len; ++ trace_kvm_csv3_launch_encrypt_data(gpa, addr, len); ++ ret = csv3_ioctl(KVM_CSV3_LAUNCH_ENCRYPT_DATA, &update, &fw_error); ++ if (ret) { ++ error_report("%s: CSV3 LAUNCH_ENCRYPT_DATA ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ } ++ ++ return ret; ++} ++ ++int ++csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) ++{ ++ int ret = 0; ++ ++ if (!csv3_enabled()) { ++ error_setg(errp, "%s: CSV3 is not enabled", __func__); ++ return -1; ++ } ++ ++ /* if CSV3 is in update state then load the data to secure memory */ ++ if (csv3_check_state(SEV_STATE_LAUNCH_UPDATE)) { ++ ret = csv3_launch_encrypt_data(gpa, ptr, len); ++ if (ret) ++ error_setg(errp, "%s: CSV3 fail to encrypt data", __func__); ++ } ++ ++ return ret; ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 4096e8658b..27b66f7857 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -87,4 +87,6 @@ typedef struct Csv3GuestState Csv3GuestState; + extern struct Csv3GuestState csv3_guest; + extern int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); + ++int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); ++ + #endif +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 87b765c73c..34c205ffda 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -19,3 +19,6 @@ kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_le + kvm_sev_receive_finish(void) "" + kvm_sev_send_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *dst, int len) "cpu_id %d cpu_index %d trans %p len %d" + kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int len, void *hdr, int hdr_len) "cpu_id %d cpu_index %d trans %p len %d hdr %p hdr_len %d" ++ ++# csv.c ++kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIx64 +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch b/target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch new file mode 100644 index 0000000..b57c352 --- /dev/null +++ b/target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch @@ -0,0 +1,108 @@ +From 368bf2c044fcdd21f10545de103af7cd2a5986f9 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 12:25:05 +0800 +Subject: [PATCH] target/i386: csv: Add command to load vmcb to CSV3 guest + memory + +The KVM_CSV3_LAUNCH_ENCRYPT_VMCB command is used to load and encrypt +the initial VMCB data to secure memory in an isolated region that +guest owns. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 1 + + target/i386/csv-sysemu-stub.c | 5 +++++ + target/i386/csv.c | 21 +++++++++++++++++++++ + target/i386/csv.h | 1 + + target/i386/sev.c | 8 ++++++-- + 5 files changed, 34 insertions(+), 2 deletions(-) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index dd6d9c2e07..8487d0889b 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2114,6 +2114,7 @@ enum csv3_cmd_id { + + KVM_CSV3_INIT = KVM_CSV3_NR_MIN, + KVM_CSV3_LAUNCH_ENCRYPT_DATA, ++ KVM_CSV3_LAUNCH_ENCRYPT_VMCB, + }; + + struct kvm_csv3_launch_encrypt_data { +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index b0ccbd2f18..23d885f0f3 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -24,3 +24,8 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) + { + g_assert_not_reached(); + } ++ ++int csv3_launch_encrypt_vmcb(void) ++{ ++ g_assert_not_reached(); ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 2a596681b8..12282ba451 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -143,3 +143,24 @@ csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) + + return ret; + } ++ ++int ++csv3_launch_encrypt_vmcb(void) ++{ ++ int ret, fw_error; ++ ++ if (!csv3_enabled()) { ++ error_report("%s: CSV3 is not enabled", __func__); ++ return -1; ++ } ++ ++ ret = csv3_ioctl(KVM_CSV3_LAUNCH_ENCRYPT_VMCB, NULL, &fw_error); ++ if (ret) { ++ error_report("%s: CSV3 LAUNCH_ENCRYPT_VMCB ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++err: ++ return ret; ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 27b66f7857..3caf216743 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -86,6 +86,7 @@ typedef struct Csv3GuestState Csv3GuestState; + + extern struct Csv3GuestState csv3_guest; + extern int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); ++extern int csv3_launch_encrypt_vmcb(void); + + int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 1c453b3148..6ff8891678 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -880,8 +880,12 @@ sev_launch_get_measure(Notifier *notifier, void *unused) + } + + if (sev_es_enabled()) { +- /* measure all the VM save areas before getting launch_measure */ +- ret = sev_launch_update_vmsa(sev); ++ if (csv3_enabled()) { ++ ret = csv3_launch_encrypt_vmcb(); ++ } else { ++ /* measure all the VM save areas before getting launch_measure */ ++ ret = sev_launch_update_vmsa(sev); ++ } + if (ret) { + exit(1); + } +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Add-support-to-migrate-the-incoming--new.patch b/target-i386-csv-Add-support-to-migrate-the-incoming--new.patch new file mode 100644 index 0000000..7990698 --- /dev/null +++ b/target-i386-csv-Add-support-to-migrate-the-incoming--new.patch @@ -0,0 +1,110 @@ +From b31be8b06440deccdf00de2a7886d04fe87dc802 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 10:00:46 +0800 +Subject: [PATCH] target/i386: csv: Add support to migrate the incoming context + for CSV3 guest + +The csv3_load_incoming_context() provides the method to read incoming +guest's context from socket. It loads them into guest private memory. +This is the last step during migration and RECEIVE FINISH command is +performed by then to complete the whole migration. + +Signed-off-by: Jiang Xin +Signed-off-by: hanliyang +--- + target/i386/csv.c | 45 ++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 1 + + target/i386/trace-events | 1 + + 3 files changed, 47 insertions(+) + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index cc90b57e5b..571beeb61f 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -47,6 +47,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { + .queue_incoming_page = NULL, + .load_queued_incoming_pages = NULL, + .save_outgoing_cpu_state = csv3_save_outgoing_context, ++ .load_incoming_cpu_state = csv3_load_incoming_context, + }; + + #define CSV3_OUTGOING_PAGE_NUM \ +@@ -644,6 +645,42 @@ err: + return ret; + } + ++static int ++csv3_receive_encrypt_context(Csv3GuestState *s, QEMUFile *f) ++{ ++ int ret = 1, fw_error = 0; ++ gchar *hdr = NULL, *trans = NULL; ++ struct kvm_csv3_receive_encrypt_context update = {}; ++ ++ /* get packet header */ ++ update.hdr_len = qemu_get_be32(f); ++ ++ hdr = g_new(gchar, update.hdr_len); ++ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); ++ update.hdr_uaddr = (uintptr_t)hdr; ++ ++ /* get transport buffer */ ++ update.trans_len = qemu_get_be32(f); ++ ++ trans = g_new(gchar, update.trans_len); ++ update.trans_uaddr = (uintptr_t)trans; ++ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ ++ trace_kvm_csv3_receive_encrypt_context(trans, update.trans_len, hdr, update.hdr_len); ++ ++ ret = csv3_ioctl(KVM_CSV3_RECEIVE_ENCRYPT_CONTEXT, &update, &fw_error); ++ if (ret) { ++ error_report("Error RECEIVE_ENCRYPT_CONTEXT ret=%d fw_error=%d '%s'", ++ ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++err: ++ g_free(trans); ++ g_free(hdr); ++ return ret; ++} ++ + int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent) + { + Csv3GuestState *s = &csv3_guest; +@@ -651,3 +688,11 @@ int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent) + /* send csv3 context. */ + return csv3_send_encrypt_context(s, f, bytes_sent); + } ++ ++int csv3_load_incoming_context(QEMUFile *f) ++{ ++ Csv3GuestState *s = &csv3_guest; ++ ++ /* receive csv3 context. */ ++ return csv3_receive_encrypt_context(s, f); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 9f83a271fd..8621f0b6fd 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -123,6 +123,7 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + int csv3_shared_region_dma_map(uint64_t start, uint64_t end); + void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); + int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); ++int csv3_load_incoming_context(QEMUFile *f); + int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); + int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); + int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent); +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 043412c569..ad3cfb9612 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -25,3 +25,4 @@ kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" P + kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" + kvm_csv3_send_encrypt_context(void *dst, int len) "trans %p len %d" + kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" ++kvm_csv3_receive_encrypt_context(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Add-support-to-migrate-the-incoming-.patch b/target-i386-csv-Add-support-to-migrate-the-incoming-.patch new file mode 100644 index 0000000..53491fb --- /dev/null +++ b/target-i386-csv-Add-support-to-migrate-the-incoming-.patch @@ -0,0 +1,205 @@ +From 3434042340ca031b6d355cc79dd00e166bd2e2fd Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 09:45:45 +0800 +Subject: [PATCH] target/i386: csv: Add support to migrate the incoming page + for CSV3 guest + +The csv3_receive_encrypt_data() provides the method to read incoming +guest private pages from socket and load them into guest memory. +The routine is similar to CSV2's. Usually, it starts with a RECEIVE +START command to create the migration context. Then RECEIVE ENCRYPT +DATA command is performed to let the firmware load incoming pages +into guest memory. After migration is completed, a RECEIVE FINISH +command is performed to the firmware. + +Signed-off-by: Jiang Xin +Signed-off-by: hanliyang +--- + target/i386/csv.c | 87 ++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 2 + + target/i386/sev.c | 8 ++++ + target/i386/sev.h | 1 + + target/i386/trace-events | 1 + + 5 files changed, 99 insertions(+) + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 22e709a95c..ac080b3766 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -38,11 +38,14 @@ bool csv_kvm_cpu_reset_inhibit; + struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { + .save_setup = sev_save_setup, + .save_outgoing_page = NULL, ++ .load_incoming_page = csv3_load_incoming_page, + .is_gfn_in_unshared_region = NULL, + .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, + .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, + .queue_outgoing_page = csv3_queue_outgoing_page, + .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, ++ .queue_incoming_page = NULL, ++ .load_queued_incoming_pages = NULL, + }; + + #define CSV3_OUTGOING_PAGE_NUM \ +@@ -89,6 +92,7 @@ csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + QTAILQ_INIT(&csv3_guest.dma_map_regions_list); + qemu_mutex_init(&csv3_guest.dma_map_regions_list_mutex); + csv3_guest.sev_send_start = ops->sev_send_start; ++ csv3_guest.sev_receive_start = ops->sev_receive_start; + } + return 0; + } +@@ -483,3 +487,86 @@ csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) + + return csv3_send_encrypt_data(s, f, NULL, 0, bytes_sent); + } ++ ++static int ++csv3_receive_start(QEMUFile *f) ++{ ++ if (csv3_guest.sev_receive_start) ++ return csv3_guest.sev_receive_start(f); ++ else ++ return -1; ++} ++ ++static int csv3_receive_encrypt_data(QEMUFile *f, uint8_t *ptr) ++{ ++ int ret = 1, fw_error = 0; ++ uint32_t i, guest_addr_entry_num; ++ gchar *hdr = NULL, *trans = NULL; ++ struct guest_addr_entry *guest_addr_data; ++ struct kvm_csv3_receive_encrypt_data update = {}; ++ void *hva = NULL; ++ MemoryRegion *mr = NULL; ++ ++ /* get packet header */ ++ update.hdr_len = qemu_get_be32(f); ++ ++ hdr = g_new(gchar, update.hdr_len); ++ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); ++ update.hdr_uaddr = (uintptr_t)hdr; ++ ++ /* get guest addr data */ ++ update.guest_addr_len = qemu_get_be32(f); ++ ++ guest_addr_data = (struct guest_addr_entry *)g_new(gchar, update.guest_addr_len); ++ qemu_get_buffer(f, (uint8_t *)guest_addr_data, update.guest_addr_len); ++ update.guest_addr_data = (uintptr_t)guest_addr_data; ++ ++ /* get transport buffer */ ++ update.trans_len = qemu_get_be32(f); ++ ++ trans = g_new(gchar, update.trans_len); ++ update.trans_uaddr = (uintptr_t)trans; ++ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ ++ /* update share memory. */ ++ guest_addr_entry_num = update.guest_addr_len / sizeof(struct guest_addr_entry); ++ for (i = 0; i < guest_addr_entry_num; i++) { ++ if (guest_addr_data[i].share) { ++ hva = gpa2hva(&mr, ++ ((uint64_t)guest_addr_data[i].gfn << TARGET_PAGE_BITS), ++ TARGET_PAGE_SIZE, ++ NULL); ++ if (hva) ++ memcpy(hva, trans + i * TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); ++ } ++ } ++ ++ trace_kvm_csv3_receive_encrypt_data(trans, update.trans_len, hdr, update.hdr_len); ++ ++ ret = csv3_ioctl(KVM_CSV3_RECEIVE_ENCRYPT_DATA, &update, &fw_error); ++ if (ret) { ++ error_report("Error RECEIVE_ENCRYPT_DATA ret=%d fw_error=%d '%s'", ++ ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++err: ++ g_free(trans); ++ g_free(guest_addr_data); ++ g_free(hdr); ++ return ret; ++} ++ ++int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr) ++{ ++ /* ++ * If this is first buffer and SEV is not in recieiving state then ++ * use RECEIVE_START command to create a encryption context. ++ */ ++ if (!csv3_check_state(SEV_STATE_RECEIVE_UPDATE) && ++ csv3_receive_start(f)) { ++ return 1; ++ } ++ ++ return csv3_receive_encrypt_data(f, ptr); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 12c1b22659..afcd59180c 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -108,6 +108,7 @@ struct Csv3GuestState { + size_t guest_addr_len; + + int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); ++ int (*sev_receive_start)(QEMUFile *f); + }; + + typedef struct Csv3GuestState Csv3GuestState; +@@ -121,6 +122,7 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + + int csv3_shared_region_dma_map(uint64_t start, uint64_t end); + void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); ++int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); + int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); + int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 5a96b0b452..5124bf3dee 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -2665,10 +2665,18 @@ static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) + return sev_send_start(s, f, bytes_sent); + } + ++static int _sev_receive_start(QEMUFile *f) ++{ ++ SevGuestState *s = sev_guest; ++ ++ return sev_receive_start(s, f); ++} ++ + struct sev_ops sev_ops = { + .sev_ioctl = sev_ioctl, + .fw_error_to_str = fw_error_to_str, + .sev_send_start = _sev_send_start, ++ .sev_receive_start = _sev_receive_start, + }; + + static void +diff --git a/target/i386/sev.h b/target/i386/sev.h +index 8ccef22a95..647b426b16 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -84,6 +84,7 @@ struct sev_ops { + int (*sev_ioctl)(int fd, int cmd, void *data, int *error); + const char *(*fw_error_to_str)(int code); + int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); ++ int (*sev_receive_start)(QEMUFile *f); + }; + + extern struct sev_ops sev_ops; +diff --git a/target/i386/trace-events b/target/i386/trace-events +index a4a58b12a1..b3cb9aaf71 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -23,3 +23,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int + # csv.c + kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIx64 + kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" ++kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Add-support-to-migrate-the-outgoing--new.patch b/target-i386-csv-Add-support-to-migrate-the-outgoing--new.patch new file mode 100644 index 0000000..bef06ef --- /dev/null +++ b/target-i386-csv-Add-support-to-migrate-the-outgoing--new.patch @@ -0,0 +1,139 @@ +From 0ebf32463e858c5f9cbd98e3f2fe494d0fbea259 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 09:52:31 +0800 +Subject: [PATCH] target/i386: csv: Add support to migrate the outgoing context + for CSV3 guest + +CSV3 needs to migrate guest cpu's context pages. Prior to migration +of the context, it should query transfer buffer length and header +data length by SEND ENCRYPT CONTEXT command. New migration flag +RAM_SAVE_ENCRYPTED_CSV3_CONTEXT is defined for CSV3. + +Signed-off-by: Jiang Xin +Signed-off-by: hanliyang +--- + target/i386/csv.c | 81 ++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 1 + + target/i386/trace-events | 1 + + 3 files changed, 83 insertions(+) + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index ac080b3766..cc90b57e5b 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -46,6 +46,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { + .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, + .queue_incoming_page = NULL, + .load_queued_incoming_pages = NULL, ++ .save_outgoing_cpu_state = csv3_save_outgoing_context, + }; + + #define CSV3_OUTGOING_PAGE_NUM \ +@@ -570,3 +571,83 @@ int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr) + + return csv3_receive_encrypt_data(f, ptr); + } ++ ++static int ++csv3_send_get_context_len(int *fw_err, int *context_len, int *hdr_len) ++{ ++ int ret = 0; ++ struct kvm_csv3_send_encrypt_context update = { 0 }; ++ ++ ret = csv3_ioctl(KVM_CSV3_SEND_ENCRYPT_CONTEXT, &update, fw_err); ++ if (*fw_err != SEV_RET_INVALID_LEN) { ++ error_report("%s: failed to get context length ret=%d fw_error=%d '%s'", ++ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); ++ ret = -1; ++ goto err; ++ } ++ ++ if (update.trans_len <= INT_MAX && update.hdr_len <= INT_MAX) { ++ *context_len = update.trans_len; ++ *hdr_len = update.hdr_len; ++ } ++ ret = 0; ++err: ++ return ret; ++} ++ ++static int ++csv3_send_encrypt_context(Csv3GuestState *s, QEMUFile *f, uint64_t *bytes_sent) ++{ ++ int ret, fw_error = 0; ++ int context_len = 0; ++ int hdr_len = 0; ++ guchar *trans; ++ guchar *hdr; ++ struct kvm_csv3_send_encrypt_context update = { }; ++ ++ ret = csv3_send_get_context_len(&fw_error, &context_len, &hdr_len); ++ if (context_len < 1 || hdr_len < 1) { ++ error_report("%s: fail to get context length fw_error=%d '%s'", ++ __func__, fw_error, fw_error_to_str(fw_error)); ++ return 1; ++ } ++ ++ /* allocate transport buffer */ ++ trans = g_new(guchar, context_len); ++ hdr = g_new(guchar, hdr_len); ++ ++ update.hdr_uaddr = (uintptr_t)hdr; ++ update.hdr_len = hdr_len; ++ update.trans_uaddr = (uintptr_t)trans; ++ update.trans_len = context_len; ++ ++ trace_kvm_csv3_send_encrypt_context(trans, update.trans_len); ++ ++ ret = csv3_ioctl(KVM_CSV3_SEND_ENCRYPT_CONTEXT, &update, &fw_error); ++ if (ret) { ++ error_report("%s: SEND_ENCRYPT_CONTEXT ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++ qemu_put_be32(f, update.hdr_len); ++ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); ++ *bytes_sent += 4 + update.hdr_len; ++ ++ qemu_put_be32(f, update.trans_len); ++ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ *bytes_sent += 4 + update.trans_len; ++ ++err: ++ g_free(trans); ++ g_free(hdr); ++ return ret; ++} ++ ++int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ Csv3GuestState *s = &csv3_guest; ++ ++ /* send csv3 context. */ ++ return csv3_send_encrypt_context(s, f, bytes_sent); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index afcd59180c..9f83a271fd 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -125,5 +125,6 @@ void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); + int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); + int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); + int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); ++int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent); + + #endif +diff --git a/target/i386/trace-events b/target/i386/trace-events +index b3cb9aaf71..043412c569 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -23,4 +23,5 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int + # csv.c + kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIx64 + kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" ++kvm_csv3_send_encrypt_context(void *dst, int len) "trans %p len %d" + kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Add-support-to-migrate-the-outgoing-.patch b/target-i386-csv-Add-support-to-migrate-the-outgoing-.patch new file mode 100644 index 0000000..886f065 --- /dev/null +++ b/target-i386-csv-Add-support-to-migrate-the-outgoing-.patch @@ -0,0 +1,452 @@ +From 13bd2629b78f528b0b4684a643f59d30b7274aa8 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 09:37:56 +0800 +Subject: [PATCH] target/i386: csv: Add support to migrate the outgoing page + for CSV3 guest + +The csv3_send_encrypt_data() provides the method to encrypt the +guest's private pages during migration. The routine is similar to +CSV2's. Usually, it starts with a SEND_START command to create the +migration context. Then SEND_ENCRYPT_DATA command is performed to +encrypt guest pages. After migration is completed, a SEND_FINISH +command is performed to the firmware. + +Signed-off-by: Jiang Xin +Signed-off-by: hanliyang +--- + migration/ram.c | 87 +++++++++++++++++++ + target/i386/csv.c | 182 +++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 22 +++++ + target/i386/sev.c | 14 ++- + target/i386/sev.h | 1 + + target/i386/trace-events | 1 + + 6 files changed, 306 insertions(+), 1 deletion(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 1377b9eb37..1f9348fd06 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -2480,6 +2480,90 @@ ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss) + } + #endif + ++/** ++ * ram_save_csv3_pages - send the given csv3 VM pages to the stream ++ */ ++static int ram_save_csv3_pages(RAMState *rs, PageSearchStatus *pss) ++{ ++ bool page_dirty; ++ int ret; ++ int tmppages, pages = 0; ++ uint8_t *p; ++ uint32_t host_len = 0; ++ uint64_t bytes_xmit = 0; ++ RAMBlock *block = pss->block; ++ ram_addr_t offset = 0; ++ hwaddr paddr = RAM_ADDR_INVALID; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); ++ struct ConfidentialGuestMemoryEncryptionOps *ops = ++ cgs_class->memory_encryption_ops; ++ ++ if (!kvm_csv3_enabled()) ++ return 0; ++ ++ do { ++ page_dirty = migration_bitmap_clear_dirty(rs, block, pss->page); ++ ++ /* Check the pages is dirty and if it is send it */ ++ if (page_dirty) { ++ ret = kvm_physical_memory_addr_from_host(kvm_state, ++ block->host + (pss->page << TARGET_PAGE_BITS), &paddr); ++ /* Process ROM or MMIO */ ++ if (paddr == RAM_ADDR_INVALID || ++ memory_region_is_rom(block->mr)) { ++ tmppages = migration_ops->ram_save_target_page(rs, pss); ++ } else { ++ /* Caculate the offset and host virtual address of the page */ ++ offset = pss->page << TARGET_PAGE_BITS; ++ p = block->host + offset; ++ ++ if (ops->queue_outgoing_page(p, TARGET_PAGE_SIZE, offset)) ++ return -1; ++ ++ tmppages = 1; ++ host_len += TARGET_PAGE_SIZE; ++ ++ stat64_add(&mig_stats.normal_pages, 1); ++ } ++ } else { ++ tmppages = 0; ++ } ++ ++ if (tmppages >= 0) { ++ pages += tmppages; ++ } else { ++ return tmppages; ++ } ++ ++ pss_find_next_dirty(pss); ++ } while (offset_in_ramblock(block, ++ ((ram_addr_t)pss->page) << TARGET_PAGE_BITS) && ++ host_len < CSV3_OUTGOING_PAGE_WINDOW_SIZE); ++ ++ /* Check if there are any queued pages */ ++ if (host_len != 0) { ++ /* Always set offset as 0 for csv3. */ ++ ram_transferred_add(save_page_header(pss, pss->pss_channel, ++ block, 0 | RAM_SAVE_FLAG_ENCRYPTED_DATA)); ++ ++ qemu_put_be32(pss->pss_channel, RAM_SAVE_ENCRYPTED_PAGE); ++ ram_transferred_add(4); ++ /* Process the queued pages in batch */ ++ ret = ops->save_queued_outgoing_pages(pss->pss_channel, &bytes_xmit); ++ if (ret) { ++ return -1; ++ } ++ ram_transferred_add(bytes_xmit); ++ } ++ ++ /* The offset we leave with is the last one we looked at */ ++ pss->page--; ++ ++ return pages; ++} ++ + /** + * ram_save_host_page: save a whole host page + * +@@ -2515,6 +2599,9 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) + return 0; + } + ++ if (kvm_csv3_enabled()) ++ return ram_save_csv3_pages(rs, pss); ++ + #ifdef CONFIG_HYGON_CSV_MIG_ACCEL + /* + * If command_batch function is enabled and memory encryption is enabled +diff --git a/target/i386/csv.c b/target/i386/csv.c +index e4706efa27..22e709a95c 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -16,8 +16,13 @@ + #include "qapi/error.h" + #include "sysemu/kvm.h" + #include "exec/address-spaces.h" ++#include "migration/blocker.h" ++#include "migration/qemu-file.h" ++#include "migration/misc.h" ++#include "monitor/monitor.h" + + #include ++#include + + #ifdef CONFIG_NUMA + #include +@@ -30,6 +35,19 @@ + + bool csv_kvm_cpu_reset_inhibit; + ++struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { ++ .save_setup = sev_save_setup, ++ .save_outgoing_page = NULL, ++ .is_gfn_in_unshared_region = NULL, ++ .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, ++ .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, ++ .queue_outgoing_page = csv3_queue_outgoing_page, ++ .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, ++}; ++ ++#define CSV3_OUTGOING_PAGE_NUM \ ++ (CSV3_OUTGOING_PAGE_WINDOW_SIZE / TARGET_PAGE_SIZE) ++ + Csv3GuestState csv3_guest = { 0 }; + + int +@@ -70,6 +88,7 @@ csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + csv3_guest.fw_error_to_str = ops->fw_error_to_str; + QTAILQ_INIT(&csv3_guest.dma_map_regions_list); + qemu_mutex_init(&csv3_guest.dma_map_regions_list_mutex); ++ csv3_guest.sev_send_start = ops->sev_send_start; + } + return 0; + } +@@ -301,3 +320,166 @@ end: + qemu_mutex_unlock(&s->dma_map_regions_list_mutex); + return; + } ++ ++static inline hwaddr csv3_hva_to_gfn(uint8_t *ptr) ++{ ++ ram_addr_t offset = RAM_ADDR_INVALID; ++ ++ kvm_physical_memory_addr_from_host(kvm_state, ptr, &offset); ++ ++ return offset >> TARGET_PAGE_BITS; ++} ++ ++static int ++csv3_send_start(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ if (csv3_guest.sev_send_start) ++ return csv3_guest.sev_send_start(f, bytes_sent); ++ else ++ return -1; ++} ++ ++static int ++csv3_send_get_packet_len(int *fw_err) ++{ ++ int ret; ++ struct kvm_csv3_send_encrypt_data update = {0}; ++ ++ update.hdr_len = 0; ++ update.trans_len = 0; ++ ret = csv3_ioctl(KVM_CSV3_SEND_ENCRYPT_DATA, &update, fw_err); ++ if (*fw_err != SEV_RET_INVALID_LEN) { ++ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", ++ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); ++ ret = 0; ++ goto err; ++ } ++ ++ if (update.hdr_len <= INT_MAX) ++ ret = update.hdr_len; ++ else ++ ret = 0; ++ ++err: ++ return ret; ++} ++ ++static int ++csv3_send_encrypt_data(Csv3GuestState *s, QEMUFile *f, ++ uint8_t *ptr, uint32_t size, uint64_t *bytes_sent) ++{ ++ int ret, fw_error = 0; ++ guchar *trans; ++ uint32_t guest_addr_entry_num; ++ uint32_t i; ++ struct kvm_csv3_send_encrypt_data update = { }; ++ ++ /* ++ * If this is first call then query the packet header bytes and allocate ++ * the packet buffer. ++ */ ++ if (!s->send_packet_hdr) { ++ s->send_packet_hdr_len = csv3_send_get_packet_len(&fw_error); ++ if (s->send_packet_hdr_len < 1) { ++ error_report("%s: SEND_UPDATE fw_error=%d '%s'", ++ __func__, fw_error, fw_error_to_str(fw_error)); ++ return 1; ++ } ++ ++ s->send_packet_hdr = g_new(gchar, s->send_packet_hdr_len); ++ } ++ ++ if (!s->guest_addr_len || !s->guest_addr_data) { ++ error_report("%s: invalid host address or size", __func__); ++ return 1; ++ } else { ++ guest_addr_entry_num = s->guest_addr_len / sizeof(struct guest_addr_entry); ++ } ++ ++ /* allocate transport buffer */ ++ trans = g_new(guchar, guest_addr_entry_num * TARGET_PAGE_SIZE); ++ ++ update.hdr_uaddr = (uintptr_t)s->send_packet_hdr; ++ update.hdr_len = s->send_packet_hdr_len; ++ update.guest_addr_data = (uintptr_t)s->guest_addr_data; ++ update.guest_addr_len = s->guest_addr_len; ++ update.trans_uaddr = (uintptr_t)trans; ++ update.trans_len = guest_addr_entry_num * TARGET_PAGE_SIZE; ++ ++ trace_kvm_csv3_send_encrypt_data(trans, update.trans_len); ++ ++ ret = csv3_ioctl(KVM_CSV3_SEND_ENCRYPT_DATA, &update, &fw_error); ++ if (ret) { ++ error_report("%s: SEND_ENCRYPT_DATA ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++ for (i = 0; i < guest_addr_entry_num; i++) { ++ if (s->guest_addr_data[i].share) ++ memcpy(trans + i * TARGET_PAGE_SIZE, (guchar *)s->guest_hva_data[i].hva, ++ TARGET_PAGE_SIZE); ++ } ++ ++ qemu_put_be32(f, update.hdr_len); ++ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); ++ *bytes_sent += 4 + update.hdr_len; ++ ++ qemu_put_be32(f, update.guest_addr_len); ++ qemu_put_buffer(f, (uint8_t *)update.guest_addr_data, update.guest_addr_len); ++ *bytes_sent += 4 + update.guest_addr_len; ++ ++ qemu_put_be32(f, update.trans_len); ++ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ *bytes_sent += (4 + update.trans_len); ++ ++err: ++ s->guest_addr_len = 0; ++ g_free(trans); ++ return ret; ++} ++ ++int ++csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) ++{ ++ Csv3GuestState *s = &csv3_guest; ++ uint32_t i = 0; ++ ++ if (!s->guest_addr_data) { ++ s->guest_hva_data = g_new0(struct guest_hva_entry, CSV3_OUTGOING_PAGE_NUM); ++ s->guest_addr_data = g_new0(struct guest_addr_entry, CSV3_OUTGOING_PAGE_NUM); ++ s->guest_addr_len = 0; ++ } ++ ++ if (s->guest_addr_len >= sizeof(struct guest_addr_entry) * CSV3_OUTGOING_PAGE_NUM) { ++ error_report("Failed to queue outgoing page"); ++ return 1; ++ } ++ ++ i = s->guest_addr_len / sizeof(struct guest_addr_entry); ++ s->guest_hva_data[i].hva = (uintptr_t)ptr; ++ s->guest_addr_data[i].share = 0; ++ s->guest_addr_data[i].reserved = 0; ++ s->guest_addr_data[i].gfn = csv3_hva_to_gfn(ptr); ++ s->guest_addr_len += sizeof(struct guest_addr_entry); ++ ++ return 0; ++} ++ ++int ++csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ Csv3GuestState *s = &csv3_guest; ++ ++ /* ++ * If this is a first buffer then create outgoing encryption context ++ * and write our PDH, policy and session data. ++ */ ++ if (!csv3_check_state(SEV_STATE_SEND_UPDATE) && ++ csv3_send_start(f, bytes_sent)) { ++ error_report("Failed to create outgoing context"); ++ return 1; ++ } ++ ++ return csv3_send_encrypt_data(s, f, NULL, 0, bytes_sent); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 12733341b3..12c1b22659 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -81,6 +81,18 @@ struct dma_map_region { + QTAILQ_ENTRY(dma_map_region) list; + }; + ++#define CSV3_OUTGOING_PAGE_WINDOW_SIZE (512 * TARGET_PAGE_SIZE) ++ ++struct guest_addr_entry { ++ uint64_t share: 1; ++ uint64_t reserved: 11; ++ uint64_t gfn: 52; ++}; ++ ++struct guest_hva_entry { ++ uint64_t hva; ++}; ++ + struct Csv3GuestState { + uint32_t policy; + int sev_fd; +@@ -89,11 +101,19 @@ struct Csv3GuestState { + const char *(*fw_error_to_str)(int code); + QTAILQ_HEAD(, dma_map_region) dma_map_regions_list; + QemuMutex dma_map_regions_list_mutex; ++ gchar *send_packet_hdr; ++ size_t send_packet_hdr_len; ++ struct guest_hva_entry *guest_hva_data; ++ struct guest_addr_entry *guest_addr_data; ++ size_t guest_addr_len; ++ ++ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); + }; + + typedef struct Csv3GuestState Csv3GuestState; + + extern struct Csv3GuestState csv3_guest; ++extern struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops; + extern int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); + extern int csv3_launch_encrypt_vmcb(void); + +@@ -101,5 +121,7 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + + int csv3_shared_region_dma_map(uint64_t start, uint64_t end); + void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); ++int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); ++int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); + + #endif +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 0012a5efb0..5a96b0b452 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1270,7 +1270,11 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + qemu_add_vm_change_state_handler(sev_vm_state_change, sev); + migration_add_notifier(&sev_migration_state, sev_migration_state_notifier); + +- cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; ++ if (csv3_enabled()) { ++ cgs_class->memory_encryption_ops = &csv3_memory_encryption_ops; ++ } else { ++ cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; ++ } + QTAILQ_INIT(&sev->shared_regions_list); + + /* Determine whether support MSR_AMD64_SEV_ES_GHCB */ +@@ -2654,9 +2658,17 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) + return ret; + } + ++static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ SevGuestState *s = sev_guest; ++ ++ return sev_send_start(s, f, bytes_sent); ++} ++ + struct sev_ops sev_ops = { + .sev_ioctl = sev_ioctl, + .fw_error_to_str = fw_error_to_str, ++ .sev_send_start = _sev_send_start, + }; + + static void +diff --git a/target/i386/sev.h b/target/i386/sev.h +index e91431e0f7..8ccef22a95 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -83,6 +83,7 @@ extern bool sev_kvm_has_msr_ghcb; + struct sev_ops { + int (*sev_ioctl)(int fd, int cmd, void *data, int *error); + const char *(*fw_error_to_str)(int code); ++ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); + }; + + extern struct sev_ops sev_ops; +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 34c205ffda..a4a58b12a1 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -22,3 +22,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int + + # csv.c + kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIx64 ++kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Do-not-register-unregister-guest-sec.patch b/target-i386-csv-Do-not-register-unregister-guest-sec.patch new file mode 100644 index 0000000..419aa8b --- /dev/null +++ b/target-i386-csv-Do-not-register-unregister-guest-sec.patch @@ -0,0 +1,35 @@ +From a3e8267b93d1e77dc547fff6fb9af6f8d48a674f Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 12:36:00 +0800 +Subject: [PATCH] target/i386: csv: Do not register/unregister guest secure + memory for CSV3 guest + +CSV3's guest memory is allocated by firmware in secure processor +from dedicated memory reserved upon system boot up, consequently +it is not necessary to add notifier to pin/unpin memory. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + target/i386/sev.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 6ff8891678..0012a5efb0 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1262,7 +1262,10 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + } + } + +- ram_block_notifier_add(&sev_ram_notifier); ++ /* CSV3 guest do not need notifier to reg/unreg memory */ ++ if (!csv3_enabled()) { ++ ram_block_notifier_add(&sev_ram_notifier); ++ } + qemu_add_machine_init_done_notifier(&sev_machine_done_notify); + qemu_add_vm_change_state_handler(sev_vm_state_change, sev); + migration_add_notifier(&sev_migration_state, sev_migration_state_notifier); +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Load-initial-image-to-private-memory.patch b/target-i386-csv-Load-initial-image-to-private-memory.patch new file mode 100644 index 0000000..011ce59 --- /dev/null +++ b/target-i386-csv-Load-initial-image-to-private-memory.patch @@ -0,0 +1,52 @@ +From ed3c233cc00d4c30718fc64b3afc48a51b4eb438 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 14:29:40 +0800 +Subject: [PATCH] target/i386: csv: Load initial image to private memory for + CSV3 guest + +The initial image of CSV3 guest should be loaded into private memory +before boot the guest. + +Add APIs to implement the image load. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + hw/i386/pc_sysfw.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index c8d9e71b88..2bbcbb8d35 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -37,6 +37,7 @@ + #include "hw/block/flash.h" + #include "sysemu/kvm.h" + #include "sev.h" ++#include "csv.h" + + #define FLASH_SECTOR_SIZE 4096 + +@@ -263,7 +264,18 @@ void x86_firmware_configure(void *ptr, int size) + error_report("failed to locate and/or save reset vector"); + exit(1); + } ++ if (csv3_enabled()) { ++ ram_addr_t offset = 0; ++ MemoryRegion *mr; + +- sev_encrypt_flash(ptr, size, &error_fatal); ++ mr = memory_region_from_host(ptr, &offset); ++ if (!mr) { ++ error_report("failed to get memory region of flash"); ++ exit(1); ++ } ++ csv3_load_data(mr->addr + offset, ptr, size, &error_fatal); ++ } else { ++ sev_encrypt_flash(ptr, size, &error_fatal); ++ } + } + } +-- +2.41.0.windows.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 0000000..c0086b8 --- /dev/null +++ b/target-loongarch-Add-TCG-macro-in-structure-CPUArchS.patch @@ -0,0 +1,233 @@ +From 033e2a67885cf7347473e09454a6704074e05878 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Mon, 6 May 2024 09:19:12 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..768db91 --- /dev/null +++ b/target-loongarch-Add-compatible-support-about-VM-reb.patch @@ -0,0 +1,49 @@ +From 2c6cf54ea2f52774f2587e7e66eed9beba3a3dec Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 27 Aug 2024 11:58:07 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..c554c45 --- /dev/null +++ b/target-loongarch-Add-loongarch-vector-property-uncon.patch @@ -0,0 +1,45 @@ +From f572c385e0d368cbf12acf7d6f0b33b5f2efd7f0 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 21 May 2024 16:05:48 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..32c8c72 --- /dev/null +++ b/target-loongarch-Add-loongson-binary-translation-fea.patch @@ -0,0 +1,198 @@ +From 962f649aa5a06169f0ac23f61e273f0860942ebb Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 29 Sep 2024 15:04:04 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..1246719 --- /dev/null +++ b/target-loongarch-Add-steal-time-support-on-migration.patch @@ -0,0 +1,150 @@ +From 8febab6bcb01e3e10ca4ac0021bae2a812a4452b Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Mon, 30 Sep 2024 14:40:40 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..beaf04b --- /dev/null +++ b/target-loongarch-Avoid-bits-shift-exceeding-width-of.patch @@ -0,0 +1,41 @@ +From fa79379bd4c5b72e11f14f24439d5d501b8cc98b Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sat, 14 Sep 2024 14:46:45 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..a75225b --- /dev/null +++ b/target-loongarch-Fix-cpu_reset-set-wrong-CSR_CRMD.patch @@ -0,0 +1,41 @@ +From d909e6bfef50fc67708358e455a3b53d869249e6 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 5 Jul 2024 10:18:39 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..8dc01ce --- /dev/null +++ b/target-loongarch-Implement-lbt-registers-save-restor.patch @@ -0,0 +1,190 @@ +From a7b08284143f7ace3635036bf0366cbec4d52c99 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 29 Sep 2024 15:04:05 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..50b320b --- /dev/null +++ b/target-loongarch-Put-cpucfg-operation-before-CSR-reg.patch @@ -0,0 +1,79 @@ +From 717faefc8f56490ad94ef69b42c2d2491225ace8 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Sun, 28 Apr 2024 11:16:51 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..2085d14 --- /dev/null +++ b/target-loongarch-Remove-avail_64-in-trans_srai_w-and.patch @@ -0,0 +1,55 @@ +From 3b3fdfa6d5439298b883e2e223fa04a2209612f5 Mon Sep 17 00:00:00 2001 +From: Feiyang Chen +Date: Fri, 28 Jun 2024 13:33:57 +1000 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..9eb7cb5 --- /dev/null +++ b/target-loongarch-Set-CSR_PRCFG1-and-CSR_PRCFG2-value.patch @@ -0,0 +1,54 @@ +From f677a8f2311e823a87ec70dbdbc07712d54e5a85 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Fri, 5 Jul 2024 10:18:38 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..c7e1c25 --- /dev/null +++ b/target-loongarch-Support-QMP-dump-guest-memory.patch @@ -0,0 +1,236 @@ +From 2f19b259a16985ce515727c819c3a7eb4f41e6d0 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Thu, 22 Aug 2024 14:52:45 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..9329cb7 --- /dev/null +++ b/target-loongarch-Use-explicit-little-endian-LD-ST-AP.patch @@ -0,0 +1,63 @@ +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] 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> +--- + 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.41.0.windows.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 0000000..ba9304e --- /dev/null +++ b/target-loongarch-fix-Werror-maybe-uninitialized-fals.patch @@ -0,0 +1,72 @@ +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] 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 +--- + 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.41.0.windows.1 + diff --git a/target-loongarch-kvm-Add-software-breakpoint-support-new.patch b/target-loongarch-kvm-Add-software-breakpoint-support-new.patch new file mode 100644 index 0000000..fa8969f --- /dev/null +++ b/target-loongarch-kvm-Add-software-breakpoint-support-new.patch @@ -0,0 +1,38 @@ +From 9a6ef31fa2fcf1f1257fb849cc6cabe2b4c440e0 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Fri, 7 Jun 2024 11:50:16 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..d937b58 --- /dev/null +++ b/target-loongarch-kvm-Add-vCPU-reset-function.patch @@ -0,0 +1,67 @@ +From ad00cc7da8ab03d6d612a3bd7ec0c4b7af594894 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Thu, 22 Aug 2024 10:28:27 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.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 0000000..0f4180d --- /dev/null +++ b/target-loongarch-kvm-Fix-VM-recovery-from-disk-failu.patch @@ -0,0 +1,38 @@ +From 520e792f674a7ab192a9237519c4e0c8f50abc71 Mon Sep 17 00:00:00 2001 +From: Song Gao +Date: Wed, 8 May 2024 10:47:32 +0800 +Subject: [PATCH] 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> +--- + 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.41.0.windows.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 0000000..3520ae3 --- /dev/null +++ b/target-loongarch-kvm-Implement-LoongArch-PMU-extensi.patch @@ -0,0 +1,232 @@ +From b87b4782e8147fd481becd946ca909edaaa58b41 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Wed, 18 Sep 2024 16:23:15 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/target-m68k-Map-FPU-exceptions-to-FPSR-register.patch b/target-m68k-Map-FPU-exceptions-to-FPSR-register.patch new file mode 100644 index 0000000..de9b79c --- /dev/null +++ b/target-m68k-Map-FPU-exceptions-to-FPSR-register.patch @@ -0,0 +1,218 @@ +From a8a621a06d54b987502d277f33021547d00fd133 Mon Sep 17 00:00:00 2001 +From: Keith Packard +Date: Wed, 2 Aug 2023 20:52:31 -0700 +Subject: [PATCH] target/m68k: Map FPU exceptions to FPSR register + +Add helpers for reading/writing the 68881 FPSR register so that +changes in floating point exception state can be seen by the +application. + +Call these helpers in pre_load/post_load hooks to synchronize +exception state. + +Signed-off-by: Keith Packard +Reviewed-by: Richard Henderson +Message-Id: <20230803035231.429697-1-keithp@keithp.com> +Signed-off-by: Richard Henderson +(cherry picked from commit 5888357942da1fd5a50efb6e4a6af8b1a27a5af8) +Signed-off-by: zhujun2 +--- + target/m68k/cpu.c | 12 +++++-- + target/m68k/cpu.h | 3 +- + target/m68k/fpu_helper.c | 72 ++++++++++++++++++++++++++++++++++++++++ + target/m68k/helper.c | 4 +-- + target/m68k/helper.h | 2 ++ + target/m68k/translate.c | 4 +-- + 6 files changed, 90 insertions(+), 7 deletions(-) + +diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c +index 11c7e0a790..d95deaafcd 100644 +--- a/target/m68k/cpu.c ++++ b/target/m68k/cpu.c +@@ -396,12 +396,19 @@ static const VMStateDescription vmstate_freg = { + } + }; + +-static int fpu_post_load(void *opaque, int version) ++static int fpu_pre_save(void *opaque) + { + M68kCPU *s = opaque; + +- cpu_m68k_restore_fp_status(&s->env); ++ s->env.fpsr = cpu_m68k_get_fpsr(&s->env); ++ return 0; ++} ++ ++static int fpu_post_load(void *opaque, int version) ++{ ++ M68kCPU *s = opaque; + ++ cpu_m68k_set_fpsr(&s->env, s->env.fpsr); + return 0; + } + +@@ -410,6 +417,7 @@ const VMStateDescription vmmstate_fpu = { + .version_id = 1, + .minimum_version_id = 1, + .needed = fpu_needed, ++ .pre_save = fpu_pre_save, + .post_load = fpu_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(env.fpcr, M68kCPU), +diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h +index 6cfc696d2b..4d78da9d5f 100644 +--- a/target/m68k/cpu.h ++++ b/target/m68k/cpu.h +@@ -199,7 +199,8 @@ void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t); + void cpu_m68k_set_sr(CPUM68KState *env, uint32_t); + void cpu_m68k_restore_fp_status(CPUM68KState *env); + void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val); +- ++uint32_t cpu_m68k_get_fpsr(CPUM68KState *env); ++void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val); + + /* + * Instead of computing the condition codes after each m68k instruction, +diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c +index ab120b5f59..8314791f50 100644 +--- a/target/m68k/fpu_helper.c ++++ b/target/m68k/fpu_helper.c +@@ -164,6 +164,78 @@ void HELPER(set_fpcr)(CPUM68KState *env, uint32_t val) + cpu_m68k_set_fpcr(env, val); + } + ++/* Convert host exception flags to cpu_m68k form. */ ++static int cpu_m68k_exceptbits_from_host(int host_bits) ++{ ++ int target_bits = 0; ++ ++ if (host_bits & float_flag_invalid) { ++ target_bits |= 0x80; ++ } ++ if (host_bits & float_flag_overflow) { ++ target_bits |= 0x40; ++ } ++ if (host_bits & (float_flag_underflow | float_flag_output_denormal)) { ++ target_bits |= 0x20; ++ } ++ if (host_bits & float_flag_divbyzero) { ++ target_bits |= 0x10; ++ } ++ if (host_bits & float_flag_inexact) { ++ target_bits |= 0x08; ++ } ++ return target_bits; ++} ++ ++/* Convert cpu_m68k exception flags to target form. */ ++static int cpu_m68k_exceptbits_to_host(int target_bits) ++{ ++ int host_bits = 0; ++ ++ if (target_bits & 0x80) { ++ host_bits |= float_flag_invalid; ++ } ++ if (target_bits & 0x40) { ++ host_bits |= float_flag_overflow; ++ } ++ if (target_bits & 0x20) { ++ host_bits |= float_flag_underflow; ++ } ++ if (target_bits & 0x10) { ++ host_bits |= float_flag_divbyzero; ++ } ++ if (target_bits & 0x08) { ++ host_bits |= float_flag_inexact; ++ } ++ return host_bits; ++} ++ ++uint32_t cpu_m68k_get_fpsr(CPUM68KState *env) ++{ ++ int host_flags = get_float_exception_flags(&env->fp_status); ++ int target_flags = cpu_m68k_exceptbits_from_host(host_flags); ++ int except = (env->fpsr & ~(0xf8)) | target_flags; ++ return except; ++} ++ ++uint32_t HELPER(get_fpsr)(CPUM68KState *env) ++{ ++ return cpu_m68k_get_fpsr(env); ++} ++ ++void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val) ++{ ++ env->fpsr = val; ++ ++ int host_flags = cpu_m68k_exceptbits_to_host((int) env->fpsr); ++ set_float_exception_flags(host_flags, &env->fp_status); ++} ++ ++void HELPER(set_fpsr)(CPUM68KState *env, uint32_t val) ++{ ++ cpu_m68k_set_fpsr(env, val); ++} ++ + #define PREC_BEGIN(prec) \ + do { \ + FloatX80RoundPrec old = \ +diff --git a/target/m68k/helper.c b/target/m68k/helper.c +index 0a1544cd68..beab4b96bc 100644 +--- a/target/m68k/helper.c ++++ b/target/m68k/helper.c +@@ -118,7 +118,7 @@ static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n) + case 8: /* fpcontrol */ + return gdb_get_reg32(mem_buf, env->fpcr); + case 9: /* fpstatus */ +- return gdb_get_reg32(mem_buf, env->fpsr); ++ return gdb_get_reg32(mem_buf, cpu_m68k_get_fpsr(env)); + case 10: /* fpiar, not implemented */ + return gdb_get_reg32(mem_buf, 0); + } +@@ -137,7 +137,7 @@ static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) + cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); + return 4; + case 9: /* fpstatus */ +- env->fpsr = ldl_p(mem_buf); ++ cpu_m68k_set_fpsr(env, ldl_p(mem_buf)); + return 4; + case 10: /* fpiar, not implemented */ + return 4; +diff --git a/target/m68k/helper.h b/target/m68k/helper.h +index 2bbe0dc032..95aa5e53bb 100644 +--- a/target/m68k/helper.h ++++ b/target/m68k/helper.h +@@ -54,6 +54,8 @@ DEF_HELPER_4(fsdiv, void, env, fp, fp, fp) + DEF_HELPER_4(fddiv, void, env, fp, fp, fp) + DEF_HELPER_4(fsgldiv, void, env, fp, fp, fp) + DEF_HELPER_FLAGS_3(fcmp, TCG_CALL_NO_RWG, void, env, fp, fp) ++DEF_HELPER_2(set_fpsr, void, env, i32) ++DEF_HELPER_1(get_fpsr, i32, env) + DEF_HELPER_FLAGS_2(set_fpcr, TCG_CALL_NO_RWG, void, env, i32) + DEF_HELPER_FLAGS_2(ftst, TCG_CALL_NO_RWG, void, env, fp) + DEF_HELPER_3(fconst, void, env, fp, i32) +diff --git a/target/m68k/translate.c b/target/m68k/translate.c +index 4a0b0b2703..f8eeb70379 100644 +--- a/target/m68k/translate.c ++++ b/target/m68k/translate.c +@@ -4686,7 +4686,7 @@ static void gen_load_fcr(DisasContext *s, TCGv res, int reg) + tcg_gen_movi_i32(res, 0); + break; + case M68K_FPSR: +- tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpsr)); ++ gen_helper_get_fpsr(res, tcg_env); + break; + case M68K_FPCR: + tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpcr)); +@@ -4700,7 +4700,7 @@ static void gen_store_fcr(DisasContext *s, TCGv val, int reg) + case M68K_FPIAR: + break; + case M68K_FPSR: +- tcg_gen_st_i32(val, tcg_env, offsetof(CPUM68KState, fpsr)); ++ gen_helper_set_fpsr(tcg_env, val); + break; + case M68K_FPCR: + gen_helper_set_fpcr(tcg_env, val); +-- +2.41.0.windows.1 + diff --git a/target-riscv-Fix-the-element-agnostic-function-probl.patch b/target-riscv-Fix-the-element-agnostic-function-probl.patch new file mode 100644 index 0000000..6951aa9 --- /dev/null +++ b/target-riscv-Fix-the-element-agnostic-function-probl.patch @@ -0,0 +1,60 @@ +From 194c3cadc1879ff4c3d2fc6c5f962ad751c83d9c Mon Sep 17 00:00:00 2001 +From: Huang Tao +Date: Mon, 25 Mar 2024 10:16:54 +0800 +Subject: [PATCH] target/riscv: Fix the element agnostic function problem + +In RVV and vcrypto instructions, the masked and tail elements are set to 1s +using vext_set_elems_1s function if the vma/vta bit is set. It is the element +agnostic policy. + +However, this function can't deal the big endian situation. This patch fixes +the problem by adding handling of such case. + +Signed-off-by: Huang Tao +Suggested-by: Richard Henderson +Reviewed-by: LIU Zhiwei +Cc: qemu-stable +Message-ID: <20240325021654.6594-1-eric.huang@linux.alibaba.com> +Signed-off-by: Alistair Francis +(cherry picked from commit 75115d880c6d396f8a2d56aab8c12236d85a90e0) +Signed-off-by: zhujun2 +--- + target/riscv/vector_internals.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/target/riscv/vector_internals.c b/target/riscv/vector_internals.c +index 9cf5c17cde..be6eb040d2 100644 +--- a/target/riscv/vector_internals.c ++++ b/target/riscv/vector_internals.c +@@ -29,6 +29,28 @@ void vext_set_elems_1s(void *base, uint32_t is_agnostic, uint32_t cnt, + if (tot - cnt == 0) { + return ; + } ++ ++ if (HOST_BIG_ENDIAN) { ++ /* ++ * Deal the situation when the elements are insdie ++ * only one uint64 block including setting the ++ * masked-off element. ++ */ ++ if (((tot - 1) ^ cnt) < 8) { ++ memset(base + H1(tot - 1), -1, tot - cnt); ++ return; ++ } ++ /* ++ * Otherwise, at least cross two uint64_t blocks. ++ * Set first unaligned block. ++ */ ++ if (cnt % 8 != 0) { ++ uint32_t j = ROUND_UP(cnt, 8); ++ memset(base + H1(j - 1), -1, j - cnt); ++ cnt = j; ++ } ++ /* Set other 64bit aligend blocks */ ++ } + memset(base + cnt, -1, tot - cnt); + } + +-- +2.41.0.windows.1 + diff --git a/tcg-Allow-top-bit-of-SIMD_DATA_BITS-to-be-set-in-sim.patch b/tcg-Allow-top-bit-of-SIMD_DATA_BITS-to-be-set-in-sim.patch new file mode 100644 index 0000000..2853559 --- /dev/null +++ b/tcg-Allow-top-bit-of-SIMD_DATA_BITS-to-be-set-in-sim.patch @@ -0,0 +1,69 @@ +From d0b24cfdeb8bd64fa55154d79574352be33ecc51 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 15 Nov 2024 17:25:15 +0000 +Subject: [PATCH] tcg: Allow top bit of SIMD_DATA_BITS to be set in simd_desc() + +In simd_desc() we create a SIMD descriptor from various pieces +including an arbitrary data value from the caller. We try to +sanitize these to make sure everything will fit: the 'data' value +needs to fit in the SIMD_DATA_BITS (== 22) sized field. However we +do that sanitizing with: + tcg_debug_assert(data == sextract32(data, 0, SIMD_DATA_BITS)); + +This works for the case where the data is supposed to be considered +as a signed integer (which can then be returned via simd_data()). +However, some callers want to treat the data value as unsigned. + +Specifically, for the Arm SVE operations, make_svemte_desc() +assembles a data value as a collection of fields, and it needs to use +all 22 bits. Currently if MTE is enabled then its MTEDESC SIZEM1 +field may have the most significant bit set, and then it will trip +this assertion. + +Loosen the assertion so that we only check that the data value will +fit into the field in some way, either as a signed or as an unsigned +value. This means we will fail to detect some kinds of bug in the +callers, but we won't spuriously assert for intentional use of the +data field as unsigned. + +Cc: qemu-stable@nongnu.org +Fixes: db432672dc50e ("tcg: Add generic vector expanders") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2601 +Signed-off-by: Peter Maydell +Message-ID: <20241115172515.1229393-1-peter.maydell@linaro.org> +Reviewed-by: Richard Henderson +Signed-off-by: Richard Henderson +Signed-off-by: Zhongrui Tang +--- + tcg/tcg-op-gvec.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c +index bb88943f79..733b44f105 100644 +--- a/tcg/tcg-op-gvec.c ++++ b/tcg/tcg-op-gvec.c +@@ -88,7 +88,20 @@ uint32_t simd_desc(uint32_t oprsz, uint32_t maxsz, int32_t data) + uint32_t desc = 0; + + check_size_align(oprsz, maxsz, 0); +- tcg_debug_assert(data == sextract32(data, 0, SIMD_DATA_BITS)); ++ ++ /* ++ * We want to check that 'data' will fit into SIMD_DATA_BITS. ++ * However, some callers want to treat the data as a signed ++ * value (which they can later get back with simd_data()) ++ * and some want to treat it as an unsigned value. ++ * So here we assert only that the data will fit into the ++ * field in at least one way. This means that some invalid ++ * values from the caller will not be detected, e.g. if the ++ * caller wants to handle the value as a signed integer but ++ * incorrectly passes us 1 << (SIMD_DATA_BITS - 1). ++ */ ++ tcg_debug_assert(data == sextract32(data, 0, SIMD_DATA_BITS) || ++ data == extract32(data, 0, SIMD_DATA_BITS)); + + oprsz = (oprsz / 8) - 1; + maxsz = (maxsz / 8) - 1; +-- +2.41.0.windows.1 + diff --git a/tcg-loongarch64-Fix-tcg_out_movi-vs-some-pcrel-point.patch b/tcg-loongarch64-Fix-tcg_out_movi-vs-some-pcrel-point.patch new file mode 100644 index 0000000..67809a1 --- /dev/null +++ b/tcg-loongarch64-Fix-tcg_out_movi-vs-some-pcrel-point.patch @@ -0,0 +1,77 @@ +From 6477ff9d89317a6124f3a46215b1567306b6ebe4 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Wed, 19 Jun 2024 05:41:13 +0000 +Subject: [PATCH] tcg/loongarch64: Fix tcg_out_movi vs some pcrel pointers + +Simplify the logic for two-part, 32-bit pc-relative addresses. +Rather than assume all such fit in int32_t, do some arithmetic +and assert a result, do some arithmetic first and then check +to see if the pieces are in range. + +Cc: qemu-stable@nongnu.org +Fixes: dacc51720db ("tcg/loongarch64: Implement tcg_out_mov and tcg_out_movi") +Reviewed-by: Song Gao +Reported-by: Song Gao +Signed-off-by: Richard Henderson +(cherry picked from commit 521d7fb3ebdf88112ed13556a93e3037742b9eb8) +Signed-off-by: zhujun2 +--- + tcg/loongarch64/tcg-target.c.inc | 32 +++++++++++++++----------------- + 1 file changed, 15 insertions(+), 17 deletions(-) + +diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc +index bab0a173a3..ad2690b90d 100644 +--- a/tcg/loongarch64/tcg-target.c.inc ++++ b/tcg/loongarch64/tcg-target.c.inc +@@ -365,8 +365,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, + * back to the slow path. + */ + +- intptr_t pc_offset; +- tcg_target_long val_lo, val_hi, pc_hi, offset_hi; ++ intptr_t src_rx, pc_offset; + tcg_target_long hi12, hi32, hi52; + + /* Value fits in signed i32. */ +@@ -376,24 +375,23 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, + } + + /* PC-relative cases. */ +- pc_offset = tcg_pcrel_diff(s, (void *)val); +- if (pc_offset == sextreg(pc_offset, 0, 22) && (pc_offset & 3) == 0) { +- /* Single pcaddu2i. */ +- tcg_out_opc_pcaddu2i(s, rd, pc_offset >> 2); +- return; ++ src_rx = (intptr_t)tcg_splitwx_to_rx(s->code_ptr); ++ if ((val & 3) == 0) { ++ pc_offset = val - src_rx; ++ if (pc_offset == sextreg(pc_offset, 0, 22)) { ++ /* Single pcaddu2i. */ ++ tcg_out_opc_pcaddu2i(s, rd, pc_offset >> 2); ++ return; ++ } + } + +- if (pc_offset == (int32_t)pc_offset) { +- /* Offset within 32 bits; load with pcalau12i + ori. */ +- val_lo = sextreg(val, 0, 12); +- val_hi = val >> 12; +- pc_hi = (val - pc_offset) >> 12; +- offset_hi = val_hi - pc_hi; +- +- tcg_debug_assert(offset_hi == sextreg(offset_hi, 0, 20)); +- tcg_out_opc_pcalau12i(s, rd, offset_hi); ++ pc_offset = (val >> 12) - (src_rx >> 12); ++ if (pc_offset == sextreg(pc_offset, 0, 20)) { ++ /* Load with pcalau12i + ori. */ ++ tcg_target_long val_lo = val & 0xfff; ++ tcg_out_opc_pcalau12i(s, rd, pc_offset); + if (val_lo != 0) { +- tcg_out_opc_ori(s, rd, rd, val_lo & 0xfff); ++ tcg_out_opc_ori(s, rd, rd, val_lo); + } + return; + } +-- +2.41.0.windows.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 0000000..8fcbf17 --- /dev/null +++ b/tests-libqos-Add-loongarch-virt-machine-node.patch @@ -0,0 +1,182 @@ +From 254957f2de480901a063759d762d4b1eca5b5bb0 Mon Sep 17 00:00:00 2001 +From: Bibo Mao +Date: Tue, 28 May 2024 16:20:53 +0800 +Subject: [PATCH] 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 +--- + 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.41.0.windows.1 + diff --git a/ui-vnc-don-t-return-an-empty-SASL-mechlist-to-the-cl.patch b/ui-vnc-don-t-return-an-empty-SASL-mechlist-to-the-cl.patch new file mode 100644 index 0000000..10049b8 --- /dev/null +++ b/ui-vnc-don-t-return-an-empty-SASL-mechlist-to-the-cl.patch @@ -0,0 +1,47 @@ +From 838c585cf6c899a0b48683a0b46ed01cc24d835c Mon Sep 17 00:00:00 2001 +From: Susanooo +Date: Fri, 25 Oct 2024 10:08:39 +0800 +Subject: [PATCH] ui/vnc: don't return an empty SASL mechlist to the client +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The SASL initialization phase may determine that there are no valid +mechanisms available to use. This may be because the host OS admin +forgot to install some packages, or it might be because the requested +SSF level is incompatible with available mechanisms, or other unknown +reasons. + +If we return an empty mechlist to the client, they're going to get a +failure from the SASL library on their end and drop the connection. +Thus there is no point even sending this back to the client, we can +just drop the connection immediately. + +Reviewed-by: Marc-André Lureau +Signed-off-by: Daniel P. Berrangé +Signed-off-by: zhangchujun +--- + ui/vnc-auth-sasl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c +index 47fdae5b21..e321c9decc 100644 +--- a/ui/vnc-auth-sasl.c ++++ b/ui/vnc-auth-sasl.c +@@ -674,6 +674,13 @@ void start_auth_sasl(VncState *vs) + } + trace_vnc_auth_sasl_mech_list(vs, mechlist); + ++ if (g_str_equal(mechlist, "")) { ++ trace_vnc_auth_fail(vs, vs->auth, "no available SASL mechanisms", ""); ++ sasl_dispose(&vs->sasl.conn); ++ vs->sasl.conn = NULL; ++ goto authabort; ++ } ++ + vs->sasl.mechlist = g_strdup(mechlist); + mechlistlen = strlen(mechlist); + vnc_write_u32(vs, mechlistlen); +-- +2.41.0.windows.1 + diff --git a/vdpa-dev-Fix-initialisation-order-to-restore-VDUSE-c.patch b/vdpa-dev-Fix-initialisation-order-to-restore-VDUSE-c.patch new file mode 100644 index 0000000..109974b --- /dev/null +++ b/vdpa-dev-Fix-initialisation-order-to-restore-VDUSE-c.patch @@ -0,0 +1,180 @@ +From 9ab31c6abf095d8f7c986676cf6a70132a3441b7 Mon Sep 17 00:00:00 2001 +From: Adttil <2429917001@qq.com> +Date: Tue, 10 Dec 2024 00:33:28 +0800 +Subject: [PATCH] vdpa-dev: Fix initialisation order to restore VDUSE + compatibility +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +VDUSE requires that virtqueues are first enabled before the DRIVER_OK +status flag is set; with the current API of the kernel module, it is +impossible to enable the opposite order in our block export code because +userspace is not notified when a virtqueue is enabled. + +This requirement also mathces the normal initialisation order as done by +the generic vhost code in QEMU. However, commit 6c48254 accidentally +changed the order for vdpa-dev and broke access to VDUSE devices with +this. + +This changes vdpa-dev to use the normal order again and use the standard +vhost callback .vhost_set_vring_enable for this. VDUSE devices can be +used with vdpa-dev again after this fix. + +vhost_net intentionally avoided enabling the vrings for vdpa and does +this manually later while it does enable them for other vhost backends. +Reflect this in the vhost_net code and return early for vdpa, so that +the behaviour doesn't change for this device. + +Cc: qemu-stable@nongnu.org +Fixes: 6c48254 ('vdpa: move vhost_vdpa_set_vring_ready to the caller') +Signed-off-by: Kevin Wolf +Message-ID: <20240315155949.86066-1-kwolf@redhat.com> +Reviewed-by: Eugenio Pérez +Reviewed-by: Stefano Garzarella +Signed-off-by: Kevin Wolf +--- + hw/net/vhost_net.c | 10 ++++++++++ + hw/virtio/trace-events | 2 +- + hw/virtio/vdpa-dev.c | 5 +---- + hw/virtio/vhost-vdpa.c | 29 ++++++++++++++++++++++++++--- + hw/virtio/vhost.c | 8 +++++++- + 5 files changed, 45 insertions(+), 9 deletions(-) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index e48c373b14..a02d65d208 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -599,6 +599,16 @@ int vhost_set_vring_enable(NetClientState *nc, int enable) + VHostNetState *net = get_vhost_net(nc); + const VhostOps *vhost_ops = net->dev.vhost_ops; + ++ /* ++ * vhost-vdpa network devices need to enable dataplane virtqueues after ++ * DRIVER_OK, so they can recover device state before starting dataplane. ++ * Because of that, we don't enable virtqueues here and leave it to ++ * net/vhost-vdpa.c. ++ */ ++ if (nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { ++ return 0; ++ } ++ + nc->vring_enable = enable; + + if (vhost_ops && vhost_ops->vhost_set_vring_enable) { +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 637cac4edf..f136815072 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -48,7 +48,7 @@ vhost_vdpa_set_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI + vhost_vdpa_get_device_id(void *dev, uint32_t device_id) "dev: %p device_id %"PRIu32 + vhost_vdpa_reset_device(void *dev) "dev: %p" + vhost_vdpa_get_vq_index(void *dev, int idx, int vq_idx) "dev: %p idx: %d vq idx: %d" +-vhost_vdpa_set_vring_ready(void *dev, unsigned i, int r) "dev: %p, idx: %u, r: %d" ++vhost_vdpa_set_vring_enable_one(void *dev, unsigned i, int enable, int r) "dev: %p, idx: %u, enable: %u, r: %d" + vhost_vdpa_dump_config(void *dev, const char *line) "dev: %p %s" + vhost_vdpa_set_config(void *dev, uint32_t offset, uint32_t size, uint32_t flags) "dev: %p offset: %"PRIu32" size: %"PRIu32" flags: 0x%"PRIx32 + vhost_vdpa_get_config(void *dev, void *config, uint32_t config_len) "dev: %p config: %p config_len: %"PRIu32 +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +index 91e71847b0..7b2b19dfb8 100644 +--- a/hw/virtio/vdpa-dev.c ++++ b/hw/virtio/vdpa-dev.c +@@ -259,14 +259,11 @@ static int vhost_vdpa_device_start(VirtIODevice *vdev, Error **errp) + + s->dev.acked_features = vdev->guest_features; + +- ret = vhost_dev_start(&s->dev, vdev, false); ++ ret = vhost_dev_start(&s->dev, vdev, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error starting vhost"); + goto err_guest_notifiers; + } +- for (i = 0; i < s->dev.nvqs; ++i) { +- vhost_vdpa_set_vring_ready(&s->vdpa, i); +- } + s->started = true; + + /* +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index d49826845f..7e172eee49 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -883,12 +883,13 @@ static int vhost_vdpa_get_vq_index(struct vhost_dev *dev, int idx) + return idx; + } + +-int vhost_vdpa_set_vring_ready(struct vhost_vdpa *v, unsigned idx) ++static int vhost_vdpa_set_vring_enable_one(struct vhost_vdpa *v, unsigned idx, ++ int enable) + { + struct vhost_dev *dev = v->dev; + struct vhost_vring_state state = { + .index = idx, +- .num = 1, ++ .num = enable, + }; + hwaddr addr = virtio_queue_get_desc_addr(dev->vdev, idx); + if (addr == 0) { +@@ -897,10 +898,31 @@ int vhost_vdpa_set_vring_ready(struct vhost_vdpa *v, unsigned idx) + + int r = vhost_vdpa_call(dev, VHOST_VDPA_SET_VRING_ENABLE, &state); + +- trace_vhost_vdpa_set_vring_ready(dev, idx, r); ++ trace_vhost_vdpa_set_vring_enable_one(dev, idx, enable, r); + return r; + } + ++static int vhost_vdpa_set_vring_enable(struct vhost_dev *dev, int enable) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ unsigned int i; ++ int ret; ++ ++ for (i = 0; i < dev->nvqs; ++i) { ++ ret = vhost_vdpa_set_vring_enable_one(v, i, enable); ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++int vhost_vdpa_set_vring_ready(struct vhost_vdpa *v, unsigned idx) ++{ ++ return vhost_vdpa_set_vring_enable_one(v, idx, 1); ++} ++ + static int vhost_vdpa_set_config_call(struct vhost_dev *dev, + int fd) + { +@@ -1584,6 +1606,7 @@ const VhostOps vdpa_ops = { + .vhost_set_features = vhost_vdpa_set_features, + .vhost_reset_device = vhost_vdpa_reset_device, + .vhost_get_vq_index = vhost_vdpa_get_vq_index, ++ .vhost_set_vring_enable = vhost_vdpa_set_vring_enable, + .vhost_get_config = vhost_vdpa_get_config, + .vhost_set_config = vhost_vdpa_set_config, + .vhost_requires_shm_log = NULL, +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index d073a6d5a5..d29075aa04 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -2063,7 +2063,13 @@ static int vhost_dev_set_vring_enable(struct vhost_dev *hdev, int enable) + return hdev->vhost_ops->vhost_set_vring_enable(hdev, enable); + } + +-/* Host notifiers must be enabled at this point. */ ++/* ++ * Host notifiers must be enabled at this point. ++ * ++ * If @vrings is true, this function will enable all vrings before starting the ++ * device. If it is false, the vring initialization is left to be done by the ++ * caller. ++ */ + int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + { + int i, r; +-- +2.41.0.windows.1 + diff --git a/vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch b/vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch new file mode 100644 index 0000000..3c0d377 --- /dev/null +++ b/vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch @@ -0,0 +1,397 @@ +From 5631d7e167d87c4e2f9283cfac39f2f4107203cc Mon Sep 17 00:00:00 2001 +From: liuyafei +Date: Mon, 22 May 2023 20:37:40 +0800 +Subject: [PATCH] vfio: Only map shared region for CSV3 virtual machine + +qemu vfio listener map/unmap all of the virtual machine's memory. +It does not work for CSV3 virtual machine, as only shared memory +should be accessed by device. + +Signed-off-by: liuyafei +Signed-off-by: hanliyang +--- + hw/vfio/container.c | 46 +++++++++++- + include/exec/memory.h | 11 +++ + system/memory.c | 18 +++++ + target/i386/csv-sysemu-stub.c | 10 +++ + target/i386/csv.c | 134 ++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 12 +++ + target/i386/kvm/kvm.c | 2 + + 7 files changed, 230 insertions(+), 3 deletions(-) + +diff --git a/hw/vfio/container.c b/hw/vfio/container.c +index 422235a221..77e61cfedd 100644 +--- a/hw/vfio/container.c ++++ b/hw/vfio/container.c +@@ -30,6 +30,7 @@ + #include "qemu/error-report.h" + #include "qemu/range.h" + #include "sysemu/reset.h" ++#include "sysemu/kvm.h" + #include "trace.h" + #include "qapi/error.h" + #include "migration/migration.h" +@@ -534,6 +535,32 @@ static void vfio_free_container(VFIOContainer *container) + g_free(container); + } + ++static SharedRegionListener *g_shl; ++ ++static void shared_memory_listener_register(MemoryListener *listener, ++ AddressSpace *as) ++{ ++ SharedRegionListener *shl; ++ ++ shl = g_new0(SharedRegionListener, 1); ++ ++ shl->listener = listener; ++ shl->as = as; ++ ++ shared_region_register_listener(shl); ++ g_shl = shl; ++} ++ ++static void shared_memory_listener_unregister(void) ++{ ++ SharedRegionListener *shl = g_shl; ++ ++ shared_region_unregister_listener(shl); ++ ++ g_free(shl); ++ g_shl = NULL; ++} ++ + static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + Error **errp) + { +@@ -681,7 +708,12 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + + container->listener = vfio_memory_listener; + +- memory_listener_register(&container->listener, container->space->as); ++ if (kvm_csv3_enabled()) { ++ shared_memory_listener_register(&container->listener, ++ container->space->as); ++ } else { ++ memory_listener_register(&container->listener, container->space->as); ++ } + + if (container->error) { + ret = -1; +@@ -697,7 +729,11 @@ listener_release_exit: + QLIST_REMOVE(group, container_next); + QLIST_REMOVE(container, next); + vfio_kvm_device_del_group(group); +- memory_listener_unregister(&container->listener); ++ if (kvm_csv3_enabled()) { ++ shared_memory_listener_unregister(); ++ } else { ++ memory_listener_unregister(&container->listener); ++ } + if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU || + container->iommu_type == VFIO_SPAPR_TCE_IOMMU) { + vfio_spapr_container_deinit(container); +@@ -731,7 +767,11 @@ static void vfio_disconnect_container(VFIOGroup *group) + * group. + */ + if (QLIST_EMPTY(&container->group_list)) { +- memory_listener_unregister(&container->listener); ++ if (kvm_csv3_enabled()) { ++ shared_memory_listener_unregister(); ++ } else { ++ memory_listener_unregister(&container->listener); ++ } + if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU || + container->iommu_type == VFIO_SPAPR_TCE_IOMMU) { + vfio_spapr_container_deinit(container); +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 73d274d8f3..542c9da918 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -775,6 +775,17 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + ram_addr_t *ram_addr, bool *read_only, + bool *mr_has_discard_manager); + ++typedef struct SharedRegionListener SharedRegionListener; ++struct SharedRegionListener { ++ MemoryListener *listener; ++ AddressSpace *as; ++ QTAILQ_ENTRY(SharedRegionListener) next; ++}; ++ ++void shared_region_register_listener(SharedRegionListener *shl); ++void shared_region_unregister_listener(SharedRegionListener *shl); ++void *shared_region_listeners_get(void); ++ + typedef struct CoalescedMemoryRange CoalescedMemoryRange; + typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd; + +diff --git a/system/memory.c b/system/memory.c +index 1ae03074f3..9db07fd832 100644 +--- a/system/memory.c ++++ b/system/memory.c +@@ -48,6 +48,9 @@ static QTAILQ_HEAD(, MemoryListener) memory_listeners + static QTAILQ_HEAD(, AddressSpace) address_spaces + = QTAILQ_HEAD_INITIALIZER(address_spaces); + ++static QTAILQ_HEAD(, SharedRegionListener) shared_region_listeners ++ = QTAILQ_HEAD_INITIALIZER(shared_region_listeners); ++ + static GHashTable *flat_views; + + typedef struct AddrRange AddrRange; +@@ -2226,6 +2229,21 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + return true; + } + ++void shared_region_register_listener(SharedRegionListener *shl) ++{ ++ QTAILQ_INSERT_TAIL(&shared_region_listeners, shl, next); ++} ++ ++void shared_region_unregister_listener(SharedRegionListener *shl) ++{ ++ QTAILQ_REMOVE(&shared_region_listeners, shl, next); ++} ++ ++void *shared_region_listeners_get(void) ++{ ++ return &shared_region_listeners; ++} ++ + void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) + { + uint8_t mask = 1 << client; +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index 23d885f0f3..db22c299a6 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -29,3 +29,13 @@ int csv3_launch_encrypt_vmcb(void) + { + g_assert_not_reached(); + } ++ ++int csv3_shared_region_dma_map(uint64_t start, uint64_t end) ++{ ++ return 0; ++} ++ ++void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end) ++{ ++ ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 65d87de003..e4706efa27 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -15,6 +15,7 @@ + #include "qemu/error-report.h" + #include "qapi/error.h" + #include "sysemu/kvm.h" ++#include "exec/address-spaces.h" + + #include + +@@ -67,6 +68,8 @@ csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + csv3_guest.state = state; + csv3_guest.sev_ioctl = ops->sev_ioctl; + csv3_guest.fw_error_to_str = ops->fw_error_to_str; ++ QTAILQ_INIT(&csv3_guest.dma_map_regions_list); ++ qemu_mutex_init(&csv3_guest.dma_map_regions_list_mutex); + } + return 0; + } +@@ -167,3 +170,134 @@ csv3_launch_encrypt_vmcb(void) + err: + return ret; + } ++ ++int csv3_shared_region_dma_map(uint64_t start, uint64_t end) ++{ ++ MemoryRegionSection section; ++ AddressSpace *as; ++ QTAILQ_HEAD(, SharedRegionListener) *shared_region_listeners; ++ SharedRegionListener *shl; ++ MemoryListener *listener; ++ uint64_t size; ++ Csv3GuestState *s = &csv3_guest; ++ struct dma_map_region *region, *pos; ++ int ret = 0; ++ ++ if (!csv3_enabled()) ++ return 0; ++ ++ if (end <= start) ++ return 0; ++ ++ shared_region_listeners = shared_region_listeners_get(); ++ if (QTAILQ_EMPTY(shared_region_listeners)) ++ return 0; ++ ++ size = end - start; ++ ++ qemu_mutex_lock(&s->dma_map_regions_list_mutex); ++ QTAILQ_FOREACH(pos, &s->dma_map_regions_list, list) { ++ if (start >= (pos->start + pos->size)) { ++ continue; ++ } else if ((start + size) <= pos->start) { ++ break; ++ } else { ++ goto end; ++ } ++ } ++ QTAILQ_FOREACH(shl, shared_region_listeners, next) { ++ listener = shl->listener; ++ as = shl->as; ++ section = memory_region_find(as->root, start, size); ++ if (!section.mr) { ++ goto end; ++ } ++ ++ if (!memory_region_is_ram(section.mr)) { ++ memory_region_unref(section.mr); ++ goto end; ++ } ++ ++ if (listener->region_add) { ++ listener->region_add(listener, §ion); ++ } ++ memory_region_unref(section.mr); ++ } ++ ++ region = g_malloc0(sizeof(*region)); ++ if (!region) { ++ ret = -1; ++ goto end; ++ } ++ region->start = start; ++ region->size = size; ++ ++ if (pos) { ++ QTAILQ_INSERT_BEFORE(pos, region, list); ++ } else { ++ QTAILQ_INSERT_TAIL(&s->dma_map_regions_list, region, list); ++ } ++ ++end: ++ qemu_mutex_unlock(&s->dma_map_regions_list_mutex); ++ return ret; ++} ++ ++void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end) ++{ ++ MemoryRegionSection section; ++ AddressSpace *as; ++ QTAILQ_HEAD(, SharedRegionListener) *shared_region_listeners; ++ SharedRegionListener *shl; ++ MemoryListener *listener; ++ uint64_t size; ++ Csv3GuestState *s = &csv3_guest; ++ struct dma_map_region *pos, *next_pos; ++ ++ if (!csv3_enabled()) ++ return; ++ ++ if (end <= start) ++ return; ++ ++ shared_region_listeners = shared_region_listeners_get(); ++ if (QTAILQ_EMPTY(shared_region_listeners)) ++ return; ++ ++ size = end - start; ++ ++ qemu_mutex_lock(&s->dma_map_regions_list_mutex); ++ QTAILQ_FOREACH_SAFE(pos, &s->dma_map_regions_list, list, next_pos) { ++ uint64_t l, r; ++ uint64_t curr_end = pos->start + pos->size; ++ ++ l = MAX(start, pos->start); ++ r = MIN(start + size, pos->start + pos->size); ++ if (l < r) { ++ if ((start <= pos->start) && (start + size >= pos->start + pos->size)) { ++ QTAILQ_FOREACH(shl, shared_region_listeners, next) { ++ listener = shl->listener; ++ as = shl->as; ++ section = memory_region_find(as->root, pos->start, pos->size); ++ if (!section.mr) { ++ goto end; ++ } ++ if (listener->region_del) { ++ listener->region_del(listener, §ion); ++ } ++ memory_region_unref(section.mr); ++ } ++ ++ QTAILQ_REMOVE(&s->dma_map_regions_list, pos, list); ++ g_free(pos); ++ } ++ break; ++ } ++ if ((start + size) <= curr_end) { ++ break; ++ } ++ } ++end: ++ qemu_mutex_unlock(&s->dma_map_regions_list_mutex); ++ return; ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 3caf216743..12733341b3 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -15,6 +15,8 @@ + #define I386_CSV_H + + #include "qapi/qapi-commands-misc-target.h" ++#include "qemu/thread.h" ++#include "qemu/queue.h" + #include "sev.h" + + #define GUEST_POLICY_CSV3_BIT (1 << 6) +@@ -74,12 +76,19 @@ int csv_save_outgoing_cpu_state(QEMUFile *f, uint64_t *bytes_sent); + int csv_load_incoming_cpu_state(QEMUFile *f); + + /* CSV3 */ ++struct dma_map_region { ++ uint64_t start, size; ++ QTAILQ_ENTRY(dma_map_region) list; ++}; ++ + struct Csv3GuestState { + uint32_t policy; + int sev_fd; + void *state; + int (*sev_ioctl)(int fd, int cmd, void *data, int *error); + const char *(*fw_error_to_str)(int code); ++ QTAILQ_HEAD(, dma_map_region) dma_map_regions_list; ++ QemuMutex dma_map_regions_list_mutex; + }; + + typedef struct Csv3GuestState Csv3GuestState; +@@ -90,4 +99,7 @@ extern int csv3_launch_encrypt_vmcb(void); + + int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + ++int csv3_shared_region_dma_map(uint64_t start, uint64_t end); ++void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); ++ + #endif +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 2866a6d0ec..925f4f8040 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -5026,8 +5026,10 @@ static int kvm_handle_exit_hypercall(X86CPU *cpu, struct kvm_run *run) + + if (enc) { + sev_remove_shared_regions_list(gfn_start, gfn_end); ++ csv3_shared_region_dma_unmap(gpa, gfn_end << TARGET_PAGE_BITS); + } else { + sev_add_shared_regions_list(gfn_start, gfn_end); ++ csv3_shared_region_dma_map(gpa, gfn_end << TARGET_PAGE_BITS); + } + } + return 0; +-- +2.41.0.windows.1 + diff --git a/vga-Force-full-update-for-CSV3-guest.patch b/vga-Force-full-update-for-CSV3-guest.patch new file mode 100644 index 0000000..3c7e89e --- /dev/null +++ b/vga-Force-full-update-for-CSV3-guest.patch @@ -0,0 +1,129 @@ +From b791d13a0630e6640b3c39dc90671a2150734a24 Mon Sep 17 00:00:00 2001 +From: Xin Jiang +Date: Thu, 13 Jul 2023 09:35:10 +0800 +Subject: [PATCH] vga: Force full update for CSV3 guest + +As CSV3's NPT(nested page table) is managed by firmware, VMM is hard +to track the dirty pages of vga buffer. Although VMM could perform +a command to firmware to update read/write attribute of vga buffer +in NPT, it costs more time due to communication between VMM and +firmware. So the simplest method is to fully update vga buffer +always. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + accel/kvm/kvm-all.c | 1 + + accel/stubs/kvm-stub.c | 2 ++ + hw/display/vga.c | 7 +++++++ + include/sysemu/kvm.h | 8 ++++++++ + target/i386/csv.c | 3 +++ + 5 files changed, 21 insertions(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 8077630825..8028caddf9 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -103,6 +103,7 @@ bool kvm_allowed; + bool kvm_readonly_mem_allowed; + bool kvm_vm_attributes_allowed; + bool kvm_msi_use_devid; ++bool kvm_csv3_allowed; + bool kvm_has_guest_debug; + static int kvm_sstep_flags; + static bool kvm_immediate_exit; +diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c +index ad39a434c4..b071afee45 100644 +--- a/accel/stubs/kvm-stub.c ++++ b/accel/stubs/kvm-stub.c +@@ -27,6 +27,8 @@ bool kvm_msi_use_devid; + + bool virtcca_cvm_allowed; + ++bool kvm_csv3_allowed; ++ + void kvm_flush_coalesced_mmio_buffer(void) + { + } +diff --git a/hw/display/vga.c b/hw/display/vga.c +index cb6b6ee2ca..3f1358676b 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -39,6 +39,8 @@ + #include "migration/vmstate.h" + #include "trace.h" + ++#include "sysemu/kvm.h" ++ + //#define DEBUG_VGA_MEM + //#define DEBUG_VGA_REG + +@@ -1790,6 +1792,11 @@ static void vga_update_display(void *opaque) + s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); + full_update = 1; + } ++ ++ /* Force to full update in CSV guest. */ ++ if (kvm_csv3_enabled()) ++ full_update = 1; ++ + switch(graphic_mode) { + case GMODE_TEXT: + vga_draw_text(s, full_update); +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 31af5f0e24..fd8634cc8f 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -44,6 +44,7 @@ extern bool kvm_gsi_routing_allowed; + extern bool kvm_gsi_direct_mapping; + extern bool kvm_readonly_mem_allowed; + extern bool kvm_msi_use_devid; ++extern bool kvm_csv3_allowed; + + #define kvm_enabled() (kvm_allowed) + #define virtcca_cvm_enabled() (virtcca_cvm_allowed) +@@ -147,6 +148,12 @@ extern bool kvm_msi_use_devid; + */ + #define kvm_msi_devid_required() (kvm_msi_use_devid) + ++/** ++ * kvm_csv3_enabled: ++ * Returns: true if CSV3 feature is used for the VM. ++ */ ++#define kvm_csv3_enabled() (kvm_csv3_allowed) ++ + #else + + #define kvm_enabled() (0) +@@ -163,6 +170,7 @@ extern bool kvm_msi_use_devid; + #define kvm_gsi_direct_mapping() (false) + #define kvm_readonly_mem_enabled() (false) + #define kvm_msi_devid_required() (false) ++#define kvm_csv3_enabled() (false) + + #endif /* CONFIG_KVM_IS_POSSIBLE */ + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 12282ba451..65d87de003 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -14,6 +14,7 @@ + #include "qemu/osdep.h" + #include "qemu/error-report.h" + #include "qapi/error.h" ++#include "sysemu/kvm.h" + + #include + +@@ -60,6 +61,8 @@ csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + return -1; + } + ++ kvm_csv3_allowed = true; ++ + csv3_guest.sev_fd = fd; + csv3_guest.state = state; + csv3_guest.sev_ioctl = ops->sev_ioctl; +-- +2.41.0.windows.1 + -- Gitee