Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
3742d1b82c
!1051 sync qemu patch from code repository
From: @lixianglai 
Reviewed-by: @imxcc 
Signed-off-by: @imxcc
2024-12-18 06:58:55 +00:00
Xianglai Li
04ca9e6c8f QEMU update to version 8.2.0-27:
- fix compile error on loongarch
- hw/loongarch: fix cpu hotplug reset
- hw/loongarch/boot: Use warn_report when no kernel filename
- hw/loongarch: clean code
- hw/loongarch: Add KVM pch msi device support
- hw/loongarch: Add KVM pch pic device support
- hw/loongarch: Add KVM extioi device support
- hw/loongarch: Add KVM IPI device support
- hw/loongarch/virt: Update the ACPI table for hotplug cpu
- hw/loongarch/virt: Add basic CPU plug support
- hw/loongarch/virt: Add CPU topology support
- accel/kvm/kvm-all: Fixes the missing break in vCPU unpark logic
- gdbstub: Add helper function to unregister GDB register space
- physmem: Add helper function to destroy CPU AddressSpace
- hw/acpi: Update CPUs AML with cpu-(ctrl)dev change
- hw/acpi: Update ACPI GED framework to support vCPU Hotplug
- hw/acpi: Move CPU ctrl-dev MMIO region len macro to common header file
- accel/kvm: Extract common KVM vCPU {creation,parking} code
- target/loongarch: Add steal time support on migration
- linux-headers: loongarch: Add kvm_para.h and unistd_64.h
- target/loongarch/kvm: Implement LoongArch PMU extension
- target/loongarch: Implement lbt registers save/restore function
- target/loongarch: Add loongson binary translation feature
- sync loongarch linux-headers
- target/loongarch: Avoid bits shift exceeding width of bool type
- target/loongarch: Use explicit little-endian LD/ST API
- target/loongarch: fix -Werror=maybe-uninitialized false-positive
- target/loongarch: Support QMP dump-guest-memory
- target/loongarch/kvm: Add vCPU reset function
- target/loongarch: Add compatible support about VM reboot
- target/loongarch: Fix cpu_reset set wrong CSR_CRMD
- target/loongarch: Set CSR_PRCFG1 and CSR_PRCFG2 values
- target/loongarch: Remove avail_64 in trans_srai_w() and simplify it
- target/loongarch/kvm: Add software breakpoint support
- target/loongarch: Add loongarch vector property unconditionally
- target/loongarch/kvm: Fix VM recovery from disk failures
- target/loongarch: Put cpucfg operation before CSR register
- target/loongarch: Add TCG macro in structure CPUArchState
- hw/arm/virt-acpi-build.c: Migrate SPCR creation to common location
- hw/loongarch/virt: Add FDT table support with acpi ged pm register
- hw/loongarch/virt: Add description for virt machine type
- hw/loongarch: Add acpi SPCR table support
- hw/loongarch: virt: pass random seed to fdt
- hw/loongarch: virt: support up to 4 serial ports
- hw/loongarch: Remove default enable with VIRTIO_VGA device
- hw/loongarch: Fix length for lowram in ACPI SRAT
- hw/loongarch/virt: Remove unused assignment
- hw/loongarch: Change the tpm support by default
- hw/loongarch/boot.c: fix out-of-bound reading
- hw/loongarch/virt: Use MemTxAttrs interface for misc ops
- tests/libqos: Add loongarch virt machine node
- hw/loongarch: Remove minimum and default memory size
- hw/loongarch: Refine system dram memory region
- hw/loongarch: Refine fwcfg memory map
- hw/loongarch: Refine fadt memory table for numa memory
- hw/loongarch: Refine acpi srat table for numa memory
- hw/loongarch: Add VM mode in IOCSR feature register in kvm mode
- hw/loongarch: Refine default numa id calculation
- hw/loongarch: Rename LoongArchMachineState with LoongArchVirtMachineState
- hw/loongarch: Rename LOONGARCH_MACHINE with LOONGARCH_VIRT_MACHINE
- hw/loongarch: move memory map to boot.c
- loongarch: switch boards to "default y"
- hw/loongarch: Add cells missing from rtc node
- hw/loongarch: Add cells missing from uart node
- hw/loongarch: fdt remove unused irqchip node
- hw/loongarch: fdt adds pcie irq_map node
- hw/loongarch: fdt adds pch_msi Controller
- hw/loongarch: fdt adds pch_pic Controller
- hw/loongarch: fdt adds Extend I/O Interrupt Controller
- hw/loongarch: fdt adds cpu interrupt controller node
- hw/loongarch: Init efi_fdt table
- hw/loongarch: Init efi_initrd table
- hw/loongarch: Init efi_boot_memmap table
- hw/loongarch: Init efi_system_table
- hw/loongarch: Add init_cmdline
- hw/loongarch: Add slave cpu boot_code
- hw/loongarch: Add load initrd
- hw/loongarch: Move boot functions to boot.c

Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
2024-12-18 11:58:21 +08:00
openeuler-ci-bot
adb290ce5c
!1053 QEMU update to version 8.2.0-26:
From: @JiaboFeng 
Reviewed-by: @imxcc 
Signed-off-by: @imxcc
2024-12-12 09:38:53 +00:00
Jiabo Feng
f45f35e885 QEMU update to version 8.2.0-26:
- vdpa-dev: Fix initialisation order to restore VDUSE compatibility
- tcg: Allow top bit of SIMD_DATA_BITS to be set in simd_desc()
- 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<n>
- 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()
- 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 <fengjiabo1@huawei.com>
2024-12-12 17:01:35 +08:00
openeuler-ci-bot
a02d180542
!1041 QEMU update to version 8.2.0-25:
From: @JiaboFeng 
Reviewed-by: @imxcc 
Signed-off-by: @imxcc
2024-11-30 01:21:59 +00:00
openeuler-ci-bot
017a1d715c
!1040 QEMU update to version 8.2.0-24
From: @JiaboFeng 
Reviewed-by: @imxcc 
Signed-off-by: @imxcc
2024-11-30 00:57:59 +00:00
Jiabo Feng
702a9cc4e2 QEMU update to version 8.2.0-25:
- hw/arm/virt:Keep Guest L1 cache type consistent with KVM
- cvm : Add support for TEE-based national encryption acceleration.
- Add virtCCA Coda annotation Adjust the position of the security device
- target/i386: sev: Add support for reuse ASID for different CSV guests
- target/i386: sev: Fix incompatibility between SEV and CSV on the GET_ID API
- hw/cxl: Ensure there is enough data for the header in cmd_ccls_set_lsa()
- hw/pci: Add parenthesis to PCI_BUILD_BDF macro
- hw/audio/hda: free timer on exit
- meson.build: Remove ncurses workaround for OpenBSD
- ui/console-vc: Silence warning about sprintf() on OpenBSD
- ui: remove break after g_assert_not_reached()
- s390x/sclp: Simplify get_sclp_device()
- hw/vfio/hct: qemu startup terminate once error happened in hct
- hw/vfio/hct: fix ccp_index error caused by uninitialized buf
- hw/vfio/hct: update support ccp count to 48.
- hw/vfio: add device hct based on vfio.

Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
2024-11-30 08:43:54 +08:00
Jiabo Feng
b6e04df301 QEMU update to version 8.2.0-24:
- ppc/xive: Fix ESB length overflow on 32-bit hosts
- target/hppa: Fix PSW V-bit packaging in cpu_hppa_get for hppa64
- target/ppc: Fix migration of CPUs with TLB_EMB TLB type
- target/arm: Clear high SVE elements in handle_vec_simd_wshli
- module: Prevent crash by resetting local_err in module_load_qom_all()
- tests/docker: update debian i686 and mipsel images to bookworm
- target/arm: Fix SVE SDOT/UDOT/USDOT (4-way, indexed)
- docs/sphinx/depfile.py: Handle env.doc2path() returning a Path not a str
- block/blkio: use FUA flag on write zeroes only if supported
- virtio-pci: Fix the use of an uninitialized irqfd
- hw/cxl: Ensure there is enough data to read the input header in cmd_get_physical_port_state()
- intel_iommu: Send IQE event when setting reserved bit in IQT_TAIL
- virtio-net: Avoid indirection_table_mask overflow
- Fix calculation of minimum in colo_compare_tcp
- target/riscv/csr.c: Fix an access to VXSAT
- linux-user: Clean up unused header
- raw-format: Fix error message for invalid offset/size
- hw/loongarch/virt: Remove unnecessary 'cpu.h' inclusion
- tests: Wait for migration completion on destination QEMU to avoid failures
- acpi: ged: Add macro for acpi sleep control register
- hw/intc/openpic: Improve errors for out of bounds property values
- hw/pci-bridge: Add a Kconfig switch for the normal PCI bridge
- docs/tools/qemu-img.rst: fix typo (sumarizes)
- audio/pw: Report more accurate error when connecting to PipeWire fails
- audio/pw: Report more accurate error when connecting to PipeWire fails
- dma: Fix function names in documentation Ensure the function names match.
- edu: fix DMA range upper bound check
- platform-bus: fix refcount leak
- hw/net/can/sja1000: fix bug for single acceptance filter and standard frame
- tests/avocado: fix typo in replay_linux
- util/userfaultfd: Remove unused uffd_poll_events
- Consider discard option when writing zeros
- crypto: factor out conversion of QAPI to gcrypt constants
- crypto: drop gnutls debug logging support
- crypto: use consistent error reporting pattern for unsupported cipher modes
- hw/gpio/aspeed_gpio: Avoid shift into sign bit

Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
2024-11-30 08:36:49 +08:00
openeuler-ci-bot
88e7dc4565
!1038 [sync] PR-1033: support kernel vdpa
From: @openeuler-sync-bot 
Reviewed-by: @imxcc 
Signed-off-by: @imxcc
2024-11-29 09:21:15 +00:00
fangyi
9e1fee891e support kernel vDpa
Sync patches below from openEuler to src-openEuler:
vdpa: fix vdpa device migrate rollback wrong when suspend device failed.
vdpa: support resizing virtio-blk capacity online for kernel vdpa
Revert "vdpa: add vhost_vdpa_suspend"
Revert "vdpa: add vhost_vdpa->suspended parameter"
Revert "vdpa: block migration if SVQ does not admit a feature"
vdpa: remove memory listener unregister in vhost_vdpa_reset_status

(cherry picked from commit 27f3decf9bda36fa7613bd8d10e26c4bee54daf2)
2024-11-29 15:28:30 +08:00
181 changed files with 22854 additions and 1 deletions

View File

@ -0,0 +1,64 @@
From 93e7987cb5a7b33c2d2e0a02b7f310955ca11851 Mon Sep 17 00:00:00 2001
From: Christian Schoenebeck <qemu_oss@crudebyte.com>
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=<optimized out>) 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=<optimized out>,
max_count=<optimized out>) 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 <suda.kyoto@gmail.com>
Tested-by: Akihiro Suda <suda.kyoto@gmail.com>
Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Message-Id: <E1t8GnN-002RS8-E2@kylie.crudebyte.com>
Signed-off-by: Zhongrui Tang <tangzhongrui_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,39 @@
From 0cf5a4c56d34542bcc2f646446bf54828a51a014 Mon Sep 17 00:00:00 2001
From: yangxiangkai <yangxiangkai@huawei.com>
Date: Tue, 12 Nov 2024 09:03:51 +0800
Subject: [PATCH] Add virtCCA Coda annotation Adjust the position of the
security device Signed-off-by: yangxiangkai <yangxiangkai@huawei.com>
---
hw/arm/virt.c | 1 +
linux-headers/linux/vfio.h | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e73a795d3d..a744393f6e 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -162,6 +162,7 @@ static const MemMapEntry base_memmap[] = {
[VIRT_PVTIME] = { 0x090a0000, 0x00010000 },
[VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 },
[VIRT_CPUHP_ACPI] = { 0x090c0000, ACPI_CPU_HOTPLUG_REG_LEN},
+ /* In the virtCCA scenario, this space is used for MSI interrupt mapping */
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
[VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index c27a43d74b..5b1e2871af 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -225,7 +225,7 @@ struct vfio_device_info {
#define VFIO_DEVICE_FLAGS_FSL_MC (1 << 6) /* vfio-fsl-mc device */
#define VFIO_DEVICE_FLAGS_CAPS (1 << 7) /* Info supports caps */
#define VFIO_DEVICE_FLAGS_CDX (1 << 8) /* vfio-cdx device */
-#define VFIO_DEVICE_FLAGS_SECURE (1 << 9) /* secure pci device */
+#define VFIO_DEVICE_FLAGS_SECURE (1 << 15) /* secure pci device */
__u32 num_regions; /* Max region index + 1 */
__u32 num_irqs; /* Max IRQ index + 1 */
__u32 cap_offset; /* Offset within info struct of first cap */
--
2.41.0.windows.1

View File

@ -0,0 +1,287 @@
From 60b9463e35fe801e49db14539ccb8c9a6057e5c3 Mon Sep 17 00:00:00 2001
From: dinglimin <dinglimin@cmss.chinamobile.com>
Date: Sat, 12 Oct 2024 14:12:17 +0800
Subject: [PATCH] Consider discard option when writing zeros
When opening an image with discard=off, we punch hole in the image when
writing zeroes, making the image sparse. This breaks users that want to
ensure that writes cannot fail with ENOSPACE by using fully allocated
images[1].
bdrv_co_pwrite_zeroes() correctly disables BDRV_REQ_MAY_UNMAP if we
opened the child without discard=unmap or discard=on. But we don't go
through this function when accessing the top node. Move the check down
to bdrv_co_do_pwrite_zeroes() which seems to be used in all code paths.
This change implements the documented behavior, punching holes only when
opening the image with discard=on or discard=unmap. This may not be the
best default but can improve it later.
The test depends on a file system supporting discard, deallocating the
entire file when punching hole with the length of the entire file.
Tested with xfs, ext4, and tmpfs.
[1] https://lists.nongnu.org/archive/html/qemu-discuss/2024-06/msg00003.html
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Message-id: 20240628202058.1964986-3-nsoffer@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: dinglimin <dinglimin@cmss.chinamobile.com>
---
block/io.c | 9 +-
tests/qemu-iotests/tests/write-zeroes-unmap | 127 ++++++++++++++++++
.../qemu-iotests/tests/write-zeroes-unmap.out | 81 +++++++++++
3 files changed, 213 insertions(+), 4 deletions(-)
create mode 100644 tests/qemu-iotests/tests/write-zeroes-unmap
create mode 100644 tests/qemu-iotests/tests/write-zeroes-unmap.out
diff --git a/block/io.c b/block/io.c
index 7e62fabbf5..a280a5a4c9 100644
--- a/block/io.c
+++ b/block/io.c
@@ -1885,6 +1885,11 @@ bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
return -EINVAL;
}
+ /* If opened with discard=off we should never unmap. */
+ if (!(bs->open_flags & BDRV_O_UNMAP)) {
+ flags &= ~BDRV_REQ_MAY_UNMAP;
+ }
+
/* Invalidate the cached block-status data range if this write overlaps */
bdrv_bsc_invalidate_range(bs, offset, bytes);
@@ -2338,10 +2343,6 @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
trace_bdrv_co_pwrite_zeroes(child->bs, offset, bytes, flags);
assert_bdrv_graph_readable();
- if (!(child->bs->open_flags & BDRV_O_UNMAP)) {
- flags &= ~BDRV_REQ_MAY_UNMAP;
- }
-
return bdrv_co_pwritev(child, offset, bytes, NULL,
BDRV_REQ_ZERO_WRITE | flags);
}
diff --git a/tests/qemu-iotests/tests/write-zeroes-unmap b/tests/qemu-iotests/tests/write-zeroes-unmap
new file mode 100644
index 0000000000..7cfeeaf839
--- /dev/null
+++ b/tests/qemu-iotests/tests/write-zeroes-unmap
@@ -0,0 +1,127 @@
+#!/usr/bin/env bash
+# group: quick
+#
+# Test write zeros unmap.
+#
+# Copyright (C) Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+trap _cleanup_test_img exit
+
+# get standard environment, filters and checks
+cd ..
+. ./common.rc
+. ./common.filter
+
+_supported_fmt raw
+_supported_proto file
+_supported_os Linux
+
+create_test_image() {
+ _make_test_img -f $IMGFMT 1m
+}
+
+filter_command() {
+ _filter_testdir | _filter_qemu_io | _filter_qemu | _filter_hmp
+}
+
+print_disk_usage() {
+ du -sh $TEST_IMG | _filter_testdir
+}
+
+echo
+echo "=== defaults - write zeros ==="
+echo
+
+create_test_image
+echo -e 'qemu-io none0 "write -z 0 1m"\nquit' \
+ | $QEMU -monitor stdio -drive if=none,file=$TEST_IMG,format=$IMGFMT \
+ | filter_command
+print_disk_usage
+
+echo
+echo "=== defaults - write zeros unmap ==="
+echo
+
+create_test_image
+echo -e 'qemu-io none0 "write -zu 0 1m"\nquit' \
+ | $QEMU -monitor stdio -drive if=none,file=$TEST_IMG,format=$IMGFMT \
+ | filter_command
+print_disk_usage
+
+
+echo
+echo "=== defaults - write actual zeros ==="
+echo
+
+create_test_image
+echo -e 'qemu-io none0 "write -P 0 0 1m"\nquit' \
+ | $QEMU -monitor stdio -drive if=none,file=$TEST_IMG,format=$IMGFMT \
+ | filter_command
+print_disk_usage
+
+echo
+echo "=== discard=off - write zeroes unmap ==="
+echo
+
+create_test_image
+echo -e 'qemu-io none0 "write -zu 0 1m"\nquit' \
+ | $QEMU -monitor stdio -drive if=none,file=$TEST_IMG,format=$IMGFMT,discard=off \
+ | filter_command
+print_disk_usage
+
+echo
+echo "=== detect-zeroes=on - write actual zeros ==="
+echo
+
+create_test_image
+echo -e 'qemu-io none0 "write -P 0 0 1m"\nquit' \
+ | $QEMU -monitor stdio -drive if=none,file=$TEST_IMG,format=$IMGFMT,detect-zeroes=on \
+ | filter_command
+print_disk_usage
+
+echo
+echo "=== detect-zeroes=on,discard=on - write actual zeros ==="
+echo
+
+create_test_image
+echo -e 'qemu-io none0 "write -P 0 0 1m"\nquit' \
+ | $QEMU -monitor stdio -drive if=none,file=$TEST_IMG,format=$IMGFMT,detect-zeroes=on,discard=on \
+ | filter_command
+print_disk_usage
+
+echo
+echo "=== discard=on - write zeroes ==="
+echo
+
+create_test_image
+echo -e 'qemu-io none0 "write -z 0 1m"\nquit' \
+ | $QEMU -monitor stdio -drive if=none,file=$TEST_IMG,format=$IMGFMT,discard=on \
+ | filter_command
+print_disk_usage
+
+echo
+echo "=== discard=on - write zeroes unmap ==="
+echo
+
+create_test_image
+echo -e 'qemu-io none0 "write -zu 0 1m"\nquit' \
+ | $QEMU -monitor stdio -drive if=none,file=$TEST_IMG,format=$IMGFMT,discard=on \
+ | filter_command
+print_disk_usage
diff --git a/tests/qemu-iotests/tests/write-zeroes-unmap.out b/tests/qemu-iotests/tests/write-zeroes-unmap.out
new file mode 100644
index 0000000000..c931994897
--- /dev/null
+++ b/tests/qemu-iotests/tests/write-zeroes-unmap.out
@@ -0,0 +1,81 @@
+QA output created by write-zeroes-unmap
+
+=== defaults - write zeros ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io none0 "write -z 0 1m"
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) quit
+1.0M TEST_DIR/t.raw
+
+=== defaults - write zeros unmap ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io none0 "write -zu 0 1m"
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) quit
+1.0M TEST_DIR/t.raw
+
+=== defaults - write actual zeros ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io none0 "write -P 0 0 1m"
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) quit
+1.0M TEST_DIR/t.raw
+
+=== discard=off - write zeroes unmap ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io none0 "write -zu 0 1m"
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) quit
+1.0M TEST_DIR/t.raw
+
+=== detect-zeroes=on - write actual zeros ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io none0 "write -P 0 0 1m"
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) quit
+1.0M TEST_DIR/t.raw
+
+=== detect-zeroes=on,discard=on - write actual zeros ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io none0 "write -P 0 0 1m"
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) quit
+1.0M TEST_DIR/t.raw
+
+=== discard=on - write zeroes ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io none0 "write -z 0 1m"
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) quit
+1.0M TEST_DIR/t.raw
+
+=== discard=on - write zeroes unmap ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io none0 "write -zu 0 1m"
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) quit
+0 TEST_DIR/t.raw
--
2.41.0.windows.1

View File

@ -0,0 +1,35 @@
From f6ad72a5b215bc5b2d8df86cd537bf1c0f468108 Mon Sep 17 00:00:00 2001
From: zhangchujun <zhangchujun@cmss.chinamobile.com>
Date: Wed, 30 Oct 2024 13:33:58 +0800
Subject: [PATCH] Fix calculation of minimum in colo_compare_tcp
GitHub's CodeQL reports a critical error which is fixed by using the MIN macro:
Unsigned difference expression compared to zero
Signed-off-by: Stefan Weil <sw@weilnetz.de>
Cc: qemu-stable@nongnu.org
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: zhangchujun <zhangchujun_yewu@cmss.chinamobile.com>
---
net/colo-compare.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 7f9e6f89ce..d4e51cb306 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -413,8 +413,7 @@ static void colo_compare_tcp(CompareState *s, Connection *conn)
* can ensure that the packet's payload is acknowledged by
* primary and secondary.
*/
- uint32_t min_ack = conn->pack - conn->sack > 0 ?
- conn->sack : conn->pack;
+ uint32_t min_ack = MIN(conn->pack, conn->sack);
pri:
if (g_queue_is_empty(&conn->primary_list)) {
--
2.41.0.windows.1

View File

@ -0,0 +1,48 @@
From e1f733fcbc4eb39333ad9527865c1590d74092ed Mon Sep 17 00:00:00 2001
From: fangyi <eric.fangyi@huawei.com>
Date: Tue, 29 Oct 2024 19:53:27 +0800
Subject: [PATCH 4/6] Revert "vdpa: add vhost_vdpa->suspended parameter"
Use a new scheme instead for kernel vdpa, So revert it.
This reverts commit b6662cb7e5376659c7abb56efe27dcf3898d4fe6.
---
hw/virtio/vhost-vdpa.c | 8 --------
include/hw/virtio/vhost-vdpa.h | 2 --
2 files changed, 10 deletions(-)
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index 130afb06dc..bb3320946d 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -1406,14 +1406,6 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev,
return 0;
}
- if (!v->suspended) {
- /*
- * Cannot trust in value returned by device, let vhost recover used
- * idx from guest.
- */
- return -1;
- }
-
ret = vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring);
trace_vhost_vdpa_get_vring_base(dev, ring->index, ring->num);
return ret;
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
index 5407d54fd7..ee255bc1bd 100644
--- a/include/hw/virtio/vhost-vdpa.h
+++ b/include/hw/virtio/vhost-vdpa.h
@@ -42,8 +42,6 @@ typedef struct vhost_vdpa {
bool shadow_vqs_enabled;
/* Vdpa must send shadow addresses as IOTLB key for data queues, not GPA */
bool shadow_data;
- /* Device suspended successfully */
- bool suspended;
/* IOVA mapping used by the Shadow Virtqueue */
VhostIOVATree *iova_tree;
GPtrArray *shadow_vqs;
--
2.43.0

View File

@ -0,0 +1,84 @@
From 05ee3017d156005e3d8d8fb19514d593858abd44 Mon Sep 17 00:00:00 2001
From: fangyi <eric.fangyi@huawei.com>
Date: Tue, 29 Oct 2024 19:51:41 +0800
Subject: [PATCH 3/6] Revert "vdpa: add vhost_vdpa_suspend"
Use a new scheme instead for kernel vdpa, So revert it.
This reverts commit 0bb302a9960a186fc488068d268dc373e6b70876.
---
hw/virtio/trace-events | 1 -
hw/virtio/vhost-vdpa.c | 26 --------------------------
2 files changed, 27 deletions(-)
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 637cac4edf..de02bdc1d0 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -52,7 +52,6 @@ vhost_vdpa_set_vring_ready(void *dev, unsigned i, int r) "dev: %p, idx: %u, r: %
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
-vhost_vdpa_suspend(void *dev) "dev: %p"
vhost_vdpa_dev_start(void *dev, bool started) "dev: %p started: %d"
vhost_vdpa_set_log_base(void *dev, uint64_t base, unsigned long long size, int refcnt, int fd, void *log) "dev: %p base: 0x%"PRIx64" size: %llu refcnt: %d fd: %d log: %p"
vhost_vdpa_set_vring_addr(void *dev, unsigned int index, unsigned int flags, uint64_t desc_user_addr, uint64_t used_user_addr, uint64_t avail_user_addr, uint64_t log_guest_addr) "dev: %p index: %u flags: 0x%x desc_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" log_guest_addr: 0x%"PRIx64
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index d49826845f..130afb06dc 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -865,13 +865,11 @@ static int vhost_vdpa_get_device_id(struct vhost_dev *dev,
static int vhost_vdpa_reset_device(struct vhost_dev *dev)
{
- struct vhost_vdpa *v = dev->opaque;
int ret;
uint8_t status = 0;
ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status);
trace_vhost_vdpa_reset_device(dev);
- v->suspended = false;
return ret;
}
@@ -1274,29 +1272,6 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev)
}
}
-static void vhost_vdpa_suspend(struct vhost_dev *dev)
-{
- struct vhost_vdpa *v = dev->opaque;
- int r;
-
- if (!vhost_vdpa_first_dev(dev)) {
- return;
- }
-
- if (dev->backend_cap & BIT_ULL(VHOST_BACKEND_F_SUSPEND)) {
- trace_vhost_vdpa_suspend(dev);
- r = ioctl(v->device_fd, VHOST_VDPA_SUSPEND);
- if (unlikely(r)) {
- error_report("Cannot suspend: %s(%d)", g_strerror(errno), errno);
- } else {
- v->suspended = true;
- return;
- }
- }
-
- vhost_vdpa_reset_device(dev);
-}
-
static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
{
struct vhost_vdpa *v = dev->opaque;
@@ -1310,7 +1285,6 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
return -1;
}
} else {
- vhost_vdpa_suspend(dev);
vhost_vdpa_svqs_stop(dev);
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
}
--
2.43.0

View File

@ -0,0 +1,42 @@
From 4a79b3c07dca4f1e21e4dbb1e59bf437b2a814fa Mon Sep 17 00:00:00 2001
From: fangyi <eric.fangyi@huawei.com>
Date: Tue, 29 Oct 2024 19:58:14 +0800
Subject: [PATCH 5/6] Revert "vdpa: block migration if SVQ does not admit a
feature"
Use a new scheme instead for kernel vdpa, So revert it.
This reverts commit 57ac831865e370012496fb581a38d261cb72c5d0.
---
hw/virtio/vhost-vdpa.c | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index bb3320946d..69cf3b76e9 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -596,21 +596,6 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
return 0;
}
- /*
- * If dev->shadow_vqs_enabled at initialization that means the device has
- * been started with x-svq=on, so don't block migration
- */
- if (dev->migration_blocker == NULL && !v->shadow_vqs_enabled) {
- /* We don't have dev->features yet */
- uint64_t features;
- ret = vhost_vdpa_get_dev_features(dev, &features);
- if (unlikely(ret)) {
- error_setg_errno(errp, -ret, "Could not get device features");
- return ret;
- }
- vhost_svq_valid_features(features, &dev->migration_blocker);
- }
-
/*
* Similar to VFIO, we end up pinning all guest memory and have to
* disable discarding of RAM.
--
2.43.0

View File

@ -0,0 +1,236 @@
From 2464d0d6115e1794468ff455e3acdb98e0d71a31 Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Tue, 16 Jul 2024 12:14:56 +0100
Subject: [PATCH 62/78] accel/kvm: Extract common KVM vCPU {creation,parking}
code
KVM vCPU creation is done once during the vCPU realization when Qemu vCPU thread
is spawned. This is common to all the architectures as of now.
Hot-unplug of vCPU results in destruction of the vCPU object in QOM but the
corresponding KVM vCPU object in the Host KVM is not destroyed as KVM doesn't
support vCPU removal. Therefore, its representative KVM vCPU object/context in
Qemu is parked.
Refactor architecture common logic so that some APIs could be reused by vCPU
Hotplug code of some architectures likes ARM, Loongson etc. Update new/old APIs
with trace events. New APIs qemu_{create,park,unpark}_vcpu() can be externally
called. No functional change is intended here.
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Tested-by: Vishnu Pajjuri <vishnu@os.amperecomputing.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Tested-by: Xianglai Li <lixianglai@loongson.cn>
Tested-by: Miguel Luis <miguel.luis@oracle.com>
Reviewed-by: Shaoqin Huang <shahuang@redhat.com>
Reviewed-by: Vishnu Pajjuri <vishnu@os.amperecomputing.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Tested-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Harsh Prateek Bora <harshpb@linux.ibm.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20240716111502.202344-2-salil.mehta@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
accel/kvm/kvm-all.c | 71 +++++++++++++++++++++---------------------
accel/kvm/trace-events | 11 +++++++
include/sysemu/kvm.h | 27 ++++++++++++++--
3 files changed, 71 insertions(+), 38 deletions(-)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 8077630825..8dea8f98bb 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -141,7 +141,6 @@ static QemuMutex kml_slots_lock;
#define kvm_slots_unlock() qemu_mutex_unlock(&kml_slots_lock)
static void kvm_slot_init_dirty_bitmap(KVMSlot *mem);
-static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id);
static inline void kvm_resample_fd_remove(int gsi)
{
@@ -334,39 +333,57 @@ void kvm_park_vcpu(CPUState *cpu)
{
struct KVMParkedVcpu *vcpu;
+ trace_kvm_park_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
+
vcpu = g_malloc0(sizeof(*vcpu));
vcpu->vcpu_id = kvm_arch_vcpu_id(cpu);
vcpu->kvm_fd = cpu->kvm_fd;
QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node);
}
+int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id)
+{
+ struct KVMParkedVcpu *cpu;
+ int kvm_fd = -ENOENT;
+
+ QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
+ if (cpu->vcpu_id == vcpu_id) {
+ QLIST_REMOVE(cpu, node);
+ kvm_fd = cpu->kvm_fd;
+ g_free(cpu);
+ }
+ }
+
+ trace_kvm_unpark_vcpu(vcpu_id, kvm_fd > 0 ? "unparked" : "!found parked");
+
+ return kvm_fd;
+}
+
int kvm_create_vcpu(CPUState *cpu)
{
- unsigned long vcpu_id = cpu->cpu_index;
+ unsigned long vcpu_id = kvm_arch_vcpu_id(cpu);
KVMState *s = kvm_state;
- int ret;
-
- DPRINTF("kvm_create_vcpu\n");
+ int kvm_fd;
/* check if the KVM vCPU already exist but is parked */
- ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu));
- if (ret > 0) {
- goto found;
- }
-
- /* create a new KVM vcpu */
- ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
- if (ret < 0) {
- return ret;
+ kvm_fd = kvm_unpark_vcpu(s, vcpu_id);
+ if (kvm_fd < 0) {
+ /* vCPU not parked: create a new KVM vCPU */
+ kvm_fd = kvm_vm_ioctl(s, KVM_CREATE_VCPU, vcpu_id);
+ if (kvm_fd < 0) {
+ error_report("KVM_CREATE_VCPU IOCTL failed for vCPU %lu", vcpu_id);
+ return kvm_fd;
+ }
}
-found:
- cpu->vcpu_dirty = true;
- cpu->kvm_fd = ret;
+ cpu->kvm_fd = kvm_fd;
cpu->kvm_state = s;
+ cpu->vcpu_dirty = true;
cpu->dirty_pages = 0;
cpu->throttle_us_per_full = 0;
+ trace_kvm_create_vcpu(cpu->cpu_index, vcpu_id, kvm_fd);
+
return 0;
}
@@ -376,7 +393,7 @@ static int do_kvm_destroy_vcpu(CPUState *cpu)
long mmap_size;
int ret = 0;
- DPRINTF("kvm_destroy_vcpu\n");
+ trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
ret = kvm_arch_destroy_vcpu(cpu);
if (ret < 0) {
@@ -415,24 +432,6 @@ void kvm_destroy_vcpu(CPUState *cpu)
}
}
-static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
-{
- struct KVMParkedVcpu *cpu;
-
- QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
- if (cpu->vcpu_id == vcpu_id) {
- int kvm_fd;
-
- QLIST_REMOVE(cpu, node);
- kvm_fd = cpu->kvm_fd;
- g_free(cpu);
- return kvm_fd;
- }
- }
-
- return -1;
-}
-
int kvm_init_vcpu(CPUState *cpu, Error **errp)
{
KVMState *s = kvm_state;
diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events
index 399aaeb0ec..9c880fdcf4 100644
--- a/accel/kvm/trace-events
+++ b/accel/kvm/trace-events
@@ -9,6 +9,10 @@ kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p"
kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s"
kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s"
kvm_init_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
+kvm_create_vcpu(int cpu_index, unsigned long arch_cpu_id, int kvm_fd) "index: %d, id: %lu, kvm fd: %d"
+kvm_destroy_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
+kvm_park_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
+kvm_unpark_vcpu(unsigned long arch_cpu_id, const char *msg) "id: %lu %s"
kvm_irqchip_commit_routes(void) ""
kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d"
kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
@@ -26,3 +30,10 @@ kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"P
kvm_dirty_ring_reaper_kick(const char *reason) "%s"
kvm_dirty_ring_flush(int finished) "%d"
+kvm_failed_get_vcpu_mmap_size(void) ""
+kvm_cpu_exec(void) ""
+kvm_interrupt_exit_request(void) ""
+kvm_io_window_exit(void) ""
+kvm_run_exit_system_event(int cpu_index, uint32_t event_type) "cpu_index %d, system_even_type %"PRIu32
+kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s"
+kvm_memory_fault(uint64_t start, uint64_t size, uint64_t flags) "start 0x%" PRIx64 " size 0x%" PRIx64 " flags 0x%" PRIx64
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 31af5f0e24..7ffb5e4992 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -319,6 +319,31 @@ int kvm_create_device(KVMState *s, uint64_t type, bool test);
*/
bool kvm_device_supported(int vmfd, uint64_t type);
+/**
+ * kvm_create_vcpu - Gets a parked KVM vCPU or creates a KVM vCPU
+ * @cpu: QOM CPUState object for which KVM vCPU has to be fetched/created.
+ *
+ * @returns: 0 when success, errno (<0) when failed.
+ */
+int kvm_create_vcpu(CPUState *cpu);
+
+/**
+ * kvm_park_vcpu - Park QEMU KVM vCPU context
+ * @cpu: QOM CPUState object for which QEMU KVM vCPU context has to be parked.
+ *
+ * @returns: none
+ */
+void kvm_park_vcpu(CPUState *cpu);
+
+/**
+ * kvm_unpark_vcpu - unpark QEMU KVM vCPU context
+ * @s: KVM State
+ * @vcpu_id: Architecture vCPU ID of the parked vCPU
+ *
+ * @returns: KVM fd
+ */
+int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id);
+
/* Arch specific hooks */
extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
@@ -440,8 +465,6 @@ void kvm_set_sigmask_len(KVMState *s, unsigned int sigmask_len);
int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr,
hwaddr *phys_addr);
-int kvm_create_vcpu(CPUState *cpu);
-void kvm_park_vcpu(CPUState *cpu);
#endif /* NEED_CPU_H */
--
2.39.1

View File

@ -0,0 +1,46 @@
From 9bbc73e18d36d75c5dd842e478ed1f1b47ed4222 Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Thu, 1 Aug 2024 10:15:03 +0100
Subject: [PATCH 68/78] accel/kvm/kvm-all: Fixes the missing break in vCPU
unpark logic
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Loop should exit prematurely on successfully finding out the parked vCPU (struct
KVMParkedVcpu) in the 'struct KVMState' maintained 'kvm_parked_vcpus' list of
parked vCPUs.
Fixes: Coverity CID 1558552
Fixes: 08c3286822 ("accel/kvm: Extract common KVM vCPU {creation,parking} code")
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Message-id: 20240725145132.99355-1-salil.mehta@huawei.com
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Message-ID: <CAFEAcA-3_d1c7XSXWkFubD-LsW5c5i95e6xxV09r2C9yGtzcdA@mail.gmail.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
accel/kvm/kvm-all.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 8dea8f98bb..79d5671841 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -351,6 +351,7 @@ int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id)
QLIST_REMOVE(cpu, node);
kvm_fd = cpu->kvm_fd;
g_free(cpu);
+ break;
}
}
--
2.39.1

View File

@ -0,0 +1,52 @@
From 378d79fa6b9410af702776ffa93865219f273380 Mon Sep 17 00:00:00 2001
From: Anton Johansson <anjo@rev.ng>
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 <anjo@rev.ng>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20240612133031.15298-1-anjo@rev.ng>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
(cherry picked from commit 3b279f73fa37bec8d3ba04a15f5153d6491cffaf)
Signed-off-by: zhujun2 <zhujun2_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,59 @@
From 07fa80eacaa17d3cc3865050244b79d39cc61944 Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
Date: Wed, 23 Oct 2024 14:34:56 +0800
Subject: [PATCH] acpi: ged: Add macro for acpi sleep control register
cheery-pick from edafc90ba481c586d0a649f34dcb8cd1f29c4259
Macro definition is added for acpi sleep control register, ged emulation
driver can use the macro , also it can be used in FDT table if ged is
exposed with FDT table.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20240918014206.2165821-2-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
hw/acpi/generic_event_device.c | 6 +++---
include/hw/acpi/generic_event_device.h | 7 +++++--
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 4731a614a3..2ce7031f1a 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -203,9 +203,9 @@ static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data,
switch (addr) {
case ACPI_GED_REG_SLEEP_CTL:
- slp_typ = (data >> 2) & 0x07;
- slp_en = (data >> 5) & 0x01;
- if (slp_en && slp_typ == 5) {
+ slp_typ = (data >> ACPI_GED_SLP_TYP_POS) & ACPI_GED_SLP_TYP_MASK;
+ slp_en = !!(data & ACPI_GED_SLP_EN);
+ if (slp_en && slp_typ == ACPI_GED_SLP_TYP_S5) {
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
}
return;
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index 90fc41cbb8..8ed9534c57 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -81,8 +81,11 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED)
/* ACPI_GED_REG_RESET value for reset*/
#define ACPI_GED_RESET_VALUE 0x42
-/* ACPI_GED_REG_SLEEP_CTL.SLP_TYP value for S5 (aka poweroff) */
-#define ACPI_GED_SLP_TYP_S5 0x05
+/* [ACPI 5.0 Chapter 4.8.3.7] Sleep Control and Status Register */
+#define ACPI_GED_SLP_TYP_POS 0x2 /* SLP_TYPx Bit Offset */
+#define ACPI_GED_SLP_TYP_MASK 0x07 /* SLP_TYPx 3-bit mask */
+#define ACPI_GED_SLP_TYP_S5 0x05 /* System _S5 State (Soft Off) */
+#define ACPI_GED_SLP_EN 0x20 /* SLP_EN write-only bit */
#define GED_DEVICE "GED"
#define AML_GED_EVT_REG "EREG"
--
2.41.0.windows.1

View File

@ -0,0 +1,899 @@
From 6adb429abb287b3143ed447b334aa89c1a1c0d71 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BC=A0=E6=A5=9A=E5=90=9B?=
<zhangchujun@cmss.chinamobile.com>
Date: Fri, 18 Oct 2024 10:29:16 +0800
Subject: [PATCH] audio/pw: Report more accurate error when connecting to
PipeWire fails
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
According to its man page [1], pw_context_connect() sets errno on
failure:
Returns a Core on success or NULL with errno set on error.
It may be handy to see errno when figuring out why PipeWire
failed to connect. That leaves us with just one possible path to
reach 'fail_error' label which is then moved to that path and
also its error message is adjusted slightly.
1: https://docs.pipewire.org/group__pw__core.html#ga5994e3a54e4ec718094ca02a1234815b
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <3a78811ad5b0e87816b7616ab21d2eeef00b9c52.1726647033.git.mprivozn@redhat.com>
Signed-off-by: Zhang Chujun <zhangchujun_yewu@cmss.chinamobile.com>
---
audio/pwaudio.c.orig | 858 -------------------------------------------
1 file changed, 858 deletions(-)
delete mode 100644 audio/pwaudio.c.orig
diff --git a/audio/pwaudio.c.orig b/audio/pwaudio.c.orig
deleted file mode 100644
index 3ce5f6507b..0000000000
--- a/audio/pwaudio.c.orig
+++ /dev/null
@@ -1,858 +0,0 @@
-/*
- * QEMU PipeWire audio driver
- *
- * Copyright (c) 2023 Red Hat Inc.
- *
- * Author: Dorinda Bassey <dbassey@redhat.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "qemu/osdep.h"
-#include "qemu/module.h"
-#include "audio.h"
-#include <errno.h>
-#include "qemu/error-report.h"
-#include "qapi/error.h"
-#include <spa/param/audio/format-utils.h>
-#include <spa/utils/ringbuffer.h>
-#include <spa/utils/result.h>
-#include <spa/param/props.h>
-
-#include <pipewire/pipewire.h>
-#include "trace.h"
-
-#define AUDIO_CAP "pipewire"
-#define RINGBUFFER_SIZE (1u << 22)
-#define RINGBUFFER_MASK (RINGBUFFER_SIZE - 1)
-
-#include "audio_int.h"
-
-typedef struct pwvolume {
- uint32_t channels;
- float values[SPA_AUDIO_MAX_CHANNELS];
-} pwvolume;
-
-typedef struct pwaudio {
- Audiodev *dev;
- struct pw_thread_loop *thread_loop;
- struct pw_context *context;
-
- struct pw_core *core;
- struct spa_hook core_listener;
- int last_seq, pending_seq, error;
-} pwaudio;
-
-typedef struct PWVoice {
- pwaudio *g;
- struct pw_stream *stream;
- struct spa_hook stream_listener;
- struct spa_audio_info_raw info;
- uint32_t highwater_mark;
- uint32_t frame_size, req;
- struct spa_ringbuffer ring;
- uint8_t buffer[RINGBUFFER_SIZE];
-
- pwvolume volume;
- bool muted;
-} PWVoice;
-
-typedef struct PWVoiceOut {
- HWVoiceOut hw;
- PWVoice v;
-} PWVoiceOut;
-
-typedef struct PWVoiceIn {
- HWVoiceIn hw;
- PWVoice v;
-} PWVoiceIn;
-
-#define PW_VOICE_IN(v) ((PWVoiceIn *)v)
-#define PW_VOICE_OUT(v) ((PWVoiceOut *)v)
-
-static void
-stream_destroy(void *data)
-{
- PWVoice *v = (PWVoice *) data;
- spa_hook_remove(&v->stream_listener);
- v->stream = NULL;
-}
-
-/* output data processing function to read stuffs from the buffer */
-static void
-playback_on_process(void *data)
-{
- PWVoice *v = data;
- void *p;
- struct pw_buffer *b;
- struct spa_buffer *buf;
- uint32_t req, index, n_bytes;
- int32_t avail;
-
- assert(v->stream);
-
- /* obtain a buffer to read from */
- b = pw_stream_dequeue_buffer(v->stream);
- if (b == NULL) {
- error_report("out of buffers: %s", strerror(errno));
- return;
- }
-
- buf = b->buffer;
- p = buf->datas[0].data;
- if (p == NULL) {
- return;
- }
- /* calculate the total no of bytes to read data from buffer */
- req = b->requested * v->frame_size;
- if (req == 0) {
- req = v->req;
- }
- n_bytes = SPA_MIN(req, buf->datas[0].maxsize);
-
- /* get no of available bytes to read data from buffer */
- avail = spa_ringbuffer_get_read_index(&v->ring, &index);
-
- if (avail <= 0) {
- PWVoiceOut *vo = container_of(data, PWVoiceOut, v);
- audio_pcm_info_clear_buf(&vo->hw.info, p, n_bytes / v->frame_size);
- } else {
- if ((uint32_t) avail < n_bytes) {
- /*
- * PipeWire immediately calls this callback again if we provide
- * less than n_bytes. Then audio_pcm_info_clear_buf() fills the
- * rest of the buffer with silence.
- */
- n_bytes = avail;
- }
-
- spa_ringbuffer_read_data(&v->ring,
- v->buffer, RINGBUFFER_SIZE,
- index & RINGBUFFER_MASK, p, n_bytes);
-
- index += n_bytes;
- spa_ringbuffer_read_update(&v->ring, index);
-
- }
- buf->datas[0].chunk->offset = 0;
- buf->datas[0].chunk->stride = v->frame_size;
- buf->datas[0].chunk->size = n_bytes;
-
- /* queue the buffer for playback */
- pw_stream_queue_buffer(v->stream, b);
-}
-
-/* output data processing function to generate stuffs in the buffer */
-static void
-capture_on_process(void *data)
-{
- PWVoice *v = (PWVoice *) data;
- void *p;
- struct pw_buffer *b;
- struct spa_buffer *buf;
- int32_t filled;
- uint32_t index, offs, n_bytes;
-
- assert(v->stream);
-
- /* obtain a buffer */
- b = pw_stream_dequeue_buffer(v->stream);
- if (b == NULL) {
- error_report("out of buffers: %s", strerror(errno));
- return;
- }
-
- /* Write data into buffer */
- buf = b->buffer;
- p = buf->datas[0].data;
- if (p == NULL) {
- return;
- }
- offs = SPA_MIN(buf->datas[0].chunk->offset, buf->datas[0].maxsize);
- n_bytes = SPA_MIN(buf->datas[0].chunk->size, buf->datas[0].maxsize - offs);
-
- filled = spa_ringbuffer_get_write_index(&v->ring, &index);
-
-
- if (filled < 0) {
- error_report("%p: underrun write:%u filled:%d", p, index, filled);
- } else {
- if ((uint32_t) filled + n_bytes > RINGBUFFER_SIZE) {
- error_report("%p: overrun write:%u filled:%d + size:%u > max:%u",
- p, index, filled, n_bytes, RINGBUFFER_SIZE);
- }
- }
- spa_ringbuffer_write_data(&v->ring,
- v->buffer, RINGBUFFER_SIZE,
- index & RINGBUFFER_MASK,
- SPA_PTROFF(p, offs, void), n_bytes);
- index += n_bytes;
- spa_ringbuffer_write_update(&v->ring, index);
-
- /* queue the buffer for playback */
- pw_stream_queue_buffer(v->stream, b);
-}
-
-static void
-on_stream_state_changed(void *data, enum pw_stream_state old,
- enum pw_stream_state state, const char *error)
-{
- PWVoice *v = (PWVoice *) data;
-
- trace_pw_state_changed(pw_stream_get_node_id(v->stream),
- pw_stream_state_as_string(state));
-}
-
-static const struct pw_stream_events capture_stream_events = {
- PW_VERSION_STREAM_EVENTS,
- .destroy = stream_destroy,
- .state_changed = on_stream_state_changed,
- .process = capture_on_process
-};
-
-static const struct pw_stream_events playback_stream_events = {
- PW_VERSION_STREAM_EVENTS,
- .destroy = stream_destroy,
- .state_changed = on_stream_state_changed,
- .process = playback_on_process
-};
-
-static size_t
-qpw_read(HWVoiceIn *hw, void *data, size_t len)
-{
- PWVoiceIn *pw = (PWVoiceIn *) hw;
- PWVoice *v = &pw->v;
- pwaudio *c = v->g;
- const char *error = NULL;
- size_t l;
- int32_t avail;
- uint32_t index;
-
- pw_thread_loop_lock(c->thread_loop);
- if (pw_stream_get_state(v->stream, &error) != PW_STREAM_STATE_STREAMING) {
- /* wait for stream to become ready */
- l = 0;
- goto done_unlock;
- }
- /* get no of available bytes to read data from buffer */
- avail = spa_ringbuffer_get_read_index(&v->ring, &index);
-
- trace_pw_read(avail, index, len);
-
- if (avail < (int32_t) len) {
- len = avail;
- }
-
- spa_ringbuffer_read_data(&v->ring,
- v->buffer, RINGBUFFER_SIZE,
- index & RINGBUFFER_MASK, data, len);
- index += len;
- spa_ringbuffer_read_update(&v->ring, index);
- l = len;
-
-done_unlock:
- pw_thread_loop_unlock(c->thread_loop);
- return l;
-}
-
-static size_t qpw_buffer_get_free(HWVoiceOut *hw)
-{
- PWVoiceOut *pw = (PWVoiceOut *)hw;
- PWVoice *v = &pw->v;
- pwaudio *c = v->g;
- const char *error = NULL;
- int32_t filled, avail;
- uint32_t index;
-
- pw_thread_loop_lock(c->thread_loop);
- if (pw_stream_get_state(v->stream, &error) != PW_STREAM_STATE_STREAMING) {
- /* wait for stream to become ready */
- avail = 0;
- goto done_unlock;
- }
-
- filled = spa_ringbuffer_get_write_index(&v->ring, &index);
- avail = v->highwater_mark - filled;
-
-done_unlock:
- pw_thread_loop_unlock(c->thread_loop);
- return avail;
-}
-
-static size_t
-qpw_write(HWVoiceOut *hw, void *data, size_t len)
-{
- PWVoiceOut *pw = (PWVoiceOut *) hw;
- PWVoice *v = &pw->v;
- pwaudio *c = v->g;
- const char *error = NULL;
- int32_t filled, avail;
- uint32_t index;
-
- pw_thread_loop_lock(c->thread_loop);
- if (pw_stream_get_state(v->stream, &error) != PW_STREAM_STATE_STREAMING) {
- /* wait for stream to become ready */
- len = 0;
- goto done_unlock;
- }
- filled = spa_ringbuffer_get_write_index(&v->ring, &index);
- avail = v->highwater_mark - filled;
-
- trace_pw_write(filled, avail, index, len);
-
- if (len > avail) {
- len = avail;
- }
-
- if (filled < 0) {
- error_report("%p: underrun write:%u filled:%d", pw, index, filled);
- } else {
- if ((uint32_t) filled + len > RINGBUFFER_SIZE) {
- error_report("%p: overrun write:%u filled:%d + size:%zu > max:%u",
- pw, index, filled, len, RINGBUFFER_SIZE);
- }
- }
-
- spa_ringbuffer_write_data(&v->ring,
- v->buffer, RINGBUFFER_SIZE,
- index & RINGBUFFER_MASK, data, len);
- index += len;
- spa_ringbuffer_write_update(&v->ring, index);
-
-done_unlock:
- pw_thread_loop_unlock(c->thread_loop);
- return len;
-}
-
-static int
-audfmt_to_pw(AudioFormat fmt, int endianness)
-{
- int format;
-
- switch (fmt) {
- case AUDIO_FORMAT_S8:
- format = SPA_AUDIO_FORMAT_S8;
- break;
- case AUDIO_FORMAT_U8:
- format = SPA_AUDIO_FORMAT_U8;
- break;
- case AUDIO_FORMAT_S16:
- format = endianness ? SPA_AUDIO_FORMAT_S16_BE : SPA_AUDIO_FORMAT_S16_LE;
- break;
- case AUDIO_FORMAT_U16:
- format = endianness ? SPA_AUDIO_FORMAT_U16_BE : SPA_AUDIO_FORMAT_U16_LE;
- break;
- case AUDIO_FORMAT_S32:
- format = endianness ? SPA_AUDIO_FORMAT_S32_BE : SPA_AUDIO_FORMAT_S32_LE;
- break;
- case AUDIO_FORMAT_U32:
- format = endianness ? SPA_AUDIO_FORMAT_U32_BE : SPA_AUDIO_FORMAT_U32_LE;
- break;
- case AUDIO_FORMAT_F32:
- format = endianness ? SPA_AUDIO_FORMAT_F32_BE : SPA_AUDIO_FORMAT_F32_LE;
- break;
- default:
- dolog("Internal logic error: Bad audio format %d\n", fmt);
- format = SPA_AUDIO_FORMAT_U8;
- break;
- }
- return format;
-}
-
-static AudioFormat
-pw_to_audfmt(enum spa_audio_format fmt, int *endianness,
- uint32_t *sample_size)
-{
- switch (fmt) {
- case SPA_AUDIO_FORMAT_S8:
- *sample_size = 1;
- return AUDIO_FORMAT_S8;
- case SPA_AUDIO_FORMAT_U8:
- *sample_size = 1;
- return AUDIO_FORMAT_U8;
- case SPA_AUDIO_FORMAT_S16_BE:
- *sample_size = 2;
- *endianness = 1;
- return AUDIO_FORMAT_S16;
- case SPA_AUDIO_FORMAT_S16_LE:
- *sample_size = 2;
- *endianness = 0;
- return AUDIO_FORMAT_S16;
- case SPA_AUDIO_FORMAT_U16_BE:
- *sample_size = 2;
- *endianness = 1;
- return AUDIO_FORMAT_U16;
- case SPA_AUDIO_FORMAT_U16_LE:
- *sample_size = 2;
- *endianness = 0;
- return AUDIO_FORMAT_U16;
- case SPA_AUDIO_FORMAT_S32_BE:
- *sample_size = 4;
- *endianness = 1;
- return AUDIO_FORMAT_S32;
- case SPA_AUDIO_FORMAT_S32_LE:
- *sample_size = 4;
- *endianness = 0;
- return AUDIO_FORMAT_S32;
- case SPA_AUDIO_FORMAT_U32_BE:
- *sample_size = 4;
- *endianness = 1;
- return AUDIO_FORMAT_U32;
- case SPA_AUDIO_FORMAT_U32_LE:
- *sample_size = 4;
- *endianness = 0;
- return AUDIO_FORMAT_U32;
- case SPA_AUDIO_FORMAT_F32_BE:
- *sample_size = 4;
- *endianness = 1;
- return AUDIO_FORMAT_F32;
- case SPA_AUDIO_FORMAT_F32_LE:
- *sample_size = 4;
- *endianness = 0;
- return AUDIO_FORMAT_F32;
- default:
- *sample_size = 1;
- dolog("Internal logic error: Bad spa_audio_format %d\n", fmt);
- return AUDIO_FORMAT_U8;
- }
-}
-
-static int
-qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
- const char *name, enum spa_direction dir)
-{
- int res;
- uint32_t n_params;
- const struct spa_pod *params[2];
- uint8_t buffer[1024];
- struct spa_pod_builder b;
- uint64_t buf_samples;
- struct pw_properties *props;
-
- props = pw_properties_new(NULL, NULL);
- if (!props) {
- error_report("Failed to create PW properties: %s", g_strerror(errno));
- return -1;
- }
-
- /* 75% of the timer period for faster updates */
- buf_samples = (uint64_t)v->g->dev->timer_period * v->info.rate
- * 3 / 4 / 1000000;
- pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%" PRIu64 "/%u",
- buf_samples, v->info.rate);
-
- trace_pw_period(buf_samples, v->info.rate);
- if (name) {
- pw_properties_set(props, PW_KEY_TARGET_OBJECT, name);
- }
- v->stream = pw_stream_new(c->core, stream_name, props);
- if (v->stream == NULL) {
- error_report("Failed to create PW stream: %s", g_strerror(errno));
- return -1;
- }
-
- if (dir == SPA_DIRECTION_INPUT) {
- pw_stream_add_listener(v->stream,
- &v->stream_listener, &capture_stream_events, v);
- } else {
- pw_stream_add_listener(v->stream,
- &v->stream_listener, &playback_stream_events, v);
- }
-
- n_params = 0;
- spa_pod_builder_init(&b, buffer, sizeof(buffer));
- params[n_params++] = spa_format_audio_raw_build(&b,
- SPA_PARAM_EnumFormat,
- &v->info);
-
- /* connect the stream to a sink or source */
- res = pw_stream_connect(v->stream,
- dir ==
- SPA_DIRECTION_INPUT ? PW_DIRECTION_INPUT :
- PW_DIRECTION_OUTPUT, PW_ID_ANY,
- PW_STREAM_FLAG_AUTOCONNECT |
- PW_STREAM_FLAG_INACTIVE |
- PW_STREAM_FLAG_MAP_BUFFERS |
- PW_STREAM_FLAG_RT_PROCESS, params, n_params);
- if (res < 0) {
- error_report("Failed to connect PW stream: %s", g_strerror(errno));
- pw_stream_destroy(v->stream);
- return -1;
- }
-
- return 0;
-}
-
-static void
-qpw_set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS])
-{
- memcpy(position, (uint32_t[SPA_AUDIO_MAX_CHANNELS]) { SPA_AUDIO_CHANNEL_UNKNOWN, },
- sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS);
- /*
- * TODO: This currently expects the only frontend supporting more than 2
- * channels is the usb-audio. We will need some means to set channel
- * order when a new frontend gains multi-channel support.
- */
- switch (channels) {
- case 8:
- position[6] = SPA_AUDIO_CHANNEL_SL;
- position[7] = SPA_AUDIO_CHANNEL_SR;
- /* fallthrough */
- case 6:
- position[2] = SPA_AUDIO_CHANNEL_FC;
- position[3] = SPA_AUDIO_CHANNEL_LFE;
- position[4] = SPA_AUDIO_CHANNEL_RL;
- position[5] = SPA_AUDIO_CHANNEL_RR;
- /* fallthrough */
- case 2:
- position[0] = SPA_AUDIO_CHANNEL_FL;
- position[1] = SPA_AUDIO_CHANNEL_FR;
- break;
- case 1:
- position[0] = SPA_AUDIO_CHANNEL_MONO;
- break;
- default:
- dolog("Internal error: unsupported channel count %d\n", channels);
- }
-}
-
-static int
-qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
-{
- PWVoiceOut *pw = (PWVoiceOut *) hw;
- PWVoice *v = &pw->v;
- struct audsettings obt_as = *as;
- pwaudio *c = v->g = drv_opaque;
- AudiodevPipewireOptions *popts = &c->dev->u.pipewire;
- AudiodevPipewirePerDirectionOptions *ppdo = popts->out;
- int r;
-
- pw_thread_loop_lock(c->thread_loop);
-
- v->info.format = audfmt_to_pw(as->fmt, as->endianness);
- v->info.channels = as->nchannels;
- qpw_set_position(as->nchannels, v->info.position);
- v->info.rate = as->freq;
-
- obt_as.fmt =
- pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
- v->frame_size *= as->nchannels;
-
- v->req = (uint64_t)c->dev->timer_period * v->info.rate
- * 1 / 2 / 1000000 * v->frame_size;
-
- /* call the function that creates a new stream for playback */
- r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
- ppdo->name, SPA_DIRECTION_OUTPUT);
- if (r < 0) {
- pw_thread_loop_unlock(c->thread_loop);
- return -1;
- }
-
- /* report the audio format we support */
- audio_pcm_init_info(&hw->info, &obt_as);
-
- /* report the buffer size to qemu */
- hw->samples = audio_buffer_frames(
- qapi_AudiodevPipewirePerDirectionOptions_base(ppdo), &obt_as, 46440);
- v->highwater_mark = MIN(RINGBUFFER_SIZE,
- (ppdo->has_latency ? ppdo->latency : 46440)
- * (uint64_t)v->info.rate / 1000000 * v->frame_size);
-
- pw_thread_loop_unlock(c->thread_loop);
- return 0;
-}
-
-static int
-qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
-{
- PWVoiceIn *pw = (PWVoiceIn *) hw;
- PWVoice *v = &pw->v;
- struct audsettings obt_as = *as;
- pwaudio *c = v->g = drv_opaque;
- AudiodevPipewireOptions *popts = &c->dev->u.pipewire;
- AudiodevPipewirePerDirectionOptions *ppdo = popts->in;
- int r;
-
- pw_thread_loop_lock(c->thread_loop);
-
- v->info.format = audfmt_to_pw(as->fmt, as->endianness);
- v->info.channels = as->nchannels;
- qpw_set_position(as->nchannels, v->info.position);
- v->info.rate = as->freq;
-
- obt_as.fmt =
- pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
- v->frame_size *= as->nchannels;
-
- /* call the function that creates a new stream for recording */
- r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
- ppdo->name, SPA_DIRECTION_INPUT);
- if (r < 0) {
- pw_thread_loop_unlock(c->thread_loop);
- return -1;
- }
-
- /* report the audio format we support */
- audio_pcm_init_info(&hw->info, &obt_as);
-
- /* report the buffer size to qemu */
- hw->samples = audio_buffer_frames(
- qapi_AudiodevPipewirePerDirectionOptions_base(ppdo), &obt_as, 46440);
-
- pw_thread_loop_unlock(c->thread_loop);
- return 0;
-}
-
-static void
-qpw_voice_fini(PWVoice *v)
-{
- pwaudio *c = v->g;
-
- if (!v->stream) {
- return;
- }
- pw_thread_loop_lock(c->thread_loop);
- pw_stream_destroy(v->stream);
- v->stream = NULL;
- pw_thread_loop_unlock(c->thread_loop);
-}
-
-static void
-qpw_fini_out(HWVoiceOut *hw)
-{
- qpw_voice_fini(&PW_VOICE_OUT(hw)->v);
-}
-
-static void
-qpw_fini_in(HWVoiceIn *hw)
-{
- qpw_voice_fini(&PW_VOICE_IN(hw)->v);
-}
-
-static void
-qpw_voice_set_enabled(PWVoice *v, bool enable)
-{
- pwaudio *c = v->g;
- pw_thread_loop_lock(c->thread_loop);
- pw_stream_set_active(v->stream, enable);
- pw_thread_loop_unlock(c->thread_loop);
-}
-
-static void
-qpw_enable_out(HWVoiceOut *hw, bool enable)
-{
- qpw_voice_set_enabled(&PW_VOICE_OUT(hw)->v, enable);
-}
-
-static void
-qpw_enable_in(HWVoiceIn *hw, bool enable)
-{
- qpw_voice_set_enabled(&PW_VOICE_IN(hw)->v, enable);
-}
-
-static void
-qpw_voice_set_volume(PWVoice *v, Volume *vol)
-{
- pwaudio *c = v->g;
- int i, ret;
-
- pw_thread_loop_lock(c->thread_loop);
- v->volume.channels = vol->channels;
-
- for (i = 0; i < vol->channels; ++i) {
- v->volume.values[i] = (float)vol->vol[i] / 255;
- }
-
- ret = pw_stream_set_control(v->stream,
- SPA_PROP_channelVolumes, v->volume.channels, v->volume.values, 0);
- trace_pw_vol(ret == 0 ? "success" : "failed");
-
- v->muted = vol->mute;
- float val = v->muted ? 1.f : 0.f;
- ret = pw_stream_set_control(v->stream, SPA_PROP_mute, 1, &val, 0);
- pw_thread_loop_unlock(c->thread_loop);
-}
-
-static void
-qpw_volume_out(HWVoiceOut *hw, Volume *vol)
-{
- qpw_voice_set_volume(&PW_VOICE_OUT(hw)->v, vol);
-}
-
-static void
-qpw_volume_in(HWVoiceIn *hw, Volume *vol)
-{
- qpw_voice_set_volume(&PW_VOICE_IN(hw)->v, vol);
-}
-
-static int wait_resync(pwaudio *pw)
-{
- int res;
- pw->pending_seq = pw_core_sync(pw->core, PW_ID_CORE, pw->pending_seq);
-
- while (true) {
- pw_thread_loop_wait(pw->thread_loop);
-
- res = pw->error;
- if (res < 0) {
- pw->error = 0;
- return res;
- }
- if (pw->pending_seq == pw->last_seq) {
- break;
- }
- }
- return 0;
-}
-
-static void
-on_core_error(void *data, uint32_t id, int seq, int res, const char *message)
-{
- pwaudio *pw = data;
-
- error_report("error id:%u seq:%d res:%d (%s): %s",
- id, seq, res, spa_strerror(res), message);
-
- /* stop and exit the thread loop */
- pw_thread_loop_signal(pw->thread_loop, FALSE);
-}
-
-static void
-on_core_done(void *data, uint32_t id, int seq)
-{
- pwaudio *pw = data;
- assert(id == PW_ID_CORE);
- pw->last_seq = seq;
- if (pw->pending_seq == seq) {
- /* stop and exit the thread loop */
- pw_thread_loop_signal(pw->thread_loop, FALSE);
- }
-}
-
-static const struct pw_core_events core_events = {
- PW_VERSION_CORE_EVENTS,
- .done = on_core_done,
- .error = on_core_error,
-};
-
-static void *
-qpw_audio_init(Audiodev *dev, Error **errp)
-{
- g_autofree pwaudio *pw = g_new0(pwaudio, 1);
-
- assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
- trace_pw_audio_init();
-
- pw_init(NULL, NULL);
-
- pw->dev = dev;
- pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL);
- if (pw->thread_loop == NULL) {
- error_setg_errno(errp, errno, "Could not create PipeWire loop");
- goto fail;
- }
-
- pw->context =
- pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
- if (pw->context == NULL) {
- error_setg_errno(errp, errno, "Could not create PipeWire context");
- goto fail;
- }
-
- if (pw_thread_loop_start(pw->thread_loop) < 0) {
- error_setg_errno(errp, errno, "Could not start PipeWire loop");
- goto fail;
- }
-
- pw_thread_loop_lock(pw->thread_loop);
-
- pw->core = pw_context_connect(pw->context, NULL, 0);
- if (pw->core == NULL) {
- pw_thread_loop_unlock(pw->thread_loop);
- goto fail_error;
- }
-
- if (pw_core_add_listener(pw->core, &pw->core_listener,
- &core_events, pw) < 0) {
- pw_thread_loop_unlock(pw->thread_loop);
- goto fail_error;
- }
- if (wait_resync(pw) < 0) {
- pw_thread_loop_unlock(pw->thread_loop);
- }
-
- pw_thread_loop_unlock(pw->thread_loop);
-
- return g_steal_pointer(&pw);
-
-fail_error:
- error_setg(errp, "Failed to initialize PW context");
-fail:
- if (pw->thread_loop) {
- pw_thread_loop_stop(pw->thread_loop);
- }
- g_clear_pointer(&pw->context, pw_context_destroy);
- g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
- return NULL;
-}
-
-static void
-qpw_audio_fini(void *opaque)
-{
- pwaudio *pw = opaque;
-
- if (pw->thread_loop) {
- pw_thread_loop_stop(pw->thread_loop);
- }
-
- if (pw->core) {
- spa_hook_remove(&pw->core_listener);
- spa_zero(pw->core_listener);
- pw_core_disconnect(pw->core);
- }
-
- if (pw->context) {
- pw_context_destroy(pw->context);
- }
- pw_thread_loop_destroy(pw->thread_loop);
-
- g_free(pw);
-}
-
-static struct audio_pcm_ops qpw_pcm_ops = {
- .init_out = qpw_init_out,
- .fini_out = qpw_fini_out,
- .write = qpw_write,
- .buffer_get_free = qpw_buffer_get_free,
- .run_buffer_out = audio_generic_run_buffer_out,
- .enable_out = qpw_enable_out,
- .volume_out = qpw_volume_out,
- .volume_in = qpw_volume_in,
-
- .init_in = qpw_init_in,
- .fini_in = qpw_fini_in,
- .read = qpw_read,
- .run_buffer_in = audio_generic_run_buffer_in,
- .enable_in = qpw_enable_in
-};
-
-static struct audio_driver pw_audio_driver = {
- .name = "pipewire",
- .descr = "http://www.pipewire.org/",
- .init = qpw_audio_init,
- .fini = qpw_audio_fini,
- .pcm_ops = &qpw_pcm_ops,
- .max_voices_out = INT_MAX,
- .max_voices_in = INT_MAX,
- .voice_size_out = sizeof(PWVoiceOut),
- .voice_size_in = sizeof(PWVoiceIn),
-};
-
-static void
-register_audio_pw(void)
-{
- audio_driver_register(&pw_audio_driver);
-}
-
-type_init(register_audio_pw);
--
2.41.0.windows.1

View File

@ -0,0 +1,931 @@
From fab03a72da74e938a2a476f1824ac0acd4a1fee2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BC=A0=E6=A5=9A=E5=90=9B?=
<zhangchujun@cmss.chinamobile.com>
Date: Fri, 18 Oct 2024 10:17:10 +0800
Subject: [PATCH] audio/pw: Report more accurate error when connecting to
PipeWire fails
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
According to its man page [1], pw_context_connect() sets errno on
failure:
Returns a Core on success or NULL with errno set on error.
It may be handy to see errno when figuring out why PipeWire
failed to connect. That leaves us with just one possible path to
reach 'fail_error' label which is then moved to that path and
also its error message is adjusted slightly.
1: https://docs.pipewire.org/group__pw__core.html#ga5994e3a54e4ec718094ca02a1234815b
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <3a78811ad5b0e87816b7616ab21d2eeef00b9c52.1726647033.git.mprivozn@redhat.com>
Signed-off-by: Zhang Chujun <zhangchujun_yewu@cmss.chinamobile.com>
---
audio/pwaudio.c | 8 +-
audio/pwaudio.c.orig | 858 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 862 insertions(+), 4 deletions(-)
create mode 100644 audio/pwaudio.c.orig
diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 3ce5f6507b..5d1c7126d3 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -770,13 +770,15 @@ qpw_audio_init(Audiodev *dev, Error **errp)
pw->core = pw_context_connect(pw->context, NULL, 0);
if (pw->core == NULL) {
pw_thread_loop_unlock(pw->thread_loop);
- goto fail_error;
+ error_setg_errno(errp, errno, "Failed to connect to PipeWire instance");
+ goto fail;
}
if (pw_core_add_listener(pw->core, &pw->core_listener,
&core_events, pw) < 0) {
pw_thread_loop_unlock(pw->thread_loop);
- goto fail_error;
+ error_setg(errp, "Failed to add PipeWire listener");
+ goto fail;
}
if (wait_resync(pw) < 0) {
pw_thread_loop_unlock(pw->thread_loop);
@@ -786,8 +788,6 @@ qpw_audio_init(Audiodev *dev, Error **errp)
return g_steal_pointer(&pw);
-fail_error:
- error_setg(errp, "Failed to initialize PW context");
fail:
if (pw->thread_loop) {
pw_thread_loop_stop(pw->thread_loop);
diff --git a/audio/pwaudio.c.orig b/audio/pwaudio.c.orig
new file mode 100644
index 0000000000..3ce5f6507b
--- /dev/null
+++ b/audio/pwaudio.c.orig
@@ -0,0 +1,858 @@
+/*
+ * QEMU PipeWire audio driver
+ *
+ * Copyright (c) 2023 Red Hat Inc.
+ *
+ * Author: Dorinda Bassey <dbassey@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "audio.h"
+#include <errno.h>
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include <spa/param/audio/format-utils.h>
+#include <spa/utils/ringbuffer.h>
+#include <spa/utils/result.h>
+#include <spa/param/props.h>
+
+#include <pipewire/pipewire.h>
+#include "trace.h"
+
+#define AUDIO_CAP "pipewire"
+#define RINGBUFFER_SIZE (1u << 22)
+#define RINGBUFFER_MASK (RINGBUFFER_SIZE - 1)
+
+#include "audio_int.h"
+
+typedef struct pwvolume {
+ uint32_t channels;
+ float values[SPA_AUDIO_MAX_CHANNELS];
+} pwvolume;
+
+typedef struct pwaudio {
+ Audiodev *dev;
+ struct pw_thread_loop *thread_loop;
+ struct pw_context *context;
+
+ struct pw_core *core;
+ struct spa_hook core_listener;
+ int last_seq, pending_seq, error;
+} pwaudio;
+
+typedef struct PWVoice {
+ pwaudio *g;
+ struct pw_stream *stream;
+ struct spa_hook stream_listener;
+ struct spa_audio_info_raw info;
+ uint32_t highwater_mark;
+ uint32_t frame_size, req;
+ struct spa_ringbuffer ring;
+ uint8_t buffer[RINGBUFFER_SIZE];
+
+ pwvolume volume;
+ bool muted;
+} PWVoice;
+
+typedef struct PWVoiceOut {
+ HWVoiceOut hw;
+ PWVoice v;
+} PWVoiceOut;
+
+typedef struct PWVoiceIn {
+ HWVoiceIn hw;
+ PWVoice v;
+} PWVoiceIn;
+
+#define PW_VOICE_IN(v) ((PWVoiceIn *)v)
+#define PW_VOICE_OUT(v) ((PWVoiceOut *)v)
+
+static void
+stream_destroy(void *data)
+{
+ PWVoice *v = (PWVoice *) data;
+ spa_hook_remove(&v->stream_listener);
+ v->stream = NULL;
+}
+
+/* output data processing function to read stuffs from the buffer */
+static void
+playback_on_process(void *data)
+{
+ PWVoice *v = data;
+ void *p;
+ struct pw_buffer *b;
+ struct spa_buffer *buf;
+ uint32_t req, index, n_bytes;
+ int32_t avail;
+
+ assert(v->stream);
+
+ /* obtain a buffer to read from */
+ b = pw_stream_dequeue_buffer(v->stream);
+ if (b == NULL) {
+ error_report("out of buffers: %s", strerror(errno));
+ return;
+ }
+
+ buf = b->buffer;
+ p = buf->datas[0].data;
+ if (p == NULL) {
+ return;
+ }
+ /* calculate the total no of bytes to read data from buffer */
+ req = b->requested * v->frame_size;
+ if (req == 0) {
+ req = v->req;
+ }
+ n_bytes = SPA_MIN(req, buf->datas[0].maxsize);
+
+ /* get no of available bytes to read data from buffer */
+ avail = spa_ringbuffer_get_read_index(&v->ring, &index);
+
+ if (avail <= 0) {
+ PWVoiceOut *vo = container_of(data, PWVoiceOut, v);
+ audio_pcm_info_clear_buf(&vo->hw.info, p, n_bytes / v->frame_size);
+ } else {
+ if ((uint32_t) avail < n_bytes) {
+ /*
+ * PipeWire immediately calls this callback again if we provide
+ * less than n_bytes. Then audio_pcm_info_clear_buf() fills the
+ * rest of the buffer with silence.
+ */
+ n_bytes = avail;
+ }
+
+ spa_ringbuffer_read_data(&v->ring,
+ v->buffer, RINGBUFFER_SIZE,
+ index & RINGBUFFER_MASK, p, n_bytes);
+
+ index += n_bytes;
+ spa_ringbuffer_read_update(&v->ring, index);
+
+ }
+ buf->datas[0].chunk->offset = 0;
+ buf->datas[0].chunk->stride = v->frame_size;
+ buf->datas[0].chunk->size = n_bytes;
+
+ /* queue the buffer for playback */
+ pw_stream_queue_buffer(v->stream, b);
+}
+
+/* output data processing function to generate stuffs in the buffer */
+static void
+capture_on_process(void *data)
+{
+ PWVoice *v = (PWVoice *) data;
+ void *p;
+ struct pw_buffer *b;
+ struct spa_buffer *buf;
+ int32_t filled;
+ uint32_t index, offs, n_bytes;
+
+ assert(v->stream);
+
+ /* obtain a buffer */
+ b = pw_stream_dequeue_buffer(v->stream);
+ if (b == NULL) {
+ error_report("out of buffers: %s", strerror(errno));
+ return;
+ }
+
+ /* Write data into buffer */
+ buf = b->buffer;
+ p = buf->datas[0].data;
+ if (p == NULL) {
+ return;
+ }
+ offs = SPA_MIN(buf->datas[0].chunk->offset, buf->datas[0].maxsize);
+ n_bytes = SPA_MIN(buf->datas[0].chunk->size, buf->datas[0].maxsize - offs);
+
+ filled = spa_ringbuffer_get_write_index(&v->ring, &index);
+
+
+ if (filled < 0) {
+ error_report("%p: underrun write:%u filled:%d", p, index, filled);
+ } else {
+ if ((uint32_t) filled + n_bytes > RINGBUFFER_SIZE) {
+ error_report("%p: overrun write:%u filled:%d + size:%u > max:%u",
+ p, index, filled, n_bytes, RINGBUFFER_SIZE);
+ }
+ }
+ spa_ringbuffer_write_data(&v->ring,
+ v->buffer, RINGBUFFER_SIZE,
+ index & RINGBUFFER_MASK,
+ SPA_PTROFF(p, offs, void), n_bytes);
+ index += n_bytes;
+ spa_ringbuffer_write_update(&v->ring, index);
+
+ /* queue the buffer for playback */
+ pw_stream_queue_buffer(v->stream, b);
+}
+
+static void
+on_stream_state_changed(void *data, enum pw_stream_state old,
+ enum pw_stream_state state, const char *error)
+{
+ PWVoice *v = (PWVoice *) data;
+
+ trace_pw_state_changed(pw_stream_get_node_id(v->stream),
+ pw_stream_state_as_string(state));
+}
+
+static const struct pw_stream_events capture_stream_events = {
+ PW_VERSION_STREAM_EVENTS,
+ .destroy = stream_destroy,
+ .state_changed = on_stream_state_changed,
+ .process = capture_on_process
+};
+
+static const struct pw_stream_events playback_stream_events = {
+ PW_VERSION_STREAM_EVENTS,
+ .destroy = stream_destroy,
+ .state_changed = on_stream_state_changed,
+ .process = playback_on_process
+};
+
+static size_t
+qpw_read(HWVoiceIn *hw, void *data, size_t len)
+{
+ PWVoiceIn *pw = (PWVoiceIn *) hw;
+ PWVoice *v = &pw->v;
+ pwaudio *c = v->g;
+ const char *error = NULL;
+ size_t l;
+ int32_t avail;
+ uint32_t index;
+
+ pw_thread_loop_lock(c->thread_loop);
+ if (pw_stream_get_state(v->stream, &error) != PW_STREAM_STATE_STREAMING) {
+ /* wait for stream to become ready */
+ l = 0;
+ goto done_unlock;
+ }
+ /* get no of available bytes to read data from buffer */
+ avail = spa_ringbuffer_get_read_index(&v->ring, &index);
+
+ trace_pw_read(avail, index, len);
+
+ if (avail < (int32_t) len) {
+ len = avail;
+ }
+
+ spa_ringbuffer_read_data(&v->ring,
+ v->buffer, RINGBUFFER_SIZE,
+ index & RINGBUFFER_MASK, data, len);
+ index += len;
+ spa_ringbuffer_read_update(&v->ring, index);
+ l = len;
+
+done_unlock:
+ pw_thread_loop_unlock(c->thread_loop);
+ return l;
+}
+
+static size_t qpw_buffer_get_free(HWVoiceOut *hw)
+{
+ PWVoiceOut *pw = (PWVoiceOut *)hw;
+ PWVoice *v = &pw->v;
+ pwaudio *c = v->g;
+ const char *error = NULL;
+ int32_t filled, avail;
+ uint32_t index;
+
+ pw_thread_loop_lock(c->thread_loop);
+ if (pw_stream_get_state(v->stream, &error) != PW_STREAM_STATE_STREAMING) {
+ /* wait for stream to become ready */
+ avail = 0;
+ goto done_unlock;
+ }
+
+ filled = spa_ringbuffer_get_write_index(&v->ring, &index);
+ avail = v->highwater_mark - filled;
+
+done_unlock:
+ pw_thread_loop_unlock(c->thread_loop);
+ return avail;
+}
+
+static size_t
+qpw_write(HWVoiceOut *hw, void *data, size_t len)
+{
+ PWVoiceOut *pw = (PWVoiceOut *) hw;
+ PWVoice *v = &pw->v;
+ pwaudio *c = v->g;
+ const char *error = NULL;
+ int32_t filled, avail;
+ uint32_t index;
+
+ pw_thread_loop_lock(c->thread_loop);
+ if (pw_stream_get_state(v->stream, &error) != PW_STREAM_STATE_STREAMING) {
+ /* wait for stream to become ready */
+ len = 0;
+ goto done_unlock;
+ }
+ filled = spa_ringbuffer_get_write_index(&v->ring, &index);
+ avail = v->highwater_mark - filled;
+
+ trace_pw_write(filled, avail, index, len);
+
+ if (len > avail) {
+ len = avail;
+ }
+
+ if (filled < 0) {
+ error_report("%p: underrun write:%u filled:%d", pw, index, filled);
+ } else {
+ if ((uint32_t) filled + len > RINGBUFFER_SIZE) {
+ error_report("%p: overrun write:%u filled:%d + size:%zu > max:%u",
+ pw, index, filled, len, RINGBUFFER_SIZE);
+ }
+ }
+
+ spa_ringbuffer_write_data(&v->ring,
+ v->buffer, RINGBUFFER_SIZE,
+ index & RINGBUFFER_MASK, data, len);
+ index += len;
+ spa_ringbuffer_write_update(&v->ring, index);
+
+done_unlock:
+ pw_thread_loop_unlock(c->thread_loop);
+ return len;
+}
+
+static int
+audfmt_to_pw(AudioFormat fmt, int endianness)
+{
+ int format;
+
+ switch (fmt) {
+ case AUDIO_FORMAT_S8:
+ format = SPA_AUDIO_FORMAT_S8;
+ break;
+ case AUDIO_FORMAT_U8:
+ format = SPA_AUDIO_FORMAT_U8;
+ break;
+ case AUDIO_FORMAT_S16:
+ format = endianness ? SPA_AUDIO_FORMAT_S16_BE : SPA_AUDIO_FORMAT_S16_LE;
+ break;
+ case AUDIO_FORMAT_U16:
+ format = endianness ? SPA_AUDIO_FORMAT_U16_BE : SPA_AUDIO_FORMAT_U16_LE;
+ break;
+ case AUDIO_FORMAT_S32:
+ format = endianness ? SPA_AUDIO_FORMAT_S32_BE : SPA_AUDIO_FORMAT_S32_LE;
+ break;
+ case AUDIO_FORMAT_U32:
+ format = endianness ? SPA_AUDIO_FORMAT_U32_BE : SPA_AUDIO_FORMAT_U32_LE;
+ break;
+ case AUDIO_FORMAT_F32:
+ format = endianness ? SPA_AUDIO_FORMAT_F32_BE : SPA_AUDIO_FORMAT_F32_LE;
+ break;
+ default:
+ dolog("Internal logic error: Bad audio format %d\n", fmt);
+ format = SPA_AUDIO_FORMAT_U8;
+ break;
+ }
+ return format;
+}
+
+static AudioFormat
+pw_to_audfmt(enum spa_audio_format fmt, int *endianness,
+ uint32_t *sample_size)
+{
+ switch (fmt) {
+ case SPA_AUDIO_FORMAT_S8:
+ *sample_size = 1;
+ return AUDIO_FORMAT_S8;
+ case SPA_AUDIO_FORMAT_U8:
+ *sample_size = 1;
+ return AUDIO_FORMAT_U8;
+ case SPA_AUDIO_FORMAT_S16_BE:
+ *sample_size = 2;
+ *endianness = 1;
+ return AUDIO_FORMAT_S16;
+ case SPA_AUDIO_FORMAT_S16_LE:
+ *sample_size = 2;
+ *endianness = 0;
+ return AUDIO_FORMAT_S16;
+ case SPA_AUDIO_FORMAT_U16_BE:
+ *sample_size = 2;
+ *endianness = 1;
+ return AUDIO_FORMAT_U16;
+ case SPA_AUDIO_FORMAT_U16_LE:
+ *sample_size = 2;
+ *endianness = 0;
+ return AUDIO_FORMAT_U16;
+ case SPA_AUDIO_FORMAT_S32_BE:
+ *sample_size = 4;
+ *endianness = 1;
+ return AUDIO_FORMAT_S32;
+ case SPA_AUDIO_FORMAT_S32_LE:
+ *sample_size = 4;
+ *endianness = 0;
+ return AUDIO_FORMAT_S32;
+ case SPA_AUDIO_FORMAT_U32_BE:
+ *sample_size = 4;
+ *endianness = 1;
+ return AUDIO_FORMAT_U32;
+ case SPA_AUDIO_FORMAT_U32_LE:
+ *sample_size = 4;
+ *endianness = 0;
+ return AUDIO_FORMAT_U32;
+ case SPA_AUDIO_FORMAT_F32_BE:
+ *sample_size = 4;
+ *endianness = 1;
+ return AUDIO_FORMAT_F32;
+ case SPA_AUDIO_FORMAT_F32_LE:
+ *sample_size = 4;
+ *endianness = 0;
+ return AUDIO_FORMAT_F32;
+ default:
+ *sample_size = 1;
+ dolog("Internal logic error: Bad spa_audio_format %d\n", fmt);
+ return AUDIO_FORMAT_U8;
+ }
+}
+
+static int
+qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
+ const char *name, enum spa_direction dir)
+{
+ int res;
+ uint32_t n_params;
+ const struct spa_pod *params[2];
+ uint8_t buffer[1024];
+ struct spa_pod_builder b;
+ uint64_t buf_samples;
+ struct pw_properties *props;
+
+ props = pw_properties_new(NULL, NULL);
+ if (!props) {
+ error_report("Failed to create PW properties: %s", g_strerror(errno));
+ return -1;
+ }
+
+ /* 75% of the timer period for faster updates */
+ buf_samples = (uint64_t)v->g->dev->timer_period * v->info.rate
+ * 3 / 4 / 1000000;
+ pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%" PRIu64 "/%u",
+ buf_samples, v->info.rate);
+
+ trace_pw_period(buf_samples, v->info.rate);
+ if (name) {
+ pw_properties_set(props, PW_KEY_TARGET_OBJECT, name);
+ }
+ v->stream = pw_stream_new(c->core, stream_name, props);
+ if (v->stream == NULL) {
+ error_report("Failed to create PW stream: %s", g_strerror(errno));
+ return -1;
+ }
+
+ if (dir == SPA_DIRECTION_INPUT) {
+ pw_stream_add_listener(v->stream,
+ &v->stream_listener, &capture_stream_events, v);
+ } else {
+ pw_stream_add_listener(v->stream,
+ &v->stream_listener, &playback_stream_events, v);
+ }
+
+ n_params = 0;
+ spa_pod_builder_init(&b, buffer, sizeof(buffer));
+ params[n_params++] = spa_format_audio_raw_build(&b,
+ SPA_PARAM_EnumFormat,
+ &v->info);
+
+ /* connect the stream to a sink or source */
+ res = pw_stream_connect(v->stream,
+ dir ==
+ SPA_DIRECTION_INPUT ? PW_DIRECTION_INPUT :
+ PW_DIRECTION_OUTPUT, PW_ID_ANY,
+ PW_STREAM_FLAG_AUTOCONNECT |
+ PW_STREAM_FLAG_INACTIVE |
+ PW_STREAM_FLAG_MAP_BUFFERS |
+ PW_STREAM_FLAG_RT_PROCESS, params, n_params);
+ if (res < 0) {
+ error_report("Failed to connect PW stream: %s", g_strerror(errno));
+ pw_stream_destroy(v->stream);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+qpw_set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS])
+{
+ memcpy(position, (uint32_t[SPA_AUDIO_MAX_CHANNELS]) { SPA_AUDIO_CHANNEL_UNKNOWN, },
+ sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS);
+ /*
+ * TODO: This currently expects the only frontend supporting more than 2
+ * channels is the usb-audio. We will need some means to set channel
+ * order when a new frontend gains multi-channel support.
+ */
+ switch (channels) {
+ case 8:
+ position[6] = SPA_AUDIO_CHANNEL_SL;
+ position[7] = SPA_AUDIO_CHANNEL_SR;
+ /* fallthrough */
+ case 6:
+ position[2] = SPA_AUDIO_CHANNEL_FC;
+ position[3] = SPA_AUDIO_CHANNEL_LFE;
+ position[4] = SPA_AUDIO_CHANNEL_RL;
+ position[5] = SPA_AUDIO_CHANNEL_RR;
+ /* fallthrough */
+ case 2:
+ position[0] = SPA_AUDIO_CHANNEL_FL;
+ position[1] = SPA_AUDIO_CHANNEL_FR;
+ break;
+ case 1:
+ position[0] = SPA_AUDIO_CHANNEL_MONO;
+ break;
+ default:
+ dolog("Internal error: unsupported channel count %d\n", channels);
+ }
+}
+
+static int
+qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
+{
+ PWVoiceOut *pw = (PWVoiceOut *) hw;
+ PWVoice *v = &pw->v;
+ struct audsettings obt_as = *as;
+ pwaudio *c = v->g = drv_opaque;
+ AudiodevPipewireOptions *popts = &c->dev->u.pipewire;
+ AudiodevPipewirePerDirectionOptions *ppdo = popts->out;
+ int r;
+
+ pw_thread_loop_lock(c->thread_loop);
+
+ v->info.format = audfmt_to_pw(as->fmt, as->endianness);
+ v->info.channels = as->nchannels;
+ qpw_set_position(as->nchannels, v->info.position);
+ v->info.rate = as->freq;
+
+ obt_as.fmt =
+ pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
+ v->frame_size *= as->nchannels;
+
+ v->req = (uint64_t)c->dev->timer_period * v->info.rate
+ * 1 / 2 / 1000000 * v->frame_size;
+
+ /* call the function that creates a new stream for playback */
+ r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
+ ppdo->name, SPA_DIRECTION_OUTPUT);
+ if (r < 0) {
+ pw_thread_loop_unlock(c->thread_loop);
+ return -1;
+ }
+
+ /* report the audio format we support */
+ audio_pcm_init_info(&hw->info, &obt_as);
+
+ /* report the buffer size to qemu */
+ hw->samples = audio_buffer_frames(
+ qapi_AudiodevPipewirePerDirectionOptions_base(ppdo), &obt_as, 46440);
+ v->highwater_mark = MIN(RINGBUFFER_SIZE,
+ (ppdo->has_latency ? ppdo->latency : 46440)
+ * (uint64_t)v->info.rate / 1000000 * v->frame_size);
+
+ pw_thread_loop_unlock(c->thread_loop);
+ return 0;
+}
+
+static int
+qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
+{
+ PWVoiceIn *pw = (PWVoiceIn *) hw;
+ PWVoice *v = &pw->v;
+ struct audsettings obt_as = *as;
+ pwaudio *c = v->g = drv_opaque;
+ AudiodevPipewireOptions *popts = &c->dev->u.pipewire;
+ AudiodevPipewirePerDirectionOptions *ppdo = popts->in;
+ int r;
+
+ pw_thread_loop_lock(c->thread_loop);
+
+ v->info.format = audfmt_to_pw(as->fmt, as->endianness);
+ v->info.channels = as->nchannels;
+ qpw_set_position(as->nchannels, v->info.position);
+ v->info.rate = as->freq;
+
+ obt_as.fmt =
+ pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
+ v->frame_size *= as->nchannels;
+
+ /* call the function that creates a new stream for recording */
+ r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
+ ppdo->name, SPA_DIRECTION_INPUT);
+ if (r < 0) {
+ pw_thread_loop_unlock(c->thread_loop);
+ return -1;
+ }
+
+ /* report the audio format we support */
+ audio_pcm_init_info(&hw->info, &obt_as);
+
+ /* report the buffer size to qemu */
+ hw->samples = audio_buffer_frames(
+ qapi_AudiodevPipewirePerDirectionOptions_base(ppdo), &obt_as, 46440);
+
+ pw_thread_loop_unlock(c->thread_loop);
+ return 0;
+}
+
+static void
+qpw_voice_fini(PWVoice *v)
+{
+ pwaudio *c = v->g;
+
+ if (!v->stream) {
+ return;
+ }
+ pw_thread_loop_lock(c->thread_loop);
+ pw_stream_destroy(v->stream);
+ v->stream = NULL;
+ pw_thread_loop_unlock(c->thread_loop);
+}
+
+static void
+qpw_fini_out(HWVoiceOut *hw)
+{
+ qpw_voice_fini(&PW_VOICE_OUT(hw)->v);
+}
+
+static void
+qpw_fini_in(HWVoiceIn *hw)
+{
+ qpw_voice_fini(&PW_VOICE_IN(hw)->v);
+}
+
+static void
+qpw_voice_set_enabled(PWVoice *v, bool enable)
+{
+ pwaudio *c = v->g;
+ pw_thread_loop_lock(c->thread_loop);
+ pw_stream_set_active(v->stream, enable);
+ pw_thread_loop_unlock(c->thread_loop);
+}
+
+static void
+qpw_enable_out(HWVoiceOut *hw, bool enable)
+{
+ qpw_voice_set_enabled(&PW_VOICE_OUT(hw)->v, enable);
+}
+
+static void
+qpw_enable_in(HWVoiceIn *hw, bool enable)
+{
+ qpw_voice_set_enabled(&PW_VOICE_IN(hw)->v, enable);
+}
+
+static void
+qpw_voice_set_volume(PWVoice *v, Volume *vol)
+{
+ pwaudio *c = v->g;
+ int i, ret;
+
+ pw_thread_loop_lock(c->thread_loop);
+ v->volume.channels = vol->channels;
+
+ for (i = 0; i < vol->channels; ++i) {
+ v->volume.values[i] = (float)vol->vol[i] / 255;
+ }
+
+ ret = pw_stream_set_control(v->stream,
+ SPA_PROP_channelVolumes, v->volume.channels, v->volume.values, 0);
+ trace_pw_vol(ret == 0 ? "success" : "failed");
+
+ v->muted = vol->mute;
+ float val = v->muted ? 1.f : 0.f;
+ ret = pw_stream_set_control(v->stream, SPA_PROP_mute, 1, &val, 0);
+ pw_thread_loop_unlock(c->thread_loop);
+}
+
+static void
+qpw_volume_out(HWVoiceOut *hw, Volume *vol)
+{
+ qpw_voice_set_volume(&PW_VOICE_OUT(hw)->v, vol);
+}
+
+static void
+qpw_volume_in(HWVoiceIn *hw, Volume *vol)
+{
+ qpw_voice_set_volume(&PW_VOICE_IN(hw)->v, vol);
+}
+
+static int wait_resync(pwaudio *pw)
+{
+ int res;
+ pw->pending_seq = pw_core_sync(pw->core, PW_ID_CORE, pw->pending_seq);
+
+ while (true) {
+ pw_thread_loop_wait(pw->thread_loop);
+
+ res = pw->error;
+ if (res < 0) {
+ pw->error = 0;
+ return res;
+ }
+ if (pw->pending_seq == pw->last_seq) {
+ break;
+ }
+ }
+ return 0;
+}
+
+static void
+on_core_error(void *data, uint32_t id, int seq, int res, const char *message)
+{
+ pwaudio *pw = data;
+
+ error_report("error id:%u seq:%d res:%d (%s): %s",
+ id, seq, res, spa_strerror(res), message);
+
+ /* stop and exit the thread loop */
+ pw_thread_loop_signal(pw->thread_loop, FALSE);
+}
+
+static void
+on_core_done(void *data, uint32_t id, int seq)
+{
+ pwaudio *pw = data;
+ assert(id == PW_ID_CORE);
+ pw->last_seq = seq;
+ if (pw->pending_seq == seq) {
+ /* stop and exit the thread loop */
+ pw_thread_loop_signal(pw->thread_loop, FALSE);
+ }
+}
+
+static const struct pw_core_events core_events = {
+ PW_VERSION_CORE_EVENTS,
+ .done = on_core_done,
+ .error = on_core_error,
+};
+
+static void *
+qpw_audio_init(Audiodev *dev, Error **errp)
+{
+ g_autofree pwaudio *pw = g_new0(pwaudio, 1);
+
+ assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
+ trace_pw_audio_init();
+
+ pw_init(NULL, NULL);
+
+ pw->dev = dev;
+ pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL);
+ if (pw->thread_loop == NULL) {
+ error_setg_errno(errp, errno, "Could not create PipeWire loop");
+ goto fail;
+ }
+
+ pw->context =
+ pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
+ if (pw->context == NULL) {
+ error_setg_errno(errp, errno, "Could not create PipeWire context");
+ goto fail;
+ }
+
+ if (pw_thread_loop_start(pw->thread_loop) < 0) {
+ error_setg_errno(errp, errno, "Could not start PipeWire loop");
+ goto fail;
+ }
+
+ pw_thread_loop_lock(pw->thread_loop);
+
+ pw->core = pw_context_connect(pw->context, NULL, 0);
+ if (pw->core == NULL) {
+ pw_thread_loop_unlock(pw->thread_loop);
+ goto fail_error;
+ }
+
+ if (pw_core_add_listener(pw->core, &pw->core_listener,
+ &core_events, pw) < 0) {
+ pw_thread_loop_unlock(pw->thread_loop);
+ goto fail_error;
+ }
+ if (wait_resync(pw) < 0) {
+ pw_thread_loop_unlock(pw->thread_loop);
+ }
+
+ pw_thread_loop_unlock(pw->thread_loop);
+
+ return g_steal_pointer(&pw);
+
+fail_error:
+ error_setg(errp, "Failed to initialize PW context");
+fail:
+ if (pw->thread_loop) {
+ pw_thread_loop_stop(pw->thread_loop);
+ }
+ g_clear_pointer(&pw->context, pw_context_destroy);
+ g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
+ return NULL;
+}
+
+static void
+qpw_audio_fini(void *opaque)
+{
+ pwaudio *pw = opaque;
+
+ if (pw->thread_loop) {
+ pw_thread_loop_stop(pw->thread_loop);
+ }
+
+ if (pw->core) {
+ spa_hook_remove(&pw->core_listener);
+ spa_zero(pw->core_listener);
+ pw_core_disconnect(pw->core);
+ }
+
+ if (pw->context) {
+ pw_context_destroy(pw->context);
+ }
+ pw_thread_loop_destroy(pw->thread_loop);
+
+ g_free(pw);
+}
+
+static struct audio_pcm_ops qpw_pcm_ops = {
+ .init_out = qpw_init_out,
+ .fini_out = qpw_fini_out,
+ .write = qpw_write,
+ .buffer_get_free = qpw_buffer_get_free,
+ .run_buffer_out = audio_generic_run_buffer_out,
+ .enable_out = qpw_enable_out,
+ .volume_out = qpw_volume_out,
+ .volume_in = qpw_volume_in,
+
+ .init_in = qpw_init_in,
+ .fini_in = qpw_fini_in,
+ .read = qpw_read,
+ .run_buffer_in = audio_generic_run_buffer_in,
+ .enable_in = qpw_enable_in
+};
+
+static struct audio_driver pw_audio_driver = {
+ .name = "pipewire",
+ .descr = "http://www.pipewire.org/",
+ .init = qpw_audio_init,
+ .fini = qpw_audio_fini,
+ .pcm_ops = &qpw_pcm_ops,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = INT_MAX,
+ .voice_size_out = sizeof(PWVoiceOut),
+ .voice_size_in = sizeof(PWVoiceIn),
+};
+
+static void
+register_audio_pw(void)
+{
+ audio_driver_register(&pw_audio_driver);
+}
+
+type_init(register_audio_pw);
--
2.41.0.windows.1

View File

@ -0,0 +1,61 @@
From 9daf2b936101d612a295217822791d323e908fc9 Mon Sep 17 00:00:00 2001
From: Stefano Garzarella <sgarzare@redhat.com>
Date: Thu, 8 Aug 2024 10:05:45 +0200
Subject: [PATCH] block/blkio: use FUA flag on write zeroes only if supported
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
libblkio supports BLKIO_REQ_FUA with write zeros requests only since
version 1.4.0, so let's inform the block layer that the blkio driver
supports it only in this case. Otherwise we can have runtime errors
as reported in https://issues.redhat.com/browse/RHEL-32878
Fixes: fd66dbd424 ("blkio: add libblkio block driver")
Cc: qemu-stable@nongnu.org
Buglink: https://issues.redhat.com/browse/RHEL-32878
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20240808080545.40744-1-sgarzare@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 547c4e50929ec6c091d9c16a7b280e829b12b463)
Signed-off-by: zhujun2 <zhujun2_yewu@cmss.chinamobile.com>
---
block/blkio.c | 6 ++++--
meson.build | 2 ++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/block/blkio.c b/block/blkio.c
index b989617608..027c16ceb6 100644
--- a/block/blkio.c
+++ b/block/blkio.c
@@ -899,8 +899,10 @@ static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags,
}
bs->supported_write_flags = BDRV_REQ_FUA | BDRV_REQ_REGISTERED_BUF;
- bs->supported_zero_flags = BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP |
- BDRV_REQ_NO_FALLBACK;
+ bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
+#ifdef CONFIG_BLKIO_WRITE_ZEROS_FUA
+ bs->supported_zero_flags |= BDRV_REQ_FUA;
+#endif
qemu_mutex_init(&s->blkio_lock);
qemu_co_mutex_init(&s->bounce_lock);
diff --git a/meson.build b/meson.build
index 4024f9a4bb..ce2fd07963 100644
--- a/meson.build
+++ b/meson.build
@@ -2181,6 +2181,8 @@ config_host_data.set('CONFIG_BLKIO', blkio.found())
if blkio.found()
config_host_data.set('CONFIG_BLKIO_VHOST_VDPA_FD',
blkio.version().version_compare('>=1.3.0'))
+ config_host_data.set('CONFIG_BLKIO_WRITE_ZEROS_FUA',
+ blkio.version().version_compare('>=1.4.0'))
endif
config_host_data.set('CONFIG_CURL', curl.found())
config_host_data.set('CONFIG_CURSES', curses.found())
--
2.41.0.windows.1

View File

@ -0,0 +1,57 @@
From c64bd463b120056ff1e6c32e48fa24b6afd17f23 Mon Sep 17 00:00:00 2001
From: dinglimin <dinglimin@cmss.chinamobile.com>
Date: Sat, 12 Oct 2024 13:47:25 +0800
Subject: [PATCH] crypto: drop gnutls debug logging support MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
GNUTLS already supports dynamically enabling its logging at runtime by
setting the env var 'GNUTLS_DEBUG_LEVEL=10', so there is no need to
re-invent this logic in QEMU in a way that requires a re-compile.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: dinglimin <dinglimin@cmss.chinamobile.com>
---
crypto/init.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/crypto/init.c b/crypto/init.c
index fb7f1bff10..674d237fa9 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -34,14 +34,11 @@
#include "crypto/random.h"
-/* #define DEBUG_GNUTLS */
-#ifdef DEBUG_GNUTLS
-static void qcrypto_gnutls_log(int level, const char *str)
-{
- fprintf(stderr, "%d: %s", level, str);
-}
-#endif
+/*
+ * To debug GNUTLS see env vars listed in
+ * https://gnutls.org/manual/html_node/Debugging-and-auditing.html
+ */
int qcrypto_init(Error **errp)
{
#ifdef CONFIG_GNUTLS
@@ -53,10 +50,6 @@ int qcrypto_init(Error **errp)
gnutls_strerror(ret));
return -1;
}
-#ifdef DEBUG_GNUTLS
- gnutls_global_set_log_level(10);
- gnutls_global_set_log_function(qcrypto_gnutls_log);
-#endif
#endif
#ifdef CONFIG_GCRYPT
--
2.41.0.windows.1

View File

@ -0,0 +1,168 @@
From e1aaa51fc2de072871cce45dd165e2cb38515978 Mon Sep 17 00:00:00 2001
From: dinglimin <dinglimin@cmss.chinamobile.com>
Date: Sat, 12 Oct 2024 14:00:08 +0800
Subject: [PATCH] crypto: factor out conversion of QAPI to gcrypt constants
MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The conversion of cipher mode will shortly be required in more
than one place.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: dinglimin <dinglimin@cmss.chinamobile.com>
---
crypto/cipher-gcrypt.c.inc | 116 +++++++++++++++++++------------------
1 file changed, 60 insertions(+), 56 deletions(-)
diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc
index 1377cbaf14..6b82280f90 100644
--- a/crypto/cipher-gcrypt.c.inc
+++ b/crypto/cipher-gcrypt.c.inc
@@ -20,6 +20,56 @@
#include <gcrypt.h>
+static int qcrypto_cipher_alg_to_gcry_alg(QCryptoCipherAlgorithm alg)
+{
+ switch (alg) {
+ case QCRYPTO_CIPHER_ALG_DES:
+ return GCRY_CIPHER_DES;
+ case QCRYPTO_CIPHER_ALG_3DES:
+ return GCRY_CIPHER_3DES;
+ case QCRYPTO_CIPHER_ALG_AES_128:
+ return GCRY_CIPHER_AES128;
+ case QCRYPTO_CIPHER_ALG_AES_192:
+ return GCRY_CIPHER_AES192;
+ case QCRYPTO_CIPHER_ALG_AES_256:
+ return GCRY_CIPHER_AES256;
+ case QCRYPTO_CIPHER_ALG_CAST5_128:
+ return GCRY_CIPHER_CAST5;
+ case QCRYPTO_CIPHER_ALG_SERPENT_128:
+ return GCRY_CIPHER_SERPENT128;
+ case QCRYPTO_CIPHER_ALG_SERPENT_192:
+ return GCRY_CIPHER_SERPENT192;
+ case QCRYPTO_CIPHER_ALG_SERPENT_256:
+ return GCRY_CIPHER_SERPENT256;
+ case QCRYPTO_CIPHER_ALG_TWOFISH_128:
+ return GCRY_CIPHER_TWOFISH128;
+ case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+ return GCRY_CIPHER_TWOFISH;
+#ifdef CONFIG_CRYPTO_SM4
+ case QCRYPTO_CIPHER_ALG_SM4:
+ return GCRY_CIPHER_SM4;
+#endif
+ default:
+ return GCRY_CIPHER_NONE;
+ }
+}
+
+static int qcrypto_cipher_mode_to_gcry_mode(QCryptoCipherMode mode)
+{
+ switch (mode) {
+ case QCRYPTO_CIPHER_MODE_ECB:
+ return GCRY_CIPHER_MODE_ECB;
+ case QCRYPTO_CIPHER_MODE_XTS:
+ return GCRY_CIPHER_MODE_XTS;
+ case QCRYPTO_CIPHER_MODE_CBC:
+ return GCRY_CIPHER_MODE_CBC;
+ case QCRYPTO_CIPHER_MODE_CTR:
+ return GCRY_CIPHER_MODE_CTR;
+ default:
+ return GCRY_CIPHER_MODE_NONE;
+ }
+}
+
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode)
{
@@ -188,72 +238,26 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return NULL;
}
- switch (alg) {
- case QCRYPTO_CIPHER_ALG_DES:
- gcryalg = GCRY_CIPHER_DES;
- break;
- case QCRYPTO_CIPHER_ALG_3DES:
- gcryalg = GCRY_CIPHER_3DES;
- break;
- case QCRYPTO_CIPHER_ALG_AES_128:
- gcryalg = GCRY_CIPHER_AES128;
- break;
- case QCRYPTO_CIPHER_ALG_AES_192:
- gcryalg = GCRY_CIPHER_AES192;
- break;
- case QCRYPTO_CIPHER_ALG_AES_256:
- gcryalg = GCRY_CIPHER_AES256;
- break;
- case QCRYPTO_CIPHER_ALG_CAST5_128:
- gcryalg = GCRY_CIPHER_CAST5;
- break;
- case QCRYPTO_CIPHER_ALG_SERPENT_128:
- gcryalg = GCRY_CIPHER_SERPENT128;
- break;
- case QCRYPTO_CIPHER_ALG_SERPENT_192:
- gcryalg = GCRY_CIPHER_SERPENT192;
- break;
- case QCRYPTO_CIPHER_ALG_SERPENT_256:
- gcryalg = GCRY_CIPHER_SERPENT256;
- break;
- case QCRYPTO_CIPHER_ALG_TWOFISH_128:
- gcryalg = GCRY_CIPHER_TWOFISH128;
- break;
- case QCRYPTO_CIPHER_ALG_TWOFISH_256:
- gcryalg = GCRY_CIPHER_TWOFISH;
- break;
-#ifdef CONFIG_CRYPTO_SM4
- case QCRYPTO_CIPHER_ALG_SM4:
- gcryalg = GCRY_CIPHER_SM4;
- break;
-#endif
- default:
+ gcryalg = qcrypto_cipher_alg_to_gcry_alg(alg);
+ if (gcryalg == GCRY_CIPHER_NONE) {
error_setg(errp, "Unsupported cipher algorithm %s",
QCryptoCipherAlgorithm_str(alg));
return NULL;
}
- drv = &qcrypto_gcrypt_driver;
- switch (mode) {
- case QCRYPTO_CIPHER_MODE_ECB:
- gcrymode = GCRY_CIPHER_MODE_ECB;
- break;
- case QCRYPTO_CIPHER_MODE_XTS:
- gcrymode = GCRY_CIPHER_MODE_XTS;
- break;
- case QCRYPTO_CIPHER_MODE_CBC:
- gcrymode = GCRY_CIPHER_MODE_CBC;
- break;
- case QCRYPTO_CIPHER_MODE_CTR:
- drv = &qcrypto_gcrypt_ctr_driver;
- gcrymode = GCRY_CIPHER_MODE_CTR;
- break;
- default:
+ gcrymode = qcrypto_cipher_mode_to_gcry_mode(mode);
+ if (gcrymode == GCRY_CIPHER_MODE_NONE) {
error_setg(errp, "Unsupported cipher mode %s",
QCryptoCipherMode_str(mode));
return NULL;
}
+ if (mode == QCRYPTO_CIPHER_MODE_CTR) {
+ drv = &qcrypto_gcrypt_ctr_driver;
+ } else {
+ drv = &qcrypto_gcrypt_driver;
+ }
+
ctx = g_new0(QCryptoCipherGcrypt, 1);
ctx->base.driver = drv;
--
2.41.0.windows.1

View File

@ -0,0 +1,78 @@
From 7bd04536327357a97206d8048f5d9341780bbe5a Mon Sep 17 00:00:00 2001
From: dinglimin <dinglimin@cmss.chinamobile.com>
Date: Sat, 12 Oct 2024 11:26:16 +0800
Subject: [PATCH] crypto: use consistent error reporting pattern for
unsupported cipher modes MIME-Version: 1.0 Content-Type: text/plain;
charset=UTF-8 Content-Transfer-Encoding: 8bit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Not all paths in qcrypto_cipher_ctx_new() were correctly distinguishing
between valid user input for cipher mode (which should report a user
facing error), vs program logic errors (which should assert).
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: dinglimin <dinglimin@cmss.chinamobile.com>
---
crypto/cipher-nettle.c.inc | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/crypto/cipher-nettle.c.inc b/crypto/cipher-nettle.c.inc
index 766de036ba..2654b439c1 100644
--- a/crypto/cipher-nettle.c.inc
+++ b/crypto/cipher-nettle.c.inc
@@ -525,8 +525,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_CTR:
drv = &qcrypto_nettle_des_driver_ctr;
break;
- default:
+ case QCRYPTO_CIPHER_MODE_XTS:
goto bad_cipher_mode;
+ default:
+ g_assert_not_reached();
}
ctx = g_new0(QCryptoNettleDES, 1);
@@ -551,8 +553,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_CTR:
drv = &qcrypto_nettle_des3_driver_ctr;
break;
- default:
+ case QCRYPTO_CIPHER_MODE_XTS:
goto bad_cipher_mode;
+ default:
+ g_assert_not_reached();
}
ctx = g_new0(QCryptoNettleDES3, 1);
@@ -663,8 +667,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_CTR:
drv = &qcrypto_nettle_cast128_driver_ctr;
break;
- default:
+ case QCRYPTO_CIPHER_MODE_XTS:
goto bad_cipher_mode;
+ default:
+ g_assert_not_reached();
}
ctx = g_new0(QCryptoNettleCAST128, 1);
@@ -741,8 +747,12 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_ECB:
drv = &qcrypto_nettle_sm4_driver_ecb;
break;
- default:
+ case QCRYPTO_CIPHER_MODE_CBC:
+ case QCRYPTO_CIPHER_MODE_CTR:
+ case QCRYPTO_CIPHER_MODE_XTS:
goto bad_cipher_mode;
+ default:
+ g_assert_not_reached();
}
ctx = g_new0(QCryptoNettleSm4, 1);
--
2.41.0.windows.1

View File

@ -0,0 +1,294 @@
From dffc0f55d93ececee55a8548d7dab227ee76b234 Mon Sep 17 00:00:00 2001
From: liupingwei <liupingwei0317@outlook.com>
Date: Thu, 24 Oct 2024 19:05:58 +0800
Subject: [PATCH] cvm : Add support for TEE-based national encryption
acceleration.
This commit enables the use of TEE for national encryption acceleration
in cvm and speeds up OpenSSL encrption /decryption operations.
Signed-off-by: liupingwei <liupingwei0317@outlook.com>
---
hw/arm/virt.c | 61 ++++++++++++++++++++++++++++++-
include/hw/arm/virt.h | 1 +
linux-headers/asm-arm64/kvm.h | 10 ++++++
qapi/qom.json | 1 +
target/arm/kvm-tmm.c | 68 +++++++++++++++++++++++++++++++++--
target/arm/kvm_arm.h | 4 +++
6 files changed, 142 insertions(+), 3 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e73a795d3d..248788db03 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1967,6 +1967,10 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits)
"kvm-type", &error_abort);
if (!strcmp(kvm_type, "cvm")) {
+ /* support kae vf device tree nodes */
+ vms->memmap[VIRT_PCIE_MMIO] = (MemMapEntry) { 0x10000000, 0x2edf0000 };
+ vms->memmap[VIRT_KAE_DEVICE] = (MemMapEntry) { 0x3edf0000, 0x00200000 };
+
vms->memmap[VIRT_MEM].base = 3 * GiB;
vms->memmap[VIRT_MEM].size = ms->ram_size;
info_report("[qemu] fix VIRT_MEM range 0x%llx - 0x%llx\n", (unsigned long long)(vms->memmap[VIRT_MEM].base),
@@ -2380,6 +2384,56 @@ out:
return;
}
+static void fdt_add_hisi_sec_nodes(const VirtMachineState *vms, int dev_id)
+{
+ const MachineState *ms = MACHINE(vms);
+ hwaddr size = 0x10000;
+
+ /*
+ * Calculate the base address for the sec device node.
+ * Each device group contains one sec device and one hpre device,spaced by 2 * size.
+ */
+ hwaddr base = vms->memmap[VIRT_KAE_DEVICE].base + dev_id * 2 * size;
+ char *nodename;
+
+ tmm_set_sec_addr(base, dev_id);
+
+ nodename = g_strdup_printf("/hisi-sec@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "hisilicon,hip07-sec-vf");
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+ g_free(nodename);
+}
+
+static void fdt_add_hisi_hpre_nodes(const VirtMachineState *vms, int dev_id)
+{
+ const MachineState *ms = MACHINE(vms);
+ hwaddr size = 0x10000;
+
+ /*
+ * Calculate the base address for the hpre device node.
+ * Each hpre device follows the corresponding sec device by an additional offset of size.
+ */
+ hwaddr base = vms->memmap[VIRT_KAE_DEVICE].base + dev_id * 2 * size + size;
+ char *nodename;
+
+ tmm_set_hpre_addr(base, dev_id);
+
+ nodename = g_strdup_printf("/hisi-hpre@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "hisilicon,hip07-hpre-vf");
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+ g_free(nodename);
+}
+
+static void fdt_add_all_hisi_nodes(const VirtMachineState *vms, int dev_id)
+{
+ for (int i = 0; i < dev_id; i++) {
+ fdt_add_hisi_sec_nodes(vms, i);
+ fdt_add_hisi_hpre_nodes(vms, i);
+ }
+}
+
static void machvirt_init(MachineState *machine)
{
VirtMachineState *vms = VIRT_MACHINE(machine);
@@ -2530,14 +2584,19 @@ static void machvirt_init(MachineState *machine)
}
}
+ create_fdt(vms);
+
if (virtcca_cvm_enabled()) {
+ int kae_num = tmm_get_kae_num();
+ fdt_add_all_hisi_nodes(vms, kae_num);
+
int ret = kvm_arm_tmm_init(machine->cgs, &error_fatal);
if (ret != 0) {
error_report("fail to initialize TMM");
exit(1);
}
}
- create_fdt(vms);
+
qemu_log("cpu init start\n");
cpu_class = object_class_by_name(machine->cpu_type);
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 27f5333772..76a0d3fa5b 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -66,6 +66,7 @@ enum {
VIRT_FW_CFG,
VIRT_PCIE,
VIRT_PCIE_MMIO,
+ VIRT_KAE_DEVICE,
VIRT_PCIE_PIO,
VIRT_PCIE_ECAM,
VIRT_PLATFORM_BUS,
diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index 2b040b5d60..552fdcb18f 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -541,6 +541,9 @@ struct reg_mask_range {
#define KVM_CAP_ARM_TMM_CFG_SVE 2
#define KVM_CAP_ARM_TMM_CFG_DBG 3
#define KVM_CAP_ARM_TMM_CFG_PMU 4
+#define KVM_CAP_ARM_TMM_CFG_KAE 5
+
+#define KVM_ARM_TMM_MAX_KAE_VF_NUM 11
struct kvm_cap_arm_tmm_config_item {
__u32 cfg;
@@ -570,6 +573,13 @@ struct kvm_cap_arm_tmm_config_item {
struct {
__u32 num_pmu_cntrs;
};
+
+ /* cfg == KVM_CAP_ARM_TMM_CFG_KAE */
+ struct {
+ __u32 kae_vf_num;
+ __u64 sec_addr[KVM_ARM_TMM_MAX_KAE_VF_NUM];
+ __u64 hpre_addr[KVM_ARM_TMM_MAX_KAE_VF_NUM];
+ };
/* Fix the size of the union */
__u8 reserved[256];
};
diff --git a/qapi/qom.json b/qapi/qom.json
index 213edd8db2..293d727a04 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -921,6 +921,7 @@
{ 'struct': 'TmmGuestProperties',
'data': { '*sve-vector-length': 'uint32',
'*num-pmu-counters': 'uint32',
+ '*kae': 'uint32',
'*measurement-algo': 'TmmGuestMeasurementAlgo' } }
##
diff --git a/target/arm/kvm-tmm.c b/target/arm/kvm-tmm.c
index efe2ca0006..ea6bcc0f40 100644
--- a/target/arm/kvm-tmm.c
+++ b/target/arm/kvm-tmm.c
@@ -19,13 +19,20 @@
#include "sysemu/kvm.h"
#include "sysemu/runstate.h"
#include "hw/loader.h"
+#include "linux-headers/asm-arm64/kvm.h"
#define TYPE_TMM_GUEST "tmm-guest"
OBJECT_DECLARE_SIMPLE_TYPE(TmmGuest, TMM_GUEST)
#define TMM_PAGE_SIZE qemu_real_host_page_size()
-#define TMM_MAX_PMU_CTRS 0x20
-#define TMM_MAX_CFG 5
+#define TMM_MAX_PMU_CTRS 0x20
+#define TMM_MAX_CFG 6
+
+typedef struct {
+ uint32_t kae_vf_num;
+ hwaddr sec_addr[KVM_ARM_TMM_MAX_KAE_VF_NUM];
+ hwaddr hpre_addr[KVM_ARM_TMM_MAX_KAE_VF_NUM];
+} KaeDeviceInfo;
struct TmmGuest {
ConfidentialGuestSupport parent_obj;
@@ -33,6 +40,7 @@ struct TmmGuest {
TmmGuestMeasurementAlgo measurement_algo;
uint32_t sve_vl;
uint32_t num_pmu_cntrs;
+ KaeDeviceInfo kae_device_info;
};
typedef struct {
@@ -92,6 +100,17 @@ static int tmm_configure_one(TmmGuest *guest, uint32_t cfg, Error **errp)
args.num_pmu_cntrs = guest->num_pmu_cntrs;
cfg_str = "PMU";
break;
+ case KVM_CAP_ARM_TMM_CFG_KAE:
+ if (!guest->kae_device_info.kae_vf_num) {
+ return 0;
+ }
+ args.kae_vf_num= guest->kae_device_info.kae_vf_num;
+ for (int i = 0; i < guest->kae_device_info.kae_vf_num; i++) {
+ args.sec_addr[i] = guest->kae_device_info.sec_addr[i];
+ args.hpre_addr[i] = guest->kae_device_info.hpre_addr[i];
+ }
+ cfg_str = "KAE";
+ break;
default:
g_assert_not_reached();
}
@@ -289,6 +308,47 @@ static void tmm_set_measurement_algo(Object *obj, int algo, Error **errp G_GNUC_
guest->measurement_algo = algo;
}
+static void tmm_get_kae_vf_num(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ TmmGuest *guest = TMM_GUEST(obj);
+
+ visit_type_uint32(v, name, &guest->kae_device_info.kae_vf_num, errp);
+}
+
+static void tmm_set_kae_vf_num(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ TmmGuest *guest = TMM_GUEST(obj);
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ if (value > KVM_ARM_TMM_MAX_KAE_VF_NUM) {
+ error_setg(errp, "invalid number of kae vfs");
+ return;
+ }
+
+ guest->kae_device_info.kae_vf_num = value;
+}
+
+int tmm_get_kae_num(void)
+{
+ return tmm_guest->kae_device_info.kae_vf_num;
+}
+
+void tmm_set_sec_addr(hwaddr base, int num)
+{
+ tmm_guest->kae_device_info.sec_addr[num] = base;
+}
+
+void tmm_set_hpre_addr(hwaddr base, int num)
+{
+ tmm_guest->kae_device_info.hpre_addr[num] = base;
+}
+
static void tmm_guest_class_init(ObjectClass *oc, void *data)
{
object_class_property_add_enum(oc, "measurement-algo",
@@ -314,6 +374,10 @@ static void tmm_guest_class_init(ObjectClass *oc, void *data)
NULL, NULL);
object_class_property_set_description(oc, "num-pmu-counters",
"Number of PMU counters");
+ object_class_property_add(oc, "kae", "uint32", tmm_get_kae_vf_num,
+ tmm_set_kae_vf_num, NULL, NULL);
+ object_class_property_set_description(oc, "kae",
+ "Number of KAE virtual functions. 0 disables KAE (the default)");
}
static void tmm_guest_instance_init(Object *obj)
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index d6c7139f4a..31457a57f7 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -390,6 +390,10 @@ int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level);
void tmm_add_ram_region(hwaddr base1, hwaddr len1, hwaddr base2, hwaddr len2, bool populate);
+int tmm_get_kae_num(void);
+void tmm_set_sec_addr(hwaddr base, int num);
+void tmm_set_hpre_addr(hwaddr base, int num);
+
int kvm_arm_tmm_init(ConfidentialGuestSupport *cgs, Error **errp);
bool kvm_arm_tmm_enabled(void);
--
2.41.0.windows.1

View File

@ -0,0 +1,61 @@
From d490ccc1254c7d4dbe8ab40dd78e189108155ae0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BC=A0=E6=A5=9A=E5=90=9B?=
<zhangchujun@cmss.chinamobile.com>
Date: Fri, 18 Oct 2024 10:10:17 +0800
Subject: [PATCH] dma: Fix function names in documentation Ensure the function
names match.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-id: 20241012-dma-v2-1-6afddf5f3c8d@daynix.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Zhang Chujun <zhangchujun@cmss.chinamoile.com>
---
include/sysemu/dma.h | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h
index a1ac5bc1b5..5a49a30628 100644
--- a/include/sysemu/dma.h
+++ b/include/sysemu/dma.h
@@ -152,7 +152,7 @@ static inline MemTxResult dma_memory_read(AddressSpace *as, dma_addr_t addr,
}
/**
- * address_space_write: Write to address space from DMA controller.
+ * dma_memory_write: Write to address space from DMA controller.
*
* Return a MemTxResult indicating whether the operation succeeded
* or failed (eg unassigned memory, device rejected the transaction,
@@ -189,7 +189,7 @@ MemTxResult dma_memory_set(AddressSpace *as, dma_addr_t addr,
uint8_t c, dma_addr_t len, MemTxAttrs attrs);
/**
- * address_space_map: Map a physical memory region into a host virtual address.
+ * dma_memory_map: Map a physical memory region into a host virtual address.
*
* May map a subset of the requested range, given by and returned in @plen.
* May return %NULL and set *@plen to zero(0), if resources needed to perform
@@ -216,16 +216,15 @@ static inline void *dma_memory_map(AddressSpace *as,
}
/**
- * address_space_unmap: Unmaps a memory region previously mapped
- * by dma_memory_map()
+ * dma_memory_unmap: Unmaps a memory region previously mapped by dma_memory_map()
*
* Will also mark the memory as dirty if @dir == %DMA_DIRECTION_FROM_DEVICE.
* @access_len gives the amount of memory that was actually read or written
* by the caller.
*
* @as: #AddressSpace used
- * @buffer: host pointer as returned by address_space_map()
- * @len: buffer length as returned by address_space_map()
+ * @buffer: host pointer as returned by dma_memory_map()
+ * @len: buffer length as returned by dma_memory_map()
* @dir: indicates the transfer direction
* @access_len: amount of data actually transferred
*/
--
2.41.0.windows.1

View File

@ -0,0 +1,52 @@
From e16c3aa63a203e376a40404314252a11e85a5bda Mon Sep 17 00:00:00 2001
From: Peter Maydell <peter.maydell@linaro.org>
Date: Mon, 29 Jul 2024 13:05:33 +0100
Subject: [PATCH] docs/sphinx/depfile.py: Handle env.doc2path() returning a
Path not a str
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In newer versions of Sphinx the env.doc2path() API is going to change
to return a Path object rather than a str. This was originally visible
in Sphinx 8.0.0rc1, but has been rolled back for the final 8.0.0
release. However it will probably emit a deprecation warning and is
likely to change for good in 9.0:
https://github.com/sphinx-doc/sphinx/issues/12686
Our use in depfile.py assumes a str, and if it is passed a Path
it will fall over:
Handler <function write_depfile at 0x77a1775ff560> for event 'build-finished' threw an exception (exception: unsupported operand type(s) for +: 'PosixPath' and 'str')
Wrapping the env.doc2path() call in str() will coerce a Path object
to the str we expect, and have no effect in older Sphinx versions
that do return a str.
Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2458
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20240729120533.2486427-1-peter.maydell@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 48e5b5f994bccf161dd88a67fdd819d4bfb400f1)
Signed-off-by: zhujun2 <zhujun2_yewu@cmss.chinamobile.com>
---
docs/sphinx/depfile.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/sphinx/depfile.py b/docs/sphinx/depfile.py
index afdcbcec6e..e74be6af98 100644
--- a/docs/sphinx/depfile.py
+++ b/docs/sphinx/depfile.py
@@ -19,7 +19,7 @@
def get_infiles(env):
for x in env.found_docs:
- yield env.doc2path(x)
+ yield str(env.doc2path(x))
yield from ((os.path.join(env.srcdir, dep)
for dep in env.dependencies[x]))
for mod in sys.modules.values():
--
2.41.0.windows.1

View File

@ -0,0 +1,31 @@
From ac7182ca1b9ed7dbb524da734a9f426b2ca07503 Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
Date: Mon, 21 Oct 2024 09:48:30 +0800
Subject: [PATCH] docs/tools/qemu-img.rst: fix typo (sumarizes)
cheery-pick from 8a8be21dde814e7cef43acac8140a7ccd0c4f6fb
Signed-off-by: Samuel Tardieu <sam@rfc1149.net>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
docs/tools/qemu-img.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 4459c065f1..3653adb963 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -406,7 +406,7 @@ Command description:
Compare exits with ``0`` in case the images are equal and with ``1``
in case the images differ. Other exit codes mean an error occurred during
execution and standard error output should contain an error message.
- The following table sumarizes all exit codes of the compare subcommand:
+ The following table summarizes all exit codes of the compare subcommand:
0
Images are identical (or requested help was printed)
--
2.41.0.windows.1

View File

@ -0,0 +1,47 @@
From edf3b2b0a9b9aa992592951a979d1b4642026fe5 Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
Date: Fri, 18 Oct 2024 09:12:50 +0800
Subject: [PATCH] edu: fix DMA range upper bound check
cheery-pick from 2c5107e1b455d4a157124f021826ead4e04b4aea
The edu_check_range function checks that start <= end1 < end2, where
end1 is the upper bound (exclusive) of the guest-supplied DMA range and
end2 is the upper bound (exclusive) of the device's allowed DMA range.
When the guest tries to transfer exactly DMA_SIZE (4096) bytes, end1
will be equal to end2, so the check fails and QEMU aborts with this
puzzling error message (newlines added for formatting):
qemu: hardware error: EDU: DMA range
0x0000000000040000-0x0000000000040fff out of bounds
(0x0000000000040000-0x0000000000040fff)!
By checking end1 <= end2 instead, guests will be allowed to transfer
exactly 4096 bytes. It is not necessary to explicitly check for
start <= end1 because the previous two checks (within(addr, start, end2)
and end1 > addr) imply start < end1.
Fixes: b30934cb52a7 ("hw: misc, add educational driver", 2015-01-21)
Signed-off-by: Max Erenberg <merenber@uwaterloo.ca>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
hw/misc/edu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/misc/edu.c b/hw/misc/edu.c
index a1f8bc77e7..e64a246d3f 100644
--- a/hw/misc/edu.c
+++ b/hw/misc/edu.c
@@ -115,7 +115,7 @@ static void edu_check_range(uint64_t addr, uint64_t size1, uint64_t start,
uint64_t end2 = start + size2;
if (within(addr, start, end2) &&
- end1 > addr && within(end1, start, end2)) {
+ end1 > addr && end1 <= end2) {
return;
}
--
2.41.0.windows.1

View File

@ -0,0 +1,39 @@
From 9a12c439cb9d1e59175be4b96adf0732dca39db3 Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
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é <philmd@linaro.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20241003234211.53644-3-philmd@linaro.org>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,27 @@
From 0826efefea34a6fb6e17502f3a293572f109a261 Mon Sep 17 00:00:00 2001
From: Xianglai Li <lixianglai@loongson.cn>
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 <lixianglai@loongson.cn>
---
hw/intc/loongarch_ipi.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
index e228669aa5..630bcb14ea 100644
--- a/hw/intc/loongarch_ipi.c
+++ b/hw/intc/loongarch_ipi.c
@@ -15,6 +15,7 @@
#include "exec/address-spaces.h"
#include "hw/loongarch/virt.h"
#include "migration/vmstate.h"
+#include "target/loongarch/cpu.h"
#include "target/loongarch/internals.h"
#include "trace.h"
--
2.39.1

View File

@ -0,0 +1,87 @@
From 7754cf384417295dc74add4e774c506d751671a9 Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Tue, 16 Jul 2024 12:15:02 +0100
Subject: [PATCH 67/78] gdbstub: Add helper function to unregister GDB register
space
Add common function to help unregister the GDB register space. This shall be
done in context to the CPU unrealization.
Note: These are common functions exported to arch specific code. For example,
for ARM this code is being referred in associated arch specific patch-set:
Link: https://lore.kernel.org/qemu-devel/20230926103654.34424-1-salil.mehta@huawei.com/
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Tested-by: Vishnu Pajjuri <vishnu@os.amperecomputing.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Tested-by: Xianglai Li <lixianglai@loongson.cn>
Tested-by: Miguel Luis <miguel.luis@oracle.com>
Reviewed-by: Shaoqin Huang <shahuang@redhat.com>
Reviewed-by: Vishnu Pajjuri <vishnu@os.amperecomputing.com>
Tested-by: Zhao Liu <zhao1.liu@intel.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20240716111502.202344-8-salil.mehta@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
gdbstub/gdbstub.c | 7 +++++++
hw/core/cpu-common.c | 4 ++++
include/exec/gdbstub.h | 5 +++++
3 files changed, 16 insertions(+)
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index f16006d2a8..31c3dae525 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -584,8 +584,15 @@ void gdb_register_coprocessor(CPUState *cpu,
void gdb_unregister_coprocessor_all(CPUState *cpu)
{
+ /*
+ * Safe to nuke everything. GDBRegisterState::xml is static const char so
+ * it won't be freed
+ */
g_array_free(cpu->gdb_regs, true);
+
cpu->gdb_regs = NULL;
+ cpu->gdb_num_regs = 0;
+ cpu->gdb_num_g_regs = 0;
}
static void gdb_process_breakpoint_remove_all(GDBProcess *p)
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 82dae51a55..e36ca2c207 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -262,6 +262,10 @@ static void cpu_common_finalize(Object *obj)
{
CPUState *cpu = CPU(obj);
+ /* If cleanup didn't happen in context to gdb_unregister_coprocessor_all */
+ if (cpu->gdb_regs) {
+ g_array_free(cpu->gdb_regs, TRUE);
+ }
qemu_lockcnt_destroy(&cpu->in_ioctl_lock);
qemu_mutex_destroy(&cpu->work_mutex);
}
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index d123b838c2..e2e8dff051 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -39,6 +39,11 @@ typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
void gdb_register_coprocessor(CPUState *cpu,
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
int num_regs, const char *xml, int g_pos);
+
+/**
+ * gdb_unregister_coprocessor_all() - unregisters supplemental set of registers
+ * @cpu - the CPU associated with registers
+ */
void gdb_unregister_coprocessor_all(CPUState *cpu);
/**
--
2.39.1

View File

@ -0,0 +1,211 @@
From ab7c657e05f896600c310c74e7584fc345ff235c Mon Sep 17 00:00:00 2001
From: Zenghui Yu <zenghui.yu@linux.dev>
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 <zenghui.yu@linux.dev>
Reviewed-by: Alexander Graf <agraf@csgraf.de>
Message-id: 20240503153453.54389-1-zenghui.yu@linux.dev
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 19ed42e8adc87a3c739f61608b66a046bb9237e2)
Signed-off-by: zhujun2 <zhujun2_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,49 @@
From a8416845f721aa5ba03446b3ccf83b096b7a0d77 Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Tue, 16 Jul 2024 12:14:57 +0100
Subject: [PATCH 63/78] hw/acpi: Move CPU ctrl-dev MMIO region len macro to
common header file
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
CPU ctrl-dev MMIO region length could be used in ACPI GED and various other
architecture specific places. Move ACPI_CPU_HOTPLUG_REG_LEN macro to more
appropriate common header file.
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Shaoqin Huang <shahuang@redhat.com>
Tested-by: Vishnu Pajjuri <vishnu@os.amperecomputing.com>
Tested-by: Xianglai Li <lixianglai@loongson.cn>
Tested-by: Miguel Luis <miguel.luis@oracle.com>
Tested-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20240716111502.202344-3-salil.mehta@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
include/hw/acpi/cpu.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h
index fced952152..fa5b5e5f01 100644
--- a/include/hw/acpi/cpu.h
+++ b/include/hw/acpi/cpu.h
@@ -18,6 +18,8 @@
#include "hw/boards.h"
#include "hw/hotplug.h"
+#define ACPI_CPU_HOTPLUG_REG_LEN 12
+
typedef struct AcpiCpuStatus {
CPUState *cpu;
uint64_t arch_id;
--
2.39.1

View File

@ -0,0 +1,128 @@
From ac96f216155002d0c874ff88e301e83495093085 Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Tue, 16 Jul 2024 12:14:58 +0100
Subject: [PATCH 64/78] hw/acpi: Update ACPI GED framework to support vCPU
Hotplug
ACPI GED (as described in the ACPI 6.4 spec) uses an interrupt listed in the
_CRS object of GED to intimate OSPM about an event. Later then demultiplexes the
notified event by evaluating ACPI _EVT method to know the type of event. Use
ACPI GED to also notify the guest kernel about any CPU hot(un)plug events.
Note, GED interface is used by many hotplug events like memory hotplug, NVDIMM
hotplug and non-hotplug events like system power down event. Each of these can
be selected using a bit in the 32 bit GED IO interface. A bit has been reserved
for the CPU hotplug event.
ACPI CPU hotplug related initialization should only happen if ACPI_CPU_HOTPLUG
support has been enabled for particular architecture. Add cpu_hotplug_hw_init()
stub to avoid compilation break.
Co-developed-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Shaoqin Huang <shahuang@redhat.com>
Tested-by: Vishnu Pajjuri <vishnu@os.amperecomputing.com>
Tested-by: Xianglai Li <lixianglai@loongson.cn>
Tested-by: Miguel Luis <miguel.luis@oracle.com>
Reviewed-by: Vishnu Pajjuri <vishnu@os.amperecomputing.com>
Tested-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Message-Id: <20240716111502.202344-4-salil.mehta@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
docs/specs/acpi_hw_reduced_hotplug.rst | 3 ++-
hw/acpi/generic_event_device.c | 37 ++++++++++++++++++++++++++
include/hw/acpi/generic_event_device.h | 1 +
3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst
index 0bd3f9399f..3acd6fcd8b 100644
--- a/docs/specs/acpi_hw_reduced_hotplug.rst
+++ b/docs/specs/acpi_hw_reduced_hotplug.rst
@@ -64,7 +64,8 @@ GED IO interface (4 byte access)
0: Memory hotplug event
1: System power down event
2: NVDIMM hotplug event
- 3-31: Reserved
+ 3: CPU hotplug event
+ 4-31: Reserved
**write_access:**
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 2ce7031f1a..755653dc26 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -397,6 +397,42 @@ static const VMStateDescription vmstate_acpi_ged = {
}
};
+static void acpi_ged_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ AcpiGedState *s = ACPI_GED(dev);
+ uint32_t ged_events;
+ int i;
+
+ ged_events = ctpop32(s->ged_event_bitmap);
+
+ for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
+ uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
+
+ if (!event) {
+ continue;
+ }
+
+ switch (event) {
+ case ACPI_GED_CPU_HOTPLUG_EVT:
+ /* initialize CPU Hotplug related regions */
+ memory_region_init(&s->container_cpuhp, OBJECT(dev),
+ "cpuhp container",
+ ACPI_CPU_HOTPLUG_REG_LEN);
+ sysbus_init_mmio(sbd, &s->container_cpuhp);
+ cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev),
+ &s->cpuhp_state, 0);
+ break;
+ }
+ ged_events--;
+ }
+
+ if (ged_events) {
+ error_report("Unsupported events specified");
+ abort();
+ }
+}
+
static void acpi_ged_initfn(Object *obj)
{
DeviceState *dev = DEVICE(obj);
@@ -447,6 +483,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data)
dc->desc = "ACPI Generic Event Device";
device_class_set_props(dc, acpi_ged_properties);
dc->vmsd = &vmstate_acpi_ged;
+ dc->realize = acpi_ged_realize;
hc->plug = acpi_ged_device_plug_cb;
hc->unplug_request = acpi_ged_unplug_request_cb;
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index 8ed9534c57..d1df3c12e5 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -63,6 +63,7 @@
#include "hw/acpi/cpu_hotplug.h"
#include "hw/acpi/memory_hotplug.h"
#include "hw/acpi/ghes.h"
+#include "hw/acpi/cpu.h"
#include "qom/object.h"
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
--
2.39.1

View File

@ -0,0 +1,54 @@
From 16d44ddb63becd559cc2185549c4b18d26feab60 Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Tue, 16 Jul 2024 12:15:00 +0100
Subject: [PATCH 65/78] hw/acpi: Update CPUs AML with cpu-(ctrl)dev change
CPUs Control device(\\_SB.PCI0) register interface for the x86 arch is IO port
based and existing CPUs AML code assumes _CRS objects would evaluate to a system
resource which describes IO Port address. But on ARM arch CPUs control
device(\\_SB.PRES) register interface is memory-mapped hence _CRS object should
evaluate to system resource which describes memory-mapped base address. Update
build CPUs AML function to accept both IO/MEMORY region spaces and accordingly
update the _CRS object.
Co-developed-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Tested-by: Vishnu Pajjuri <vishnu@os.amperecomputing.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Tested-by: Xianglai Li <lixianglai@loongson.cn>
Tested-by: Miguel Luis <miguel.luis@oracle.com>
Reviewed-by: Shaoqin Huang <shahuang@redhat.com>
Tested-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20240716111502.202344-6-salil.mehta@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/acpi/cpu.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 292e1daca2..5e9093991e 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -392,11 +392,13 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_name_decl("_UID", aml_string("CPU Hotplug resources")));
aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0));
+ assert((rs == AML_SYSTEM_IO) || (rs == AML_SYSTEM_MEMORY));
+
crs = aml_resource_template();
if (rs == AML_SYSTEM_IO) {
aml_append(crs, aml_io(AML_DECODE16, base_addr, base_addr, 1,
ACPI_CPU_HOTPLUG_REG_LEN));
- } else {
+ } else if (rs == AML_SYSTEM_MEMORY) {
aml_append(crs, aml_memory32_fixed(base_addr,
ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE));
}
--
2.39.1

View File

@ -0,0 +1,50 @@
From 322f39889ff60a6fda87d7d95a6f233efb558e8a Mon Sep 17 00:00:00 2001
From: Marco Palumbi <Marco.Palumbi@tii.ae>
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 <Marco.Palumbi@tii.ae>
Message-id: 20240730073123.72992-1-marco@palumbi.it
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 5a558be93ad628e5bed6e0ee062870f49251725c)
Signed-off-by: zhujun2 <zhujun2_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,671 @@
From 6060f8cad07a3d2a49795fef19d585a9d205ecef Mon Sep 17 00:00:00 2001
From: Jia Qingtong <jiaqingtong97@gmail.com>
Date: Tue, 24 Sep 2024 18:24:33 +0800
Subject: [PATCH] hw/arm/virt:Keep Guest L1 cache type consistent with KVM
Linux KVM normalize the cache configuration and expose a
fabricated CLIDR_EL1 value to guest, where L1 cache type
could be unified or seperate instruction cache and data
cache. Let's keep guest L1 cache type consistent with
KVM by checking the guest visable CLIDR_EL1, which can
avoid abnormal issue in guest when it's probing cache
info conbined CLIDR_EL1 with ACPI PPTT and DT.
Signed-off-by: Yanan Wang <wangyanan55@huawei.com>
Signed-off-by: lishusen <lishusen2@huawei.com>
---
hw/acpi/aml-build.c | 165 ++---------------------------------
hw/arm/virt-acpi-build.c | 167 ++++++++++++++++++++++++++++++++++++
hw/arm/virt.c | 86 +++++++++++++++----
include/hw/acpi/aml-build.h | 54 ++----------
include/hw/arm/virt.h | 60 +++++++++++++
5 files changed, 306 insertions(+), 226 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index bf9c59f544..0d4994bafe 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -47,7 +47,7 @@ static void build_prepend_byte(GArray *array, uint8_t val)
g_array_prepend_val(array, val);
}
-static void build_append_byte(GArray *array, uint8_t val)
+void build_append_byte(GArray *array, uint8_t val)
{
g_array_append_val(array, val);
}
@@ -1990,10 +1990,10 @@ void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms,
* ACPI spec, Revision 6.3
* 5.2.29.1 Processor hierarchy node structure (Type 0)
*/
-static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags,
- uint32_t parent, uint32_t id,
- uint32_t *priv_rsrc,
- uint32_t priv_num)
+void build_processor_hierarchy_node(GArray *tbl, uint32_t flags,
+ uint32_t parent, uint32_t id,
+ uint32_t *priv_rsrc,
+ uint32_t priv_num)
{
int i;
@@ -2016,161 +2016,6 @@ static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags,
}
}
-/*
- * ACPI spec, Revision 6.3
- * 5.2.29.2 Cache Type Structure (Type 1)
- */
-static void build_cache_hierarchy_node(GArray *tbl, uint32_t next_level,
- uint32_t cache_type)
-{
- build_append_byte(tbl, 1);
- build_append_byte(tbl, 24);
- build_append_int_noprefix(tbl, 0, 2);
- build_append_int_noprefix(tbl, 127, 4);
- build_append_int_noprefix(tbl, next_level, 4);
-
- switch (cache_type) {
- case ARM_L1D_CACHE: /* L1 dcache info */
- build_append_int_noprefix(tbl, ARM_L1DCACHE_SIZE, 4);
- build_append_int_noprefix(tbl, ARM_L1DCACHE_SETS, 4);
- build_append_byte(tbl, ARM_L1DCACHE_ASSOCIATIVITY);
- build_append_byte(tbl, ARM_L1DCACHE_ATTRIBUTES);
- build_append_int_noprefix(tbl, ARM_L1DCACHE_LINE_SIZE, 2);
- break;
- case ARM_L1I_CACHE: /* L1 icache info */
- build_append_int_noprefix(tbl, ARM_L1ICACHE_SIZE, 4);
- build_append_int_noprefix(tbl, ARM_L1ICACHE_SETS, 4);
- build_append_byte(tbl, ARM_L1ICACHE_ASSOCIATIVITY);
- build_append_byte(tbl, ARM_L1ICACHE_ATTRIBUTES);
- build_append_int_noprefix(tbl, ARM_L1ICACHE_LINE_SIZE, 2);
- break;
- case ARM_L2_CACHE: /* L2 cache info */
- build_append_int_noprefix(tbl, ARM_L2CACHE_SIZE, 4);
- build_append_int_noprefix(tbl, ARM_L2CACHE_SETS, 4);
- build_append_byte(tbl, ARM_L2CACHE_ASSOCIATIVITY);
- build_append_byte(tbl, ARM_L2CACHE_ATTRIBUTES);
- build_append_int_noprefix(tbl, ARM_L2CACHE_LINE_SIZE, 2);
- break;
- case ARM_L3_CACHE: /* L3 cache info */
- build_append_int_noprefix(tbl, ARM_L3CACHE_SIZE, 4);
- build_append_int_noprefix(tbl, ARM_L3CACHE_SETS, 4);
- build_append_byte(tbl, ARM_L3CACHE_ASSOCIATIVITY);
- build_append_byte(tbl, ARM_L3CACHE_ATTRIBUTES);
- build_append_int_noprefix(tbl, ARM_L3CACHE_LINE_SIZE, 2);
- break;
- default:
- build_append_int_noprefix(tbl, 0, 4);
- build_append_int_noprefix(tbl, 0, 4);
- build_append_byte(tbl, 0);
- build_append_byte(tbl, 0);
- build_append_int_noprefix(tbl, 0, 2);
- }
-}
-
-/*
- * ACPI spec, Revision 6.3
- * 5.2.29 Processor Properties Topology Table (PPTT)
- */
-void build_pptt_arm(GArray *table_data, BIOSLinker *linker, MachineState *ms,
- const char *oem_id, const char *oem_table_id)
-{
- MachineClass *mc = MACHINE_GET_CLASS(ms);
- GQueue *list = g_queue_new();
- guint pptt_start = table_data->len;
- guint parent_offset;
- guint length, i;
- int uid = 0;
- int socket;
- AcpiTable table = { .sig = "PPTT", .rev = 2,
- .oem_id = oem_id, .oem_table_id = oem_table_id };
-
- acpi_table_begin(&table, table_data);
-
- for (socket = 0; socket < ms->smp.sockets; socket++) {
- uint32_t l3_cache_offset = table_data->len - pptt_start;
- build_cache_hierarchy_node(table_data, 0, ARM_L3_CACHE);
-
- g_queue_push_tail(list,
- GUINT_TO_POINTER(table_data->len - pptt_start));
- build_processor_hierarchy_node(
- table_data,
- /*
- * Physical package - represents the boundary
- * of a physical package
- */
- (1 << 0),
- 0, socket, &l3_cache_offset, 1);
- }
-
- if (mc->smp_props.clusters_supported) {
- length = g_queue_get_length(list);
- for (i = 0; i < length; i++) {
- int cluster;
-
- parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list));
- for (cluster = 0; cluster < ms->smp.clusters; cluster++) {
- g_queue_push_tail(list,
- GUINT_TO_POINTER(table_data->len - pptt_start));
- build_processor_hierarchy_node(
- table_data,
- (0 << 0), /* not a physical package */
- parent_offset, cluster, NULL, 0);
- }
- }
- }
-
- length = g_queue_get_length(list);
- for (i = 0; i < length; i++) {
- int core;
-
- parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list));
- for (core = 0; core < ms->smp.cores; core++) {
- uint32_t priv_rsrc[3] = {};
- priv_rsrc[0] = table_data->len - pptt_start; /* L2 cache offset */
- build_cache_hierarchy_node(table_data, 0, ARM_L2_CACHE);
-
- priv_rsrc[1] = table_data->len - pptt_start; /* L1 dcache offset */
- build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1D_CACHE);
-
- priv_rsrc[2] = table_data->len - pptt_start; /* L1 icache offset */
- build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1I_CACHE);
-
- if (ms->smp.threads > 1) {
- g_queue_push_tail(list,
- GUINT_TO_POINTER(table_data->len - pptt_start));
- build_processor_hierarchy_node(
- table_data,
- (0 << 0), /* not a physical package */
- parent_offset, core, priv_rsrc, 3);
- } else {
- build_processor_hierarchy_node(
- table_data,
- (1 << 1) | /* ACPI Processor ID valid */
- (1 << 3), /* Node is a Leaf */
- parent_offset, uid++, priv_rsrc, 3);
- }
- }
- }
-
- length = g_queue_get_length(list);
- for (i = 0; i < length; i++) {
- int thread;
-
- parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list));
- for (thread = 0; thread < ms->smp.threads; thread++) {
- build_processor_hierarchy_node(
- table_data,
- (1 << 1) | /* ACPI Processor ID valid */
- (1 << 2) | /* Processor is a Thread */
- (1 << 3), /* Node is a Leaf */
- parent_offset, uid++, NULL, 0);
- }
- }
-
- g_queue_free(list);
- acpi_table_end(linker, &table);
-}
-
/*
* ACPI spec, Revision 6.3
* 5.2.29 Processor Properties Topology Table (PPTT)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 179600d4fe..86984b7167 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -63,6 +63,173 @@
#define ACPI_BUILD_TABLE_SIZE 0x20000
+/*
+ * ACPI spec, Revision 6.3
+ * 5.2.29.2 Cache Type Structure (Type 1)
+ */
+static void build_cache_hierarchy_node(GArray *tbl, uint32_t next_level,
+ uint32_t cache_type)
+{
+ build_append_byte(tbl, 1);
+ build_append_byte(tbl, 24);
+ build_append_int_noprefix(tbl, 0, 2);
+ build_append_int_noprefix(tbl, 127, 4);
+ build_append_int_noprefix(tbl, next_level, 4);
+
+ switch (cache_type) {
+ case ARM_L1D_CACHE: /* L1 dcache info */
+ build_append_int_noprefix(tbl, ARM_L1DCACHE_SIZE, 4);
+ build_append_int_noprefix(tbl, ARM_L1DCACHE_SETS, 4);
+ build_append_byte(tbl, ARM_L1DCACHE_ASSOCIATIVITY);
+ build_append_byte(tbl, ARM_L1DCACHE_ATTRIBUTES);
+ build_append_int_noprefix(tbl, ARM_L1DCACHE_LINE_SIZE, 2);
+ break;
+ case ARM_L1I_CACHE: /* L1 icache info */
+ build_append_int_noprefix(tbl, ARM_L1ICACHE_SIZE, 4);
+ build_append_int_noprefix(tbl, ARM_L1ICACHE_SETS, 4);
+ build_append_byte(tbl, ARM_L1ICACHE_ASSOCIATIVITY);
+ build_append_byte(tbl, ARM_L1ICACHE_ATTRIBUTES);
+ build_append_int_noprefix(tbl, ARM_L1ICACHE_LINE_SIZE, 2);
+ break;
+ case ARM_L1_CACHE: /* L1 cache info */
+ build_append_int_noprefix(tbl, ARM_L1CACHE_SIZE, 4);
+ build_append_int_noprefix(tbl, ARM_L1CACHE_SETS, 4);
+ build_append_byte(tbl, ARM_L1CACHE_ASSOCIATIVITY);
+ build_append_byte(tbl, ARM_L1CACHE_ATTRIBUTES);
+ build_append_int_noprefix(tbl, ARM_L1CACHE_LINE_SIZE, 2);
+ break;
+ case ARM_L2_CACHE: /* L2 cache info */
+ build_append_int_noprefix(tbl, ARM_L2CACHE_SIZE, 4);
+ build_append_int_noprefix(tbl, ARM_L2CACHE_SETS, 4);
+ build_append_byte(tbl, ARM_L2CACHE_ASSOCIATIVITY);
+ build_append_byte(tbl, ARM_L2CACHE_ATTRIBUTES);
+ build_append_int_noprefix(tbl, ARM_L2CACHE_LINE_SIZE, 2);
+ break;
+ case ARM_L3_CACHE: /* L3 cache info */
+ build_append_int_noprefix(tbl, ARM_L3CACHE_SIZE, 4);
+ build_append_int_noprefix(tbl, ARM_L3CACHE_SETS, 4);
+ build_append_byte(tbl, ARM_L3CACHE_ASSOCIATIVITY);
+ build_append_byte(tbl, ARM_L3CACHE_ATTRIBUTES);
+ build_append_int_noprefix(tbl, ARM_L3CACHE_LINE_SIZE, 2);
+ break;
+ default:
+ build_append_int_noprefix(tbl, 0, 4);
+ build_append_int_noprefix(tbl, 0, 4);
+ build_append_byte(tbl, 0);
+ build_append_byte(tbl, 0);
+ build_append_int_noprefix(tbl, 0, 2);
+ }
+}
+
+/*
+ * ACPI spec, Revision 6.3
+ * 5.2.29 Processor Properties Topology Table (PPTT)
+ */
+static void build_pptt_arm(GArray *table_data, BIOSLinker *linker, MachineState *ms,
+ const char *oem_id, const char *oem_table_id)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ GQueue *list = g_queue_new();
+ guint pptt_start = table_data->len;
+ guint parent_offset;
+ guint length, i;
+ int uid = 0;
+ int socket;
+ AcpiTable table = { .sig = "PPTT", .rev = 2,
+ .oem_id = oem_id, .oem_table_id = oem_table_id };
+ bool unified_l1 = cpu_l1_cache_unified(0);
+
+ acpi_table_begin(&table, table_data);
+
+ for (socket = 0; socket < ms->smp.sockets; socket++) {
+ uint32_t l3_cache_offset = table_data->len - pptt_start;
+ build_cache_hierarchy_node(table_data, 0, ARM_L3_CACHE);
+
+ g_queue_push_tail(list,
+ GUINT_TO_POINTER(table_data->len - pptt_start));
+ build_processor_hierarchy_node(
+ table_data,
+ /*
+ * Physical package - represents the boundary
+ * of a physical package
+ */
+ (1 << 0),
+ 0, socket, &l3_cache_offset, 1);
+ }
+
+ if (mc->smp_props.clusters_supported) {
+ length = g_queue_get_length(list);
+ for (i = 0; i < length; i++) {
+ int cluster;
+
+ parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list));
+ for (cluster = 0; cluster < ms->smp.clusters; cluster++) {
+ g_queue_push_tail(list,
+ GUINT_TO_POINTER(table_data->len - pptt_start));
+ build_processor_hierarchy_node(
+ table_data,
+ (0 << 0), /* not a physical package */
+ parent_offset, cluster, NULL, 0);
+ }
+ }
+ }
+
+ length = g_queue_get_length(list);
+ for (i = 0; i < length; i++) {
+ int core;
+
+ parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list));
+ for (core = 0; core < ms->smp.cores; core++) {
+ uint32_t priv_rsrc[3] = {};
+ priv_rsrc[0] = table_data->len - pptt_start; /* L2 cache offset */
+ build_cache_hierarchy_node(table_data, 0, ARM_L2_CACHE);
+
+ if (unified_l1) {
+ priv_rsrc[1] = table_data->len - pptt_start; /* L1 cache offset */
+ build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1_CACHE);
+ } else {
+ priv_rsrc[1] = table_data->len - pptt_start; /* L1 dcache offset */
+ build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1D_CACHE);
+ priv_rsrc[2] = table_data->len - pptt_start; /* L1 icache offset */
+ build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1I_CACHE);
+ }
+
+ if (ms->smp.threads > 1) {
+ g_queue_push_tail(list,
+ GUINT_TO_POINTER(table_data->len - pptt_start));
+ build_processor_hierarchy_node(
+ table_data,
+ (0 << 0), /* not a physical package */
+ parent_offset, core, priv_rsrc, 3);
+ } else {
+ build_processor_hierarchy_node(
+ table_data,
+ (1 << 1) | /* ACPI Processor ID valid */
+ (1 << 3), /* Node is a Leaf */
+ parent_offset, uid++, priv_rsrc, 3);
+ }
+ }
+ }
+
+ length = g_queue_get_length(list);
+ for (i = 0; i < length; i++) {
+ int thread;
+
+ parent_offset = GPOINTER_TO_UINT(g_queue_pop_head(list));
+ for (thread = 0; thread < ms->smp.threads; thread++) {
+ build_processor_hierarchy_node(
+ table_data,
+ (1 << 1) | /* ACPI Processor ID valid */
+ (1 << 2) | /* Processor is a Thread */
+ (1 << 3), /* Node is a Leaf */
+ parent_offset, uid++, NULL, 0);
+ }
+ }
+
+ g_queue_free(list);
+ acpi_table_end(linker, &table);
+}
+
static void acpi_dsdt_add_psd(Aml *dev, int cpus)
{
Aml *pkg;
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e31c289968..a9efcec85e 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -401,6 +401,39 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms)
INTID_TO_PPI(ARCH_TIMER_NS_EL2_IRQ), irqflags);
}
+/*
+ * In CLIDR_EL1 exposed to guest by the hypervisor, L1 cache type
+ * maybe unified or seperate ins and data. We need to read the
+ * guest visable CLIDR_EL1 and check L1 cache type.
+ */
+bool cpu_l1_cache_unified(int cpu)
+{
+ bool unified = false;
+ uint64_t clidr;
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
+ CPUState *cs = CPU(armcpu);
+ int ret;
+
+ if (kvm_enabled()) {
+ struct kvm_one_reg reg = {
+ .id = ARM64_REG_CLIDR_EL1,
+ .addr = (uintptr_t)&clidr
+ };
+
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (ret) {
+ error_setg(&error_fatal, "Get vCPU clidr from KVM failed:%d", ret);
+ return unified;
+ }
+
+ if (CLIDR_CTYPE(clidr, 1) == CTYPE_UNIFIED) {
+ unified = true;
+ }
+ }
+
+ return unified;
+}
+
static void fdt_add_l3cache_nodes(const VirtMachineState *vms)
{
int i;
@@ -415,9 +448,10 @@ static void fdt_add_l3cache_nodes(const VirtMachineState *vms)
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cache");
qemu_fdt_setprop_string(ms->fdt, nodename, "cache-unified", "true");
qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-level", 3);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", 0x2000000);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size", 128);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", 2048);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", ARM_L3CACHE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size",
+ ARM_L3CACHE_LINE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", ARM_L3CACHE_SETS);
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
qemu_fdt_alloc_phandle(ms->fdt));
g_free(nodename);
@@ -436,10 +470,12 @@ static void fdt_add_l2cache_nodes(const VirtMachineState *vms)
char *nodename = g_strdup_printf("/cpus/l2-cache%d", cpu);
qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "cache-unified", "true");
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cache");
- qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", 0x80000);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size", 64);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", 1024);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", ARM_L2CACHE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size",
+ ARM_L2CACHE_LINE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", ARM_L2CACHE_SETS);
qemu_fdt_setprop_phandle(ms->fdt, nodename, "next-level-cache",
next_path);
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
@@ -453,18 +489,32 @@ static void fdt_add_l2cache_nodes(const VirtMachineState *vms)
static void fdt_add_l1cache_prop(const VirtMachineState *vms,
char *nodename, int cpu)
{
- const MachineState *ms = MACHINE(vms);
- char *cachename = g_strdup_printf("/cpus/l2-cache%d", cpu);
-
- qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-size", 0x10000);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-line-size", 64);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-sets", 256);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-size", 0x10000);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-line-size", 64);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-sets", 256);
- qemu_fdt_setprop_phandle(ms->fdt, nodename, "next-level-cache",
- cachename);
- g_free(cachename);
+ const MachineState *ms = MACHINE(vms);
+ char *next_path = g_strdup_printf("/cpus/l2-cache%d", cpu);
+ bool unified_l1 = cpu_l1_cache_unified(0);
+
+ if (unified_l1) {
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", ARM_L1CACHE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size",
+ ARM_L1CACHE_LINE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", ARM_L1CACHE_SETS);
+ } else {
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-size",
+ ARM_L1DCACHE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-line-size",
+ ARM_L1DCACHE_LINE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-sets",
+ ARM_L1DCACHE_SETS);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-size",
+ ARM_L1ICACHE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-line-size",
+ ARM_L1ICACHE_LINE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-sets",
+ ARM_L1ICACHE_SETS);
+ }
+ qemu_fdt_setprop_phandle(ms->fdt, nodename, "next-level-cache", next_path);
+
+ g_free(next_path);
}
static void fdt_add_cpu_nodes(const VirtMachineState *vms)
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 7281c281f6..91f9cbf4f1 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -221,51 +221,6 @@ struct AcpiBuildTables {
BIOSLinker *linker;
} AcpiBuildTables;
-/* Definitions of the hardcoded cache info*/
-
-typedef enum {
- ARM_L1D_CACHE,
- ARM_L1I_CACHE,
- ARM_L2_CACHE,
- ARM_L3_CACHE
-} ArmCacheType;
-
-/* L1 data cache: */
-#define ARM_L1DCACHE_SIZE 65536
-#define ARM_L1DCACHE_SETS 256
-#define ARM_L1DCACHE_ASSOCIATIVITY 4
-#define ARM_L1DCACHE_ATTRIBUTES 2
-#define ARM_L1DCACHE_LINE_SIZE 64
-
-/* L1 instruction cache: */
-#define ARM_L1ICACHE_SIZE 65536
-#define ARM_L1ICACHE_SETS 256
-#define ARM_L1ICACHE_ASSOCIATIVITY 4
-#define ARM_L1ICACHE_ATTRIBUTES 4
-#define ARM_L1ICACHE_LINE_SIZE 64
-
-/* Level 2 unified cache: */
-#define ARM_L2CACHE_SIZE 524288
-#define ARM_L2CACHE_SETS 1024
-#define ARM_L2CACHE_ASSOCIATIVITY 8
-#define ARM_L2CACHE_ATTRIBUTES 10
-#define ARM_L2CACHE_LINE_SIZE 64
-
-/* Level 3 unified cache: */
-#define ARM_L3CACHE_SIZE 33554432
-#define ARM_L3CACHE_SETS 2048
-#define ARM_L3CACHE_ASSOCIATIVITY 15
-#define ARM_L3CACHE_ATTRIBUTES 10
-#define ARM_L3CACHE_LINE_SIZE 128
-
-struct offset_status {
- uint32_t parent;
- uint32_t l2_offset;
- uint32_t l1d_offset;
- uint32_t l1i_offset;
-};
-
-
typedef
struct CrsRangeEntry {
uint64_t base;
@@ -460,6 +415,7 @@ Aml *aml_sizeof(Aml *arg);
Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target);
Aml *aml_object_type(Aml *object);
+void build_append_byte(GArray *array, uint8_t val);
void build_append_int_noprefix(GArray *table, uint64_t value, int size);
typedef struct AcpiTable {
@@ -537,10 +493,12 @@ void build_srat_memory(GArray *table_data, uint64_t base,
void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms,
const char *oem_id, const char *oem_table_id);
-void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
- const char *oem_id, const char *oem_table_id);
+void build_processor_hierarchy_node(GArray *tbl, uint32_t flags,
+ uint32_t parent, uint32_t id,
+ uint32_t *priv_rsrc,
+ uint32_t priv_num);
-void build_pptt_arm(GArray *table_data, BIOSLinker *linker, MachineState *ms,
+void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
const char *oem_id, const char *oem_table_id);
void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 76a0d3fa5b..4b7dc61c24 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -47,6 +47,65 @@
/* See Linux kernel arch/arm64/include/asm/pvclock-abi.h */
#define PVTIME_SIZE_PER_CPU 64
+/* ARM CLIDR_EL1 related definitions */
+/* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */
+#define CTYPE_NONE 0b000
+#define CTYPE_INS 0b001
+#define CTYPE_DATA 0b010
+#define CTYPE_INS_DATA 0b011
+#define CTYPE_UNIFIED 0b100
+
+#define ARM64_REG_CLIDR_EL1 ARM64_SYS_REG(3, 1, 0, 0, 1)
+
+#define CLIDR_CTYPE_SHIFT(level) (3 * (level - 1))
+#define CLIDR_CTYPE_MASK(level) (7 << CLIDR_CTYPE_SHIFT(level))
+#define CLIDR_CTYPE(clidr, level) \
+ (((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level))
+
+/* L1 data cache */
+#define ARM_L1DCACHE_SIZE 65536
+#define ARM_L1DCACHE_SETS 256
+#define ARM_L1DCACHE_ASSOCIATIVITY 4
+#define ARM_L1DCACHE_ATTRIBUTES 2
+#define ARM_L1DCACHE_LINE_SIZE 64
+
+/* L1 instruction cache */
+#define ARM_L1ICACHE_SIZE 65536
+#define ARM_L1ICACHE_SETS 256
+#define ARM_L1ICACHE_ASSOCIATIVITY 4
+#define ARM_L1ICACHE_ATTRIBUTES 4
+#define ARM_L1ICACHE_LINE_SIZE 64
+
+/* L1 unified cache */
+#define ARM_L1CACHE_SIZE 131072
+#define ARM_L1CACHE_SETS 256
+#define ARM_L1CACHE_ASSOCIATIVITY 4
+#define ARM_L1CACHE_ATTRIBUTES 10
+#define ARM_L1CACHE_LINE_SIZE 128
+
+/* L2 unified cache */
+#define ARM_L2CACHE_SIZE 524288
+#define ARM_L2CACHE_SETS 1024
+#define ARM_L2CACHE_ASSOCIATIVITY 8
+#define ARM_L2CACHE_ATTRIBUTES 10
+#define ARM_L2CACHE_LINE_SIZE 64
+
+/* L3 unified cache */
+#define ARM_L3CACHE_SIZE 33554432
+#define ARM_L3CACHE_SETS 2048
+#define ARM_L3CACHE_ASSOCIATIVITY 15
+#define ARM_L3CACHE_ATTRIBUTES 10
+#define ARM_L3CACHE_LINE_SIZE 128
+
+/* Definitions of the hardcoded cache info */
+typedef enum {
+ ARM_L1D_CACHE,
+ ARM_L1I_CACHE,
+ ARM_L1_CACHE,
+ ARM_L2_CACHE,
+ ARM_L3_CACHE
+} ArmCacheType;
+
enum {
VIRT_FLASH,
VIRT_MEM,
@@ -194,6 +253,7 @@ OBJECT_DECLARE_TYPE(VirtMachineState, VirtMachineClass, VIRT_MACHINE)
void virt_acpi_setup(VirtMachineState *vms);
bool virt_is_acpi_enabled(VirtMachineState *vms);
+bool cpu_l1_cache_unified(int cpu);
/* Return number of redistributors that fit in the specified region */
static uint32_t virt_redist_capacity(VirtMachineState *vms, int region)
--
2.41.0.windows.1

View File

@ -0,0 +1,237 @@
From f6b4a18ba78b1daa2a69fccfb768ec2bdcafb1d4 Mon Sep 17 00:00:00 2001
From: Sia Jee Heng <jeeheng.sia@starfivetech.com>
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 <jeeheng.sia@starfivetech.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20240129021440.17640-2-jeeheng.sia@starfivetech.com>
[ Changes by AF:
- Add missing Language SPCR entry
]
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/acpi/aml-build.c | 53 +++++++++++++++++++++++++++++
hw/arm/virt-acpi-build.c | 68 +++++++++++++++----------------------
include/hw/acpi/acpi-defs.h | 33 ++++++++++++++++++
include/hw/acpi/aml-build.h | 4 +++
4 files changed, 117 insertions(+), 41 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 0d4994baf..3fb996c03 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -2016,6 +2016,59 @@ void build_processor_hierarchy_node(GArray *tbl, uint32_t flags,
}
}
+void build_spcr(GArray *table_data, BIOSLinker *linker,
+ const AcpiSpcrData *f, const uint8_t rev,
+ const char *oem_id, const char *oem_table_id)
+{
+ AcpiTable table = { .sig = "SPCR", .rev = rev, .oem_id = oem_id,
+ .oem_table_id = oem_table_id };
+
+ acpi_table_begin(&table, table_data);
+ /* Interface type */
+ build_append_int_noprefix(table_data, f->interface_type, 1);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 3);
+ /* Base Address */
+ build_append_gas(table_data, f->base_addr.id, f->base_addr.width,
+ f->base_addr.offset, f->base_addr.size,
+ f->base_addr.addr);
+ /* Interrupt type */
+ build_append_int_noprefix(table_data, f->interrupt_type, 1);
+ /* IRQ */
+ build_append_int_noprefix(table_data, f->pc_interrupt, 1);
+ /* Global System Interrupt */
+ build_append_int_noprefix(table_data, f->interrupt, 4);
+ /* Baud Rate */
+ build_append_int_noprefix(table_data, f->baud_rate, 1);
+ /* Parity */
+ build_append_int_noprefix(table_data, f->parity, 1);
+ /* Stop Bits */
+ build_append_int_noprefix(table_data, f->stop_bits, 1);
+ /* Flow Control */
+ build_append_int_noprefix(table_data, f->flow_control, 1);
+ /* Language */
+ build_append_int_noprefix(table_data, f->language, 1);
+ /* Terminal Type */
+ build_append_int_noprefix(table_data, f->terminal_type, 1);
+ /* PCI Device ID */
+ build_append_int_noprefix(table_data, f->pci_device_id, 2);
+ /* PCI Vendor ID */
+ build_append_int_noprefix(table_data, f->pci_vendor_id, 2);
+ /* PCI Bus Number */
+ build_append_int_noprefix(table_data, f->pci_bus, 1);
+ /* PCI Device Number */
+ build_append_int_noprefix(table_data, f->pci_device, 1);
+ /* PCI Function Number */
+ build_append_int_noprefix(table_data, f->pci_function, 1);
+ /* PCI Flags */
+ build_append_int_noprefix(table_data, f->pci_flags, 4);
+ /* PCI Segment */
+ build_append_int_noprefix(table_data, f->pci_segment, 1);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+
+ acpi_table_end(linker, &table);
+}
/*
* ACPI spec, Revision 6.3
* 5.2.29 Processor Properties Topology Table (PPTT)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 86984b716..076781423 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -717,48 +717,34 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
* Rev: 1.07
*/
static void
-build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
+spcr_setup(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
- AcpiTable table = { .sig = "SPCR", .rev = 2, .oem_id = vms->oem_id,
- .oem_table_id = vms->oem_table_id };
-
- acpi_table_begin(&table, table_data);
-
- /* Interface Type */
- build_append_int_noprefix(table_data, 3, 1); /* ARM PL011 UART */
- build_append_int_noprefix(table_data, 0, 3); /* Reserved */
- /* Base Address */
- build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 32, 0, 3,
- vms->memmap[VIRT_UART].base);
- /* Interrupt Type */
- build_append_int_noprefix(table_data,
- (1 << 3) /* Bit[3] ARMH GIC interrupt */, 1);
- build_append_int_noprefix(table_data, 0, 1); /* IRQ */
- /* Global System Interrupt */
- build_append_int_noprefix(table_data,
- vms->irqmap[VIRT_UART] + ARM_SPI_BASE, 4);
- build_append_int_noprefix(table_data, 3 /* 9600 */, 1); /* Baud Rate */
- build_append_int_noprefix(table_data, 0 /* No Parity */, 1); /* Parity */
- /* Stop Bits */
- build_append_int_noprefix(table_data, 1 /* 1 Stop bit */, 1);
- /* Flow Control */
- build_append_int_noprefix(table_data,
- (1 << 1) /* RTS/CTS hardware flow control */, 1);
- /* Terminal Type */
- build_append_int_noprefix(table_data, 0 /* VT100 */, 1);
- build_append_int_noprefix(table_data, 0, 1); /* Language */
- /* PCI Device ID */
- build_append_int_noprefix(table_data, 0xffff /* not a PCI device*/, 2);
- /* PCI Vendor ID */
- build_append_int_noprefix(table_data, 0xffff /* not a PCI device*/, 2);
- build_append_int_noprefix(table_data, 0, 1); /* PCI Bus Number */
- build_append_int_noprefix(table_data, 0, 1); /* PCI Device Number */
- build_append_int_noprefix(table_data, 0, 1); /* PCI Function Number */
- build_append_int_noprefix(table_data, 0, 4); /* PCI Flags */
- build_append_int_noprefix(table_data, 0, 1); /* PCI Segment */
- build_append_int_noprefix(table_data, 0, 4); /* Reserved */
+ AcpiSpcrData serial = {
+ .interface_type = 3, /* ARM PL011 UART */
+ .base_addr.id = AML_AS_SYSTEM_MEMORY,
+ .base_addr.width = 32,
+ .base_addr.offset = 0,
+ .base_addr.size = 3,
+ .base_addr.addr = vms->memmap[VIRT_UART].base,
+ .interrupt_type = (1 << 3),/* Bit[3] ARMH GIC interrupt*/
+ .pc_interrupt = 0, /* IRQ */
+ .interrupt = (vms->irqmap[VIRT_UART] + ARM_SPI_BASE),
+ .baud_rate = 3, /* 9600 */
+ .parity = 0, /* No Parity */
+ .stop_bits = 1, /* 1 Stop bit */
+ .flow_control = 1 << 1, /* RTS/CTS hardware flow control */
+ .terminal_type = 0, /* VT100 */
+ .language = 0, /* Language */
+ .pci_device_id = 0xffff, /* not a PCI device*/
+ .pci_vendor_id = 0xffff, /* not a PCI device*/
+ .pci_bus = 0,
+ .pci_device = 0,
+ .pci_function = 0,
+ .pci_flags = 0,
+ .pci_segment = 0,
+ };
- acpi_table_end(linker, &table);
+ build_spcr(table_data, linker, &serial, 2, vms->oem_id, vms->oem_table_id);
}
/*
@@ -1316,7 +1302,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
}
acpi_add_table(table_offsets, tables_blob);
- build_spcr(tables_blob, tables->linker, vms);
+ spcr_setup(tables_blob, tables->linker, vms);
acpi_add_table(table_offsets, tables_blob);
build_dbg2(tables_blob, tables->linker, vms);
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index b1f389fb4..7a8b708cd 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -90,6 +90,39 @@ typedef struct AcpiFadtData {
unsigned *xdsdt_tbl_offset;
} AcpiFadtData;
+typedef struct AcpiGas {
+ uint8_t id; /* Address space ID */
+ uint8_t width; /* Register bit width */
+ uint8_t offset; /* Register bit offset */
+ uint8_t size; /* Access size */
+ uint64_t addr; /* Address */
+} AcpiGas;
+
+/* SPCR (Serial Port Console Redirection table) */
+typedef struct AcpiSpcrData {
+ uint8_t interface_type;
+ uint8_t reserved[3];
+ struct AcpiGas base_addr;
+ uint8_t interrupt_type;
+ uint8_t pc_interrupt;
+ uint32_t interrupt; /* Global system interrupt */
+ uint8_t baud_rate;
+ uint8_t parity;
+ uint8_t stop_bits;
+ uint8_t flow_control;
+ uint8_t terminal_type;
+ uint8_t language;
+ uint8_t reserved1;
+ uint16_t pci_device_id; /* Must be 0xffff if not PCI device */
+ uint16_t pci_vendor_id; /* Must be 0xffff if not PCI device */
+ uint8_t pci_bus;
+ uint8_t pci_device;
+ uint8_t pci_function;
+ uint32_t pci_flags;
+ uint8_t pci_segment;
+ uint32_t reserved2;
+} AcpiSpcrData;
+
#define ACPI_FADT_ARM_PSCI_COMPLIANT (1 << 0)
#define ACPI_FADT_ARM_PSCI_USE_HVC (1 << 1)
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 91f9cbf4f..381ad4a8a 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -506,4 +506,8 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
const char *oem_id, const char *oem_table_id);
+
+void build_spcr(GArray *table_data, BIOSLinker *linker,
+ const AcpiSpcrData *f, const uint8_t rev,
+ const char *oem_id, const char *oem_table_id);
#endif
--
2.43.0

View File

@ -0,0 +1,36 @@
From 28bf94c86d3914b8b517dae483d1d69b3afabacc Mon Sep 17 00:00:00 2001
From: qihao_yewu <qihao_yewu@cmss.chinamobile.com>
Date: Tue, 5 Nov 2024 07:03:48 -0500
Subject: [PATCH] hw/audio/hda: free timer on exit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
cheery-pick from f27206ceedbe2efae37c8d143c5eb2db05251508
Fixes: 280c1e1cd ("audio/hda: create millisecond timers that handle IO")
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-ID: <20241008125028.1177932-2-marcandre.lureau@redhat.com>
Signed-off-by: qihao_yewu <qihao_yewu@cmss.chinamobile.com>
---
hw/audio/hda-codec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 0bc20d49f6..19f401cabe 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -751,7 +751,7 @@ static void hda_audio_exit(HDACodecDevice *hda)
continue;
}
if (a->use_timer) {
- timer_del(st->buft);
+ timer_free(st->buft);
}
if (st->output) {
AUD_close_out(&a->card, st->voice.out);
--
2.41.0.windows.1

View File

@ -0,0 +1,37 @@
From 830009038a73e496598c26679b7e30d7e931a1cf Mon Sep 17 00:00:00 2001
From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Date: Fri, 1 Nov 2024 13:39:16 +0000
Subject: [PATCH] hw/cxl: Ensure there is enough data for the header in
cmd_ccls_set_lsa()
The properties of the requested set command cannot be established if
len_in is less than the size of the header.
Reported-by: Esifiel <esifiel@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Message-Id: <20241101133917.27634-10-Jonathan.Cameron@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Zhongrui Tang <tangzhongrui_yewu@cmss.chinamobile.com>
---
hw/cxl/cxl-mailbox-utils.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 6eff56fb1b..9f2304389b 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -897,8 +897,8 @@ static CXLRetCode cmd_ccls_set_lsa(const struct cxl_cmd *cmd,
const size_t hdr_len = offsetof(struct set_lsa_pl, data);
*len_out = 0;
- if (!len_in) {
- return CXL_MBOX_SUCCESS;
+ if (len_in < hdr_len) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
}
if (set_lsa_payload->offset + len_in > cvc->get_lsa_size(ct3d) + hdr_len) {
--
2.41.0.windows.1

View File

@ -0,0 +1,37 @@
From d96c34e132df55ca7be458095f23d81dfc14e0d5 Mon Sep 17 00:00:00 2001
From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Date: Fri, 1 Nov 2024 13:39:17 +0000
Subject: [PATCH] hw/cxl: Ensure there is enough data to read the input header
in cmd_get_physical_port_state()
If len_in is smaller than the header length then the accessing the
number of ports will result in an out of bounds access.
Add a check to avoid this.
Reported-by: Esifiel <esifiel@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Message-Id: <20241101133917.27634-11-Jonathan.Cameron@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Zhongrui Tang <tangzhongrui_yewu@cmss.chinamobile.com>
---
hw/cxl/cxl-mailbox-utils.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 6eff56fb1b..11a26525a2 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -505,6 +505,9 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
in = (struct cxl_fmapi_get_phys_port_state_req_pl *)payload_in;
out = (struct cxl_fmapi_get_phys_port_state_resp_pl *)payload_out;
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
/* Check if what was requested can fit */
if (sizeof(*out) + sizeof(*out->ports) * in->num_ports > cci->payload_max) {
return CXL_MBOX_INVALID_INPUT;
--
2.41.0.windows.1

View File

@ -0,0 +1,36 @@
From 10794f7a9bc3c88c8a26f094e5d3ef42e9fd290f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BC=A0=E6=A5=9A=E5=90=9B?=
<zhangchujun@cmss.chinamobile.com>
Date: Fri, 11 Oct 2024 14:04:54 +0800
Subject: [PATCH] hw/gpio/aspeed_gpio: Avoid shift into sign bit
In aspeed_gpio_update() we calculate "mask = 1 << gpio", where gpio can be between 0 and 31.
Coverity complains about this beacuse 1 << 31 won't fit in a signed integer.
For QEMU this isn't an error because we enable -fwrapv, but we can keep Coverity happy
by doing the shift on unsigned numbers.
Resolves: Coverity CID 1547742
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Cedric Le Goater <clg@redhat.com>
Signed-off-by: zhangchujun <zhangchujun@cmss.chinamobile.com>
---
hw/gpio/aspeed_gpio.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 1e267dd482..0fc3d4c05f 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -281,7 +281,7 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
diff &= mode_mask;
if (diff) {
for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) {
- uint32_t mask = 1 << gpio;
+ uint32_t mask = 1U << gpio;
/* If the gpio needs to be updated... */
if (!(diff & mask)) {
--
2.41.0.windows.1

View File

@ -0,0 +1,324 @@
From d29bc8738131dcaaa1a1ae2870ea29b59a137f30 Mon Sep 17 00:00:00 2001
From: xiongmengbiao <xiongmengbiao@hygon.cn>
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 <xiongmengbiao@hygon.cn>
---
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

View File

@ -0,0 +1,50 @@
From 1b0d08faf1daaed39809ed1a3516eaa0f7d61534 Mon Sep 17 00:00:00 2001
From: Peter Maydell <peter.maydell@linaro.org>
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 <peter.maydell@linaro.org>
Message-Id: <20240731170019.3590563-1-peter.maydell@linaro.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 9a45b0761628cc59267b3283a85d15294464ac31)
Signed-off-by: zhujun2 <zhujun2_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,61 @@
From 20541823659dc78a6a7be427f8fc03ccc58c88d1 Mon Sep 17 00:00:00 2001
From: Andrey Shumilin <shum.sdl@nppct.ru>
Date: Thu, 23 May 2024 16:06:20 +0100
Subject: [PATCH] hw/intc/arm_gic: Fix handling of NS view of GICC_APR<n>
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<n> 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<n>, GICC_NSAPR<n> registers")
Signed-off-by: Andrey Shumilin <shum.sdl@nppct.ru>
[PMM: Rewrote commit message]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alex Bennée<alex.bennee@linaro.org>
(cherry picked from commit daafa78b297291fea36fb4daeed526705fa7c035)
Signed-off-by: zhujun2 <zhujun2_yewu@cmss.chinamobile.com>
---
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<n> is the top half of GIC_NSAPR<n> */
- *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<n> is the top half of GIC_NSAPR<n> */
- 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

View File

@ -0,0 +1,51 @@
From 15b6c032ed2f92aa3210fe30376119eb468af039 Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
Date: Wed, 23 Oct 2024 14:19:00 +0800
Subject: [PATCH] hw/intc/openpic: Improve errors for out of bounds property
values
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
cheery-pick from 627c1e012cb3f14745f9b7d991642894a4402d5c
The error message doesn't matter much, as the "openpic" device isn't
user-creatable. But it's the last use of
QERR_PROPERTY_VALUE_OUT_OF_RANGE, which has to go. Change the message
just like the previous commit did for x86 CPUs.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-ID: <20241010150144.986655-7-armbru@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
hw/intc/openpic.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index a6f91d4bcd..0f99b77a17 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -41,7 +41,6 @@
#include "hw/pci/msi.h"
#include "qapi/error.h"
#include "qemu/bitops.h"
-#include "qapi/qmp/qerror.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "qemu/error-report.h"
@@ -1535,9 +1534,7 @@ static void openpic_realize(DeviceState *dev, Error **errp)
};
if (opp->nb_cpus > MAX_CPU) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
- TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus,
- (uint64_t)0, (uint64_t)MAX_CPU);
+ error_setg(errp, "property 'nb_cpus' can be at most %d", MAX_CPU);
return;
}
--
2.41.0.windows.1

View File

@ -0,0 +1,400 @@
From 24e4e6742bdc8d804760e84f4e4bde5460e1e024 Mon Sep 17 00:00:00 2001
From: gaosong <gaosong@loongson.cn>
Date: Sun, 8 Sep 2024 09:29:00 +0800
Subject: [PATCH 72/78] hw/loongarch: Add KVM IPI device support
Added ipi interrupt controller for kvm emulation.
The main process is to send the command word for
creating an ipi device to the kernel.
When the VM is saved, the ioctl obtains the ipi
interrupt controller data in the kernel and saves it.
When the VM is recovered, the saved data is sent to the kernel.
Signed-off-by: gaosong <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/intc/Kconfig | 3 +
hw/intc/loongarch_ipi_kvm.c | 207 ++++++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/loongarch/Kconfig | 1 +
hw/loongarch/virt.c | 35 ++++--
include/hw/intc/loongarch_ipi.h | 23 ++++
linux-headers/linux/kvm.h | 2 +
target/loongarch/kvm/kvm.c | 4 +
8 files changed, 263 insertions(+), 13 deletions(-)
create mode 100644 hw/intc/loongarch_ipi_kvm.c
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 97d550b06b..cbba74c22e 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -93,6 +93,9 @@ config NIOS2_VIC
config LOONGARCH_IPI
bool
+config LOONGARCH_IPI_KVM
+ bool
+
config LOONGARCH_PCH_PIC
bool
select UNIMP
diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c
new file mode 100644
index 0000000000..fd308eb0c0
--- /dev/null
+++ b/hw/intc/loongarch_ipi_kvm.c
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch kvm ipi interrupt support
+ *
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "qemu/typedefs.h"
+#include "hw/intc/loongarch_ipi.h"
+#include "hw/sysbus.h"
+#include "linux/kvm.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+
+#define IPI_DEV_FD_UNDEF -1
+
+static void kvm_ipi_access_regs(int fd, uint64_t addr,
+ uint32_t *val, int is_write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_IPI_GRP_REGS,
+ addr, val, is_write, &error_abort);
+}
+
+static int kvm_loongarch_ipi_pre_save(void *opaque)
+{
+ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque;
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi);
+ IPICore *cpu;
+ uint64_t attr;
+ int cpu_id = 0;
+ int fd = ipi_class->dev_fd;
+
+ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) {
+ cpu = &ipi->cpu[cpu_id];
+ attr = (cpu_id << 16) | CORE_STATUS_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->status, false);
+
+ attr = (cpu_id << 16) | CORE_EN_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->en, false);
+
+ attr = (cpu_id << 16) | CORE_SET_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->set, false);
+
+ attr = (cpu_id << 16) | CORE_CLEAR_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->clear, false);
+
+ attr = (cpu_id << 16) | CORE_BUF_20;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], false);
+
+ attr = (cpu_id << 16) | CORE_BUF_28;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], false);
+
+ attr = (cpu_id << 16) | CORE_BUF_30;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], false);
+
+ attr = (cpu_id << 16) | CORE_BUF_38;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], false);
+ }
+
+ return 0;
+}
+
+static int kvm_loongarch_ipi_post_load(void *opaque, int version_id)
+{
+ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque;
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi);
+ IPICore *cpu;
+ uint64_t attr;
+ int cpu_id = 0;
+ int fd = ipi_class->dev_fd;
+
+ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) {
+ cpu = &ipi->cpu[cpu_id];
+ attr = (cpu_id << 16) | CORE_STATUS_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->status, true);
+
+ attr = (cpu_id << 16) | CORE_EN_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->en, true);
+
+ attr = (cpu_id << 16) | CORE_SET_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->set, true);
+
+ attr = (cpu_id << 16) | CORE_CLEAR_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->clear, true);
+
+ attr = (cpu_id << 16) | CORE_BUF_20;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], true);
+
+ attr = (cpu_id << 16) | CORE_BUF_28;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], true);
+
+ attr = (cpu_id << 16) | CORE_BUF_30;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], true);
+
+ attr = (cpu_id << 16) | CORE_BUF_38;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], true);
+ }
+
+ return 0;
+}
+
+static void kvm_loongarch_ipi_realize(DeviceState *dev, Error **errp)
+{
+ KVMLoongArchIPI *ipi = KVM_LOONGARCH_IPI(dev);
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(dev);
+ struct kvm_create_device cd = {0};
+ Error *err = NULL;
+ int ret;
+
+ if (ipi->num_cpu == 0) {
+ error_setg(errp, "num-cpu must be at least 1");
+ return;
+ }
+
+ ipi_class->parent_realize(dev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ ipi->cpu = g_new0(IPICore, ipi->num_cpu);
+ if (ipi->cpu == NULL) {
+ error_setg(errp, "Memory allocation for ExtIOICore faile");
+ return;
+ }
+
+ if (!ipi_class->is_created) {
+ cd.type = KVM_DEV_TYPE_LA_IPI;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ error_setg_errno(errp, errno, "Creating the KVM device failed");
+ return;
+ }
+ ipi_class->is_created = true;
+ ipi_class->dev_fd = cd.fd;
+ fprintf(stdout, "Create LoongArch IPI irqchip in KVM done!\n");
+ }
+
+ assert(ipi_class->dev_fd != IPI_DEV_FD_UNDEF);
+}
+
+static Property kvm_loongarch_ipi_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", KVMLoongArchIPI, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_kvm_ipi_core = {
+ .name = "kvm-ipi-single",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(status, IPICore),
+ VMSTATE_UINT32(en, IPICore),
+ VMSTATE_UINT32(set, IPICore),
+ VMSTATE_UINT32(clear, IPICore),
+ VMSTATE_UINT32_ARRAY(buf, IPICore, 8),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_kvm_loongarch_ipi = {
+ .name = TYPE_KVM_LOONGARCH_IPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = kvm_loongarch_ipi_pre_save,
+ .post_load = kvm_loongarch_ipi_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, KVMLoongArchIPI, num_cpu,
+ vmstate_kvm_ipi_core, IPICore),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void kvm_loongarch_ipi_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_CLASS(oc);
+
+ ipi_class->parent_realize = dc->realize;
+ dc->realize = kvm_loongarch_ipi_realize;
+
+ ipi_class->is_created = false;
+ ipi_class->dev_fd = IPI_DEV_FD_UNDEF;
+
+ device_class_set_props(dc, kvm_loongarch_ipi_properties);
+
+ dc->vmsd = &vmstate_kvm_loongarch_ipi;
+}
+
+static const TypeInfo kvm_loongarch_ipi_info = {
+ .name = TYPE_KVM_LOONGARCH_IPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMLoongArchIPI),
+ .class_size = sizeof(KVMLoongArchIPIClass),
+ .class_init = kvm_loongarch_ipi_class_init,
+};
+
+static void kvm_loongarch_ipi_register_types(void)
+{
+ type_register_static(&kvm_loongarch_ipi_info);
+}
+
+type_init(kvm_loongarch_ipi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index ed355941d1..9deeeb51bb 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -70,6 +70,7 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_IPI_KVM', if_true: files('loongarch_ipi_kvm.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index b42a8573d4..1e761624c6 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -14,6 +14,7 @@ config LOONGARCH_VIRT
select LOONGARCH_PCH_PIC
select LOONGARCH_PCH_MSI
select LOONGARCH_EXTIOI
+ select LOONGARCH_IPI_KVM if KVM
select LS7A_RTC
select SMBIOS
select ACPI_CPU_HOTPLUG
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 6159fd9470..f065eb75f8 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -829,16 +829,28 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
* +--------+ +---------+ +---------+
*/
- /* Create IPI device */
- ipi = qdev_new(TYPE_LOONGARCH_IPI);
- qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
-
- /* IPI iocsr memory region */
- memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
- memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ ipi = qdev_new(TYPE_KVM_LOONGARCH_IPI);
+ qdev_prop_set_int32(ipi, "num-cpu", ms->smp.max_cpus);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+ } else {
+ ipi = qdev_new(TYPE_LOONGARCH_IPI);
+ qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+
+ /* IPI iocsr memory region */
+ memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
+ memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
+ for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
+ cpu_state = qemu_get_cpu(cpu);
+ cpudev = DEVICE(cpu_state);
+
+ /* connect ipi irq to cpu irq */
+ qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
+ }
+ }
/* Add cpu interrupt-controller */
fdt_add_cpuic_node(lvms, &cpuintc_phandle);
@@ -849,9 +861,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
lacpu = LOONGARCH_CPU(cpu_state);
env = &(lacpu->env);
env->address_space_iocsr = &lvms->as_iocsr;
-
- /* connect ipi irq to cpu irq */
- qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
env->ipistate = ipi;
}
diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
index 1c1e834849..601b4f18a7 100644
--- a/include/hw/intc/loongarch_ipi.h
+++ b/include/hw/intc/loongarch_ipi.h
@@ -32,6 +32,7 @@
#define TYPE_LOONGARCH_IPI "loongarch_ipi"
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI)
+#define TYPE_KVM_LOONGARCH_IPI "loongarch-ipi-kvm"
typedef struct IPICore {
uint32_t status;
@@ -51,4 +52,26 @@ struct LoongArchIPI {
IPICore *cpu;
};
+struct KVMLoongArchIPI {
+ SysBusDevice parent_obj;
+ uint32_t num_cpu;
+ IPICore *cpu;
+};
+typedef struct KVMLoongArchIPI KVMLoongArchIPI;
+DECLARE_INSTANCE_CHECKER(KVMLoongArchIPI, KVM_LOONGARCH_IPI,
+ TYPE_KVM_LOONGARCH_IPI)
+
+struct KVMLoongArchIPIClass {
+ SysBusDeviceClass parent_class;
+ DeviceRealize parent_realize;
+
+ bool is_created;
+ int dev_fd;
+
+};
+typedef struct KVMLoongArchIPIClass KVMLoongArchIPIClass;
+DECLARE_CLASS_CHECKERS(KVMLoongArchIPIClass, KVM_LOONGARCH_IPI,
+ TYPE_KVM_LOONGARCH_IPI)
+
+
#endif
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index eb30402c2d..ea1f821a9f 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1470,6 +1470,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME
KVM_DEV_TYPE_RISCV_AIA,
#define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA
+ KVM_DEV_TYPE_LA_IPI,
+#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI
KVM_DEV_TYPE_MAX,
};
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 550f14269e..ab1ea3d4fd 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1066,6 +1066,10 @@ int kvm_arch_get_default_type(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
+ if(!kvm_vm_check_attr(kvm_state, KVM_LOONGARCH_VM_HAVE_IRQCHIP, KVM_LOONGARCH_VM_HAVE_IRQCHIP)) {
+ s->kernel_irqchip_allowed = false;
+ }
+
return 0;
}
--
2.39.1

View File

@ -0,0 +1,384 @@
From 833cdea8037d9124cd2e0328739de1b85aaec2a2 Mon Sep 17 00:00:00 2001
From: gaosong <gaosong@loongson.cn>
Date: Sun, 8 Sep 2024 09:50:50 +0800
Subject: [PATCH 73/78] hw/loongarch: Add KVM extioi device support
Added extioi interrupt controller for kvm emulation.
The main process is to send the command word for
creating an extioi device to the kernel.
When the VM is saved, the ioctl obtains the related
data of the extioi interrupt controller in the kernel
and saves it. When the VM is recovered, the saved data
is sent to the kernel.
Signed-off-by: gaosong <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/intc/Kconfig | 3 +
hw/intc/loongarch_extioi_kvm.c | 150 +++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/loongarch/Kconfig | 1 +
hw/loongarch/virt.c | 50 +++++-----
include/hw/intc/loongarch_extioi.h | 36 ++++++-
include/hw/loongarch/virt.h | 15 +++
linux-headers/linux/kvm.h | 2 +
8 files changed, 232 insertions(+), 26 deletions(-)
create mode 100644 hw/intc/loongarch_extioi_kvm.c
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index cbba74c22e..f1e8bd2fc9 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -107,3 +107,6 @@ config LOONGARCH_PCH_MSI
config LOONGARCH_EXTIOI
bool
+
+config LOONGARCH_EXTIOI_KVM
+ bool
diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c
new file mode 100644
index 0000000000..f5bbc33255
--- /dev/null
+++ b/hw/intc/loongarch_extioi_kvm.c
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch kvm extioi interrupt support
+ *
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "qemu/typedefs.h"
+#include "hw/intc/loongarch_extioi.h"
+#include "hw/sysbus.h"
+#include "linux/kvm.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+
+static void kvm_extioi_access_regs(int fd, uint64_t addr,
+ void *val, int is_write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS,
+ addr, val, is_write, &error_abort);
+}
+
+static int kvm_loongarch_extioi_pre_save(void *opaque)
+{
+ KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque;
+ KVMLoongArchExtIOIClass *class = KVM_LOONGARCH_EXTIOI_GET_CLASS(s);
+ int fd = class->dev_fd;
+
+ kvm_extioi_access_regs(fd, EXTIOI_NODETYPE_START,
+ (void *)s->nodetype, false);
+ kvm_extioi_access_regs(fd, EXTIOI_IPMAP_START, (void *)s->ipmap, false);
+ kvm_extioi_access_regs(fd, EXTIOI_ENABLE_START, (void *)s->enable, false);
+ kvm_extioi_access_regs(fd, EXTIOI_BOUNCE_START, (void *)s->bounce, false);
+ kvm_extioi_access_regs(fd, EXTIOI_ISR_START, (void *)s->isr, false);
+ kvm_extioi_access_regs(fd, EXTIOI_COREMAP_START,
+ (void *)s->coremap, false);
+ kvm_extioi_access_regs(fd, EXTIOI_SW_COREMAP_FLAG,
+ (void *)s->sw_coremap, false);
+ kvm_extioi_access_regs(fd, EXTIOI_COREISR_START,
+ (void *)s->coreisr, false);
+
+ return 0;
+}
+
+static int kvm_loongarch_extioi_post_load(void *opaque, int version_id)
+{
+ KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque;
+ KVMLoongArchExtIOIClass *class = KVM_LOONGARCH_EXTIOI_GET_CLASS(s);
+ int fd = class->dev_fd;
+
+ kvm_extioi_access_regs(fd, EXTIOI_NODETYPE_START,
+ (void *)s->nodetype, true);
+ kvm_extioi_access_regs(fd, EXTIOI_IPMAP_START, (void *)s->ipmap, true);
+ kvm_extioi_access_regs(fd, EXTIOI_ENABLE_START, (void *)s->enable, true);
+ kvm_extioi_access_regs(fd, EXTIOI_BOUNCE_START, (void *)s->bounce, true);
+ kvm_extioi_access_regs(fd, EXTIOI_ISR_START, (void *)s->isr, true);
+ kvm_extioi_access_regs(fd, EXTIOI_COREMAP_START, (void *)s->coremap, true);
+ kvm_extioi_access_regs(fd, EXTIOI_SW_COREMAP_FLAG,
+ (void *)s->sw_coremap, true);
+ kvm_extioi_access_regs(fd, EXTIOI_COREISR_START, (void *)s->coreisr, true);
+
+ return 0;
+}
+
+static void kvm_loongarch_extioi_realize(DeviceState *dev, Error **errp)
+{
+ KVMLoongArchExtIOIClass *extioi_class = KVM_LOONGARCH_EXTIOI_GET_CLASS(dev);
+ struct kvm_create_device cd = {0};
+ Error *err = NULL;
+ int ret,i;
+
+ extioi_class->parent_realize(dev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ if (!extioi_class->is_created) {
+ cd.type = KVM_DEV_TYPE_LA_EXTIOI;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ error_setg_errno(errp, errno,
+ "Creating the KVM extioi device failed");
+ return;
+ }
+ extioi_class->is_created = true;
+ extioi_class->dev_fd = cd.fd;
+ fprintf(stdout, "Create LoongArch extioi irqchip in KVM done!\n");
+ }
+
+ kvm_async_interrupts_allowed = true;
+ kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
+ if (kvm_has_gsi_routing()) {
+ for (i = 0; i < 64; ++i) {
+ kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
+ }
+ kvm_gsi_routing_allowed = true;
+ }
+}
+
+static const VMStateDescription vmstate_kvm_extioi_core = {
+ .name = "kvm-extioi-single",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = kvm_loongarch_extioi_pre_save,
+ .post_load = kvm_loongarch_extioi_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(nodetype, KVMLoongArchExtIOI,
+ EXTIOI_IRQS_NODETYPE_COUNT / 2),
+ VMSTATE_UINT32_ARRAY(bounce, KVMLoongArchExtIOI,
+ EXTIOI_IRQS_GROUP_COUNT),
+ VMSTATE_UINT32_ARRAY(isr, KVMLoongArchExtIOI, EXTIOI_IRQS / 32),
+ VMSTATE_UINT32_2DARRAY(coreisr, KVMLoongArchExtIOI, EXTIOI_CPUS,
+ EXTIOI_IRQS_GROUP_COUNT),
+ VMSTATE_UINT32_ARRAY(enable, KVMLoongArchExtIOI, EXTIOI_IRQS / 32),
+ VMSTATE_UINT32_ARRAY(ipmap, KVMLoongArchExtIOI,
+ EXTIOI_IRQS_IPMAP_SIZE / 4),
+ VMSTATE_UINT32_ARRAY(coremap, KVMLoongArchExtIOI, EXTIOI_IRQS / 4),
+ VMSTATE_UINT8_ARRAY(sw_coremap, KVMLoongArchExtIOI, EXTIOI_IRQS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void kvm_loongarch_extioi_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ KVMLoongArchExtIOIClass *extioi_class = KVM_LOONGARCH_EXTIOI_CLASS(oc);
+
+ extioi_class->parent_realize = dc->realize;
+ dc->realize = kvm_loongarch_extioi_realize;
+ extioi_class->is_created = false;
+ dc->vmsd = &vmstate_kvm_extioi_core;
+}
+
+static const TypeInfo kvm_loongarch_extioi_info = {
+ .name = TYPE_KVM_LOONGARCH_EXTIOI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMLoongArchExtIOI),
+ .class_size = sizeof(KVMLoongArchExtIOIClass),
+ .class_init = kvm_loongarch_extioi_class_init,
+};
+
+static void kvm_loongarch_extioi_register_types(void)
+{
+ type_register_static(&kvm_loongarch_extioi_info);
+}
+
+type_init(kvm_loongarch_extioi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 9deeeb51bb..a37d7da8aa 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -74,3 +74,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_IPI_KVM', if_true: files('loongarch_ipi_
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI_KVM', if_true: files('loongarch_extioi_kvm.c'))
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 1e761624c6..1a47d44a64 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -15,6 +15,7 @@ config LOONGARCH_VIRT
select LOONGARCH_PCH_MSI
select LOONGARCH_EXTIOI
select LOONGARCH_IPI_KVM if KVM
+ select LOONGARCH_EXTIOI_KVM if KVM
select LS7A_RTC
select SMBIOS
select ACPI_CPU_HOTPLUG
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index f065eb75f8..71e2a3735c 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -867,31 +867,33 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
lvms->ipi = ipi;
/* Create EXTIOI device */
- extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
- qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.max_cpus);
- if (virt_is_veiointc_enabled(lvms)) {
- qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
- }
- sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
-
- memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
- if (virt_is_veiointc_enabled(lvms)) {
- memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
- }
- lvms->extioi = extioi;
-
- /*
- * connect ext irq to the cpu irq
- * cpu_pin[9:2] <= intc_pin[7:0]
- */
- for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
- cpudev = DEVICE(qemu_get_cpu(cpu));
- for (pin = 0; pin < LS3A_INTC_IP; pin++) {
- qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
- qdev_get_gpio_in(cpudev, pin + 2));
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ extioi = qdev_new(TYPE_KVM_LOONGARCH_EXTIOI);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
+ } else {
+ extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
+ qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.max_cpus);
+ if (virt_is_veiointc_enabled(lvms)) {
+ qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
}
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
+ memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+ if (virt_is_veiointc_enabled(lvms)) {
+ memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
+ }
+ /*
+ * connect ext irq to the cpu irq
+ * cpu_pin[9:2] <= intc_pin[7:0]
+ */
+ for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
+ cpudev = DEVICE(qemu_get_cpu(cpu));
+ for (pin = 0; pin < LS3A_INTC_IP; pin++) {
+ qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
+ qdev_get_gpio_in(cpudev, pin + 2));
+ }
+ }
}
lvms->extioi = extioi;
diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
index 722ffee1bc..9966cd98d3 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -15,7 +15,7 @@
#define EXTIOI_IRQS (256)
#define EXTIOI_IRQS_BITMAP_SIZE (256 / 8)
/* irq from EXTIOI is routed to no more than 4 cpus */
-#define EXTIOI_CPUS (4)
+#define EXTIOI_CPUS (256)
/* map to ipnum per 32 irqs */
#define EXTIOI_IRQS_IPMAP_SIZE (256 / 32)
#define EXTIOI_IRQS_COREMAP_SIZE 256
@@ -59,13 +59,17 @@
#define EXTIOI_VIRT_COREMAP_START (0x40)
#define EXTIOI_VIRT_COREMAP_END (0x240)
+#define EXTIOI_SW_COREMAP_FLAG (1 << 0)
+
typedef struct ExtIOICore {
uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
qemu_irq parent_irq[LS3A_INTC_IP];
} ExtIOICore;
-#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi"
+#define TYPE_LOONGARCH_EXTIOI "loongarch-extioi"
+#define TYPE_KVM_LOONGARCH_EXTIOI "loongarch-kvm-extioi"
+
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
struct LoongArchExtIOI {
SysBusDevice parent_obj;
@@ -87,4 +91,32 @@ struct LoongArchExtIOI {
MemoryRegion extioi_system_mem;
MemoryRegion virt_extend;
};
+
+struct KVMLoongArchExtIOI {
+ SysBusDevice parent_obj;
+ /* hardware state */
+ uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
+ uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
+ uint32_t isr[EXTIOI_IRQS / 32];
+ uint32_t coreisr[EXTIOI_CPUS][EXTIOI_IRQS_GROUP_COUNT];
+ uint32_t enable[EXTIOI_IRQS / 32];
+ uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4];
+ uint32_t coremap[EXTIOI_IRQS / 4];
+ uint8_t sw_coremap[EXTIOI_IRQS];
+};
+typedef struct KVMLoongArchExtIOI KVMLoongArchExtIOI;
+DECLARE_INSTANCE_CHECKER(KVMLoongArchExtIOI, KVM_LOONGARCH_EXTIOI,
+ TYPE_KVM_LOONGARCH_EXTIOI)
+
+struct KVMLoongArchExtIOIClass {
+ SysBusDeviceClass parent_class;
+ DeviceRealize parent_realize;
+
+ bool is_created;
+ int dev_fd;
+};
+typedef struct KVMLoongArchExtIOIClass KVMLoongArchExtIOIClass;
+DECLARE_CLASS_CHECKERS(KVMLoongArchExtIOIClass, KVM_LOONGARCH_EXTIOI,
+ TYPE_KVM_LOONGARCH_EXTIOI)
+
#endif /* LOONGARCH_EXTIOI_H */
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 98c990327b..168b40c31b 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -38,6 +38,21 @@
#define FDT_BASE 0x100000
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_LOONGARCH_IRQ_TYPE_SHIFT 24
+#define KVM_LOONGARCH_IRQ_TYPE_MASK 0xff
+#define KVM_LOONGARCH_IRQ_VCPU_SHIFT 16
+#define KVM_LOONGARCH_IRQ_VCPU_MASK 0xff
+#define KVM_LOONGARCH_IRQ_NUM_SHIFT 0
+#define KVM_LOONGARCH_IRQ_NUM_MASK 0xffff
+
+/* irq_type field */
+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IP 0
+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IO 1
+#define KVM_LOONGARCH_IRQ_TYPE_HT 2
+#define KVM_LOONGARCH_IRQ_TYPE_MSI 3
+#define KVM_LOONGARCH_IRQ_TYPE_IOAPIC 4
+
struct LoongArchVirtMachineState {
/*< private >*/
MachineState parent_obj;
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index ea1f821a9f..0c0b82d1ef 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1472,6 +1472,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA
KVM_DEV_TYPE_LA_IPI,
#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI
+ KVM_DEV_TYPE_LA_EXTIOI,
+#define KVM_DEV_TYPE_LA_EXTIOI KVM_DEV_TYPE_LA_EXTIOI
KVM_DEV_TYPE_MAX,
};
--
2.39.1

View File

@ -0,0 +1,136 @@
From 24bd774f8146247c7ac6071492f6016140a97267 Mon Sep 17 00:00:00 2001
From: gaosong <gaosong@loongson.cn>
Date: Sun, 8 Sep 2024 22:18:50 +0800
Subject: [PATCH 75/78] hw/loongarch: Add KVM pch msi device support
Added pch_msi interrupt controller handling
during kernel emulation of irq chip.
Signed-off-by: gaosong <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/intc/loongarch_pch_msi.c | 39 ++++++++++++++++++++++-------
hw/loongarch/virt.c | 22 +++++++++-------
include/hw/intc/loongarch_pch_msi.h | 2 +-
3 files changed, 44 insertions(+), 19 deletions(-)
diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c
index ecf3ed0267..901c2c21be 100644
--- a/hw/intc/loongarch_pch_msi.c
+++ b/hw/intc/loongarch_pch_msi.c
@@ -14,6 +14,8 @@
#include "hw/misc/unimp.h"
#include "migration/vmstate.h"
#include "trace.h"
+#include "sysemu/kvm.h"
+#include "hw/loongarch/virt.h"
static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
{
@@ -26,14 +28,24 @@ static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque;
int irq_num;
- /*
- * vector number is irq number from upper extioi intc
- * need subtract irq base to get msi vector offset
- */
- irq_num = (val & 0xff) - s->irq_base;
- trace_loongarch_msi_set_irq(irq_num);
- assert(irq_num < s->irq_num);
- qemu_set_irq(s->pch_msi_irq[irq_num], 1);
+ MSIMessage msg = {
+ .address = addr,
+ .data = val,
+ };
+
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ kvm_irqchip_send_msi(kvm_state, msg);
+ } else {
+ /*
+ * vector number is irq number from upper extioi intc
+ * need subtract irq base to get msi vector offset
+ */
+ irq_num = (val & 0xff) - s->irq_base;
+ trace_loongarch_msi_set_irq(irq_num);
+ assert(irq_num < s->irq_num);
+
+ qemu_set_irq(s->pch_msi_irq[irq_num], 1);
+ }
}
static const MemoryRegionOps loongarch_pch_msi_ops = {
@@ -46,7 +58,16 @@ static void pch_msi_irq_handler(void *opaque, int irq, int level)
{
LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque);
- qemu_set_irq(s->pch_msi_irq[irq], level);
+ MSIMessage msg = {
+ .address = 0,
+ .data = irq,
+ };
+
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ kvm_irqchip_send_msi(kvm_state, msg);
+ } else {
+ qemu_set_irq(s->pch_msi_irq[irq], level);
+ }
}
static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 270dcfd38f..5b0468f6cb 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -928,22 +928,26 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
for (i = 0; i < num; i++) {
qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
}
+ }
- pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
- start = num;
- num = EXTIOI_IRQS - start;
- qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
- qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
- d = SYS_BUS_DEVICE(pch_msi);
- sysbus_realize_and_unref(d, &error_fatal);
- sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
+ pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
+ num = VIRT_PCH_PIC_IRQ_NUM;
+ start = num;
+ num = EXTIOI_IRQS - start;
+ qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
+ qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
+ d = SYS_BUS_DEVICE(pch_msi);
+ sysbus_realize_and_unref(d, &error_fatal);
+
+ if (!(kvm_enabled() && kvm_irqchip_in_kernel())) {
+ /* Connect pch_msi irqs to extioi */
for (i = 0; i < num; i++) {
- /* Connect pch_msi irqs to extioi */
qdev_connect_gpio_out(DEVICE(d), i,
qdev_get_gpio_in(extioi, i + start));
}
}
+ sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
virt_devices_init(pch_pic, lvms, &pch_pic_phandle, &pch_msi_phandle);
}
diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h
index b8586fb3b6..fd4ea97a83 100644
--- a/include/hw/intc/loongarch_pch_msi.h
+++ b/include/hw/intc/loongarch_pch_msi.h
@@ -7,7 +7,7 @@
#include "hw/sysbus.h"
-#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi"
+#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi"
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHMSI, LOONGARCH_PCH_MSI)
/* MSI irq start from 32 to 255 */
--
2.39.1

View File

@ -0,0 +1,487 @@
From 30f88e80a47d9bcde08c44c0d752c22c11f2224c Mon Sep 17 00:00:00 2001
From: gaosong <gaosong@loongson.cn>
Date: Sun, 8 Sep 2024 10:13:29 +0800
Subject: [PATCH 74/78] hw/loongarch: Add KVM pch pic device support
Added pch_pic interrupt controller for kvm emulation.
The main process is to send the command word for
creating an pch_pic device to the kernel,
Delivers the pch pic interrupt controller configuration
register base address to the kernel.
When the VM is saved, the ioctl obtains the pch_pic
interrupt controller data in the kernel and saves it.
When the VM is recovered, the saved data is sent to the kernel.
Signed-off-by: gaosong <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/intc/Kconfig | 3 +
hw/intc/loongarch_pch_pic.c | 24 +++-
hw/intc/loongarch_pch_pic_kvm.c | 189 ++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/loongarch/Kconfig | 1 +
hw/loongarch/virt.c | 70 ++++++-----
include/hw/intc/loongarch_pch_pic.h | 51 +++++++-
linux-headers/linux/kvm.h | 2 +
8 files changed, 303 insertions(+), 38 deletions(-)
create mode 100644 hw/intc/loongarch_pch_pic_kvm.c
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index f1e8bd2fc9..91c7aa668e 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -100,6 +100,9 @@ config LOONGARCH_PCH_PIC
bool
select UNIMP
+config LOONGARCH_PCH_PIC_KVM
+ bool
+
config LOONGARCH_PCH_MSI
select MSI_NONBROKEN
bool
diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
index 6aa4cadfa4..beb4ac188d 100644
--- a/hw/intc/loongarch_pch_pic.c
+++ b/hw/intc/loongarch_pch_pic.c
@@ -16,19 +16,28 @@
#include "migration/vmstate.h"
#include "trace.h"
#include "qapi/error.h"
+#include "sysemu/kvm.h"
static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
{
uint64_t val;
int irq;
+ int kvm_irq;
if (level) {
val = mask & s->intirr & ~s->int_mask;
if (val) {
irq = ctz64(val);
s->intisr |= MAKE_64BIT_MASK(irq, 1);
- qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
- }
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ kvm_irq = (
+ KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT)
+ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | s->htmsi_vector[irq];
+ kvm_set_irq(kvm_state, kvm_irq, !!level);
+ } else {
+ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
+ }
+ }
} else {
/*
* intirr means requested pending irq
@@ -38,8 +47,15 @@ static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
if (val) {
irq = ctz64(val);
s->intisr &= ~MAKE_64BIT_MASK(irq, 1);
- qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
- }
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ kvm_irq = (
+ KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT)
+ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | s->htmsi_vector[irq];
+ kvm_set_irq(kvm_state, kvm_irq, !!level);
+ } else {
+ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
+ }
+ }
}
}
diff --git a/hw/intc/loongarch_pch_pic_kvm.c b/hw/intc/loongarch_pch_pic_kvm.c
new file mode 100644
index 0000000000..8f66d9a01f
--- /dev/null
+++ b/hw/intc/loongarch_pch_pic_kvm.c
@@ -0,0 +1,189 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch kvm pch pic interrupt support
+ *
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "qemu/typedefs.h"
+#include "hw/intc/loongarch_pch_pic.h"
+#include "hw/sysbus.h"
+#include "linux/kvm.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+#include "hw/loongarch/virt.h"
+#include "hw/pci-host/ls7a.h"
+#include "qemu/error-report.h"
+
+static void kvm_pch_pic_access_regs(int fd, uint64_t addr,
+ void *val, int is_write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS,
+ addr, val, is_write, &error_abort);
+}
+
+static int kvm_loongarch_pch_pic_pre_save(void *opaque)
+{
+ KVMLoongArchPCHPIC *s = (KVMLoongArchPCHPIC *)opaque;
+ KVMLoongArchPCHPICClass *class = KVM_LOONGARCH_PCH_PIC_GET_CLASS(s);
+ int fd = class->dev_fd;
+
+ kvm_pch_pic_access_regs(fd, PCH_PIC_MASK_START,
+ (void *)&s->int_mask, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_EN_START,
+ (void *)&s->htmsi_en, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_EDGE_START,
+ (void *)&s->intedge, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL0_START,
+ (void *)&s->auto_crtl0, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL1_START,
+ (void *)&s->auto_crtl1, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_ROUTE_ENTRY_START,
+ (void *)s->route_entry, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_VEC_START,
+ (void *)s->htmsi_vector, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_IRR_START,
+ (void *)&s->intirr, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_ISR_START,
+ (void *)&s->intisr, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_POLARITY_START,
+ (void *)&s->int_polarity, false);
+
+ return 0;
+}
+
+static int kvm_loongarch_pch_pic_post_load(void *opaque, int version_id)
+{
+ KVMLoongArchPCHPIC *s = (KVMLoongArchPCHPIC *)opaque;
+ KVMLoongArchPCHPICClass *class = KVM_LOONGARCH_PCH_PIC_GET_CLASS(s);
+ int fd = class->dev_fd;
+
+ kvm_pch_pic_access_regs(fd, PCH_PIC_MASK_START,
+ (void *)&s->int_mask, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_EN_START,
+ (void *)&s->htmsi_en, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_EDGE_START,
+ (void *)&s->intedge, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL0_START,
+ (void *)&s->auto_crtl0, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL1_START,
+ (void *)&s->auto_crtl1, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_ROUTE_ENTRY_START,
+ (void *)s->route_entry, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_VEC_START,
+ (void *)s->htmsi_vector, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_IRR_START,
+ (void *)&s->intirr, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_ISR_START,
+ (void *)&s->intisr, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_POLARITY_START,
+ (void *)&s->int_polarity, true);
+
+ return 0;
+}
+
+static void kvm_pch_pic_handler(void *opaque, int irq, int level)
+{
+ int kvm_irq;
+
+ if (kvm_enabled()) {
+ kvm_irq = \
+ (KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT)
+ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | irq;
+ kvm_set_irq(kvm_state, kvm_irq, !!level);
+ }
+}
+
+static void kvm_loongarch_pch_pic_realize(DeviceState *dev, Error **errp)
+{
+ KVMLoongArchPCHPICClass *pch_pic_class =
+ KVM_LOONGARCH_PCH_PIC_GET_CLASS(dev);
+ struct kvm_create_device cd = {0};
+ uint64_t pch_pic_base = VIRT_PCH_REG_BASE;
+ Error *err = NULL;
+ int ret;
+
+ pch_pic_class->parent_realize(dev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ if (!pch_pic_class->is_created) {
+ cd.type = KVM_DEV_TYPE_LA_PCH_PIC;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ error_setg_errno(errp, errno,
+ "Creating the KVM pch pic device failed");
+ return;
+ }
+ pch_pic_class->is_created = true;
+ pch_pic_class->dev_fd = cd.fd;
+ fprintf(stdout, "Create LoongArch pch pic irqchip in KVM done!\n");
+
+ ret = kvm_device_access(cd.fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL,
+ KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT,
+ &pch_pic_base, true, NULL);
+ if (ret < 0) {
+ error_report(
+ "KVM EXTIOI: failed to set the base address of EXTIOI");
+ exit(1);
+ }
+
+ qdev_init_gpio_in(dev, kvm_pch_pic_handler, VIRT_PCH_PIC_IRQ_NUM);
+ }
+}
+
+static const VMStateDescription vmstate_kvm_loongarch_pch_pic = {
+ .name = TYPE_LOONGARCH_PCH_PIC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = kvm_loongarch_pch_pic_pre_save,
+ .post_load = kvm_loongarch_pch_pic_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64(int_mask, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(htmsi_en, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(intedge, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(intclr, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(auto_crtl0, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(auto_crtl1, KVMLoongArchPCHPIC),
+ VMSTATE_UINT8_ARRAY(route_entry, KVMLoongArchPCHPIC, 64),
+ VMSTATE_UINT8_ARRAY(htmsi_vector, KVMLoongArchPCHPIC, 64),
+ VMSTATE_UINT64(last_intirr, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(intirr, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(intisr, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(int_polarity, KVMLoongArchPCHPIC),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+static void kvm_loongarch_pch_pic_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ KVMLoongArchPCHPICClass *pch_pic_class = KVM_LOONGARCH_PCH_PIC_CLASS(oc);
+
+ pch_pic_class->parent_realize = dc->realize;
+ dc->realize = kvm_loongarch_pch_pic_realize;
+ pch_pic_class->is_created = false;
+ dc->vmsd = &vmstate_kvm_loongarch_pch_pic;
+
+}
+
+static const TypeInfo kvm_loongarch_pch_pic_info = {
+ .name = TYPE_KVM_LOONGARCH_PCH_PIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMLoongArchPCHPIC),
+ .class_size = sizeof(KVMLoongArchPCHPICClass),
+ .class_init = kvm_loongarch_pch_pic_class_init,
+};
+
+static void kvm_loongarch_pch_pic_register_types(void)
+{
+ type_register_static(&kvm_loongarch_pch_pic_info);
+}
+
+type_init(kvm_loongarch_pch_pic_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index a37d7da8aa..49b4501315 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -75,3 +75,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI_KVM', if_true: files('loongarch_extioi_kvm.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC_KVM', if_true: files('loongarch_pch_pic_kvm.c'))
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 1a47d44a64..16c854c0d5 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -15,6 +15,7 @@ config LOONGARCH_VIRT
select LOONGARCH_PCH_MSI
select LOONGARCH_EXTIOI
select LOONGARCH_IPI_KVM if KVM
+ select LOONGARCH_PCH_PIC_KVM if KVM
select LOONGARCH_EXTIOI_KVM if KVM
select LS7A_RTC
select SMBIOS
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 71e2a3735c..270dcfd38f 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -901,45 +901,49 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
/* Add Extend I/O Interrupt Controller node */
fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle);
- pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
- num = VIRT_PCH_PIC_IRQ_NUM;
- qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
- d = SYS_BUS_DEVICE(pch_pic);
- sysbus_realize_and_unref(d, &error_fatal);
- memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
- sysbus_mmio_get_region(d, 0));
- memory_region_add_subregion(get_system_memory(),
- VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET,
- sysbus_mmio_get_region(d, 1));
- memory_region_add_subregion(get_system_memory(),
- VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
- sysbus_mmio_get_region(d, 2));
-
- /* Connect pch_pic irqs to extioi */
- for (i = 0; i < num; i++) {
- qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
- }
-
/* Add PCH PIC node */
fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle);
- pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
- start = num;
- num = EXTIOI_IRQS - start;
- qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
- qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
- d = SYS_BUS_DEVICE(pch_msi);
- sysbus_realize_and_unref(d, &error_fatal);
- sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
- for (i = 0; i < num; i++) {
- /* Connect pch_msi irqs to extioi */
- qdev_connect_gpio_out(DEVICE(d), i,
- qdev_get_gpio_in(extioi, i + start));
- }
-
/* Add PCH MSI node */
fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle);
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ pch_pic = qdev_new(TYPE_KVM_LOONGARCH_PCH_PIC);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(pch_pic), &error_fatal);
+ } else {
+ pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
+ num = VIRT_PCH_PIC_IRQ_NUM;
+ qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
+ d = SYS_BUS_DEVICE(pch_pic);
+ sysbus_realize_and_unref(d, &error_fatal);
+ memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
+ sysbus_mmio_get_region(d, 0));
+ memory_region_add_subregion(get_system_memory(),
+ VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET,
+ sysbus_mmio_get_region(d, 1));
+ memory_region_add_subregion(get_system_memory(),
+ VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
+ sysbus_mmio_get_region(d, 2));
+ /* Connect pch_pic irqs to extioi */
+ for (i = 0; i < num; i++) {
+ qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
+ }
+
+ pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
+ start = num;
+ num = EXTIOI_IRQS - start;
+ qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
+ qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
+ d = SYS_BUS_DEVICE(pch_msi);
+ sysbus_realize_and_unref(d, &error_fatal);
+ sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
+ for (i = 0; i < num; i++) {
+ /* Connect pch_msi irqs to extioi */
+ qdev_connect_gpio_out(DEVICE(d), i,
+ qdev_get_gpio_in(extioi, i + start));
+ }
+ }
+
virt_devices_init(pch_pic, lvms, &pch_pic_phandle, &pch_msi_phandle);
}
diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
index d5437e88f2..77f4cd74a1 100644
--- a/include/hw/intc/loongarch_pch_pic.h
+++ b/include/hw/intc/loongarch_pch_pic.h
@@ -7,7 +7,8 @@
#include "hw/sysbus.h"
-#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
+#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
+#define TYPE_KVM_LOONGARCH_PCH_PIC "loongarch_kvm_pch_pic"
#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
@@ -37,6 +38,19 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
#define PCH_PIC_INT_POL_LO 0x3e0
#define PCH_PIC_INT_POL_HI 0x3e4
+#define PCH_PIC_INT_ID_START PCH_PIC_INT_ID_LO
+#define PCH_PIC_MASK_START PCH_PIC_INT_MASK_LO
+#define PCH_PIC_HTMSI_EN_START PCH_PIC_HTMSI_EN_LO
+#define PCH_PIC_EDGE_START PCH_PIC_INT_EDGE_LO
+#define PCH_PIC_CLEAR_START PCH_PIC_INT_CLEAR_LO
+#define PCH_PIC_AUTO_CTRL0_START PCH_PIC_AUTO_CTRL0_LO
+#define PCH_PIC_AUTO_CTRL1_START PCH_PIC_AUTO_CTRL1_LO
+#define PCH_PIC_ROUTE_ENTRY_START PCH_PIC_ROUTE_ENTRY_OFFSET
+#define PCH_PIC_HTMSI_VEC_START PCH_PIC_HTMSI_VEC_OFFSET
+#define PCH_PIC_INT_IRR_START 0x380
+#define PCH_PIC_INT_ISR_START PCH_PIC_INT_STATUS_LO
+#define PCH_PIC_POLARITY_START PCH_PIC_INT_POL_LO
+
#define STATUS_LO_START 0
#define STATUS_HI_START 0x4
#define POL_LO_START 0x40
@@ -67,3 +81,38 @@ struct LoongArchPCHPIC {
MemoryRegion iomem8;
unsigned int irq_num;
};
+
+struct KVMLoongArchPCHPIC {
+ SysBusDevice parent_obj;
+ uint64_t int_mask; /*0x020 interrupt mask register*/
+ uint64_t htmsi_en; /*0x040 1=msi*/
+ uint64_t intedge; /*0x060 edge=1 level =0*/
+ uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
+ uint64_t auto_crtl0; /*0x0c0*/
+ uint64_t auto_crtl1; /*0x0e0*/
+ uint64_t last_intirr; /* edge detection */
+ uint64_t intirr; /* 0x380 interrupt request register */
+ uint64_t intisr; /* 0x3a0 interrupt service register */
+ /*
+ * 0x3e0 interrupt level polarity selection
+ * register 0 for high level trigger
+ */
+ uint64_t int_polarity;
+
+ uint8_t route_entry[64]; /*0x100 - 0x138*/
+ uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
+};
+typedef struct KVMLoongArchPCHPIC KVMLoongArchPCHPIC;
+DECLARE_INSTANCE_CHECKER(KVMLoongArchPCHPIC, KVM_LOONGARCH_PCH_PIC,
+ TYPE_KVM_LOONGARCH_PCH_PIC)
+
+struct KVMLoongArchPCHPICClass {
+ SysBusDeviceClass parent_class;
+ DeviceRealize parent_realize;
+
+ bool is_created;
+ int dev_fd;
+};
+typedef struct KVMLoongArchPCHPICClass KVMLoongArchPCHPICClass;
+DECLARE_CLASS_CHECKERS(KVMLoongArchPCHPICClass, KVM_LOONGARCH_PCH_PIC,
+ TYPE_KVM_LOONGARCH_PCH_PIC)
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 0c0b82d1ef..887f8268e7 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1470,6 +1470,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME
KVM_DEV_TYPE_RISCV_AIA,
#define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA
+ KVM_DEV_TYPE_LA_PCH_PIC = 0x100,
+#define KVM_DEV_TYPE_LA_PCH_PIC KVM_DEV_TYPE_LA_PCH_PIC
KVM_DEV_TYPE_LA_IPI,
#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI
KVM_DEV_TYPE_LA_EXTIOI,
--
2.39.1

View File

@ -0,0 +1,49 @@
From 0437c11a20b3c66882770e468518d33ff71a932a Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Tue, 14 May 2024 10:51:09 +0800
Subject: [PATCH 22/78] hw/loongarch: Add VM mode in IOCSR feature register in
kvm mode
If VM runs in kvm mode, VM mode is added in IOCSR feature register.
So guest can detect kvm hypervisor type and enable possible pv functions.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240514025109.3238398-1-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index e82e3b6792..c3514f9293 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -10,6 +10,7 @@
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/char/serial.h"
+#include "sysemu/kvm.h"
#include "sysemu/sysemu.h"
#include "sysemu/qtest.h"
#include "sysemu/runstate.h"
@@ -914,12 +915,11 @@ static MemTxResult loongarch_qemu_read(void *opaque, hwaddr addr,
ret = 0x11ULL;
break;
case FEATURE_REG:
- ret = 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI |
- 1ULL << IOCSRF_CSRIPI;
+ ret = BIT(IOCSRF_MSI) | BIT(IOCSRF_EXTIOI) | BIT(IOCSRF_CSRIPI);
if (kvm_enabled()) {
- ret |= 1ULL << IOCSRF_VM;
+ ret |= BIT(IOCSRF_VM);
}
- break;
+ return ret;
case VENDOR_REG:
ret = 0x6e6f73676e6f6f4cULL; /* "Loongson" */
break;
--
2.39.1

View File

@ -0,0 +1,82 @@
From fe22e0efe4c1c99fc876a42446cb2c87f9457afb Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Sat, 7 Sep 2024 15:30:37 +0800
Subject: [PATCH 37/78] hw/loongarch: Add acpi SPCR table support
Serial port console redirection table can be used for default serial
port selection, like chosen stdout-path selection with FDT method.
With acpi SPCR table added, early debug console can be parsed from
SPCR table with simple kernel parameter earlycon rather than
earlycon=uart,mmio,0x1fe001e0
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240907073037.243353-1-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/acpi-build.c | 40 +++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 33a92223d8..bcdec2e1cb 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -242,6 +242,44 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
acpi_table_end(linker, &table);
}
+/*
+ * Serial Port Console Redirection Table (SPCR)
+ * https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
+ */
+static void
+spcr_setup(GArray *table_data, BIOSLinker *linker, MachineState *machine)
+{
+ LoongArchVirtMachineState *lvms;
+ AcpiSpcrData serial = {
+ .interface_type = 0, /* 16550 compatible */
+ .base_addr.id = AML_AS_SYSTEM_MEMORY,
+ .base_addr.width = 32,
+ .base_addr.offset = 0,
+ .base_addr.size = 1,
+ .base_addr.addr = VIRT_UART_BASE,
+ .interrupt_type = 0, /* Interrupt not supported */
+ .pc_interrupt = 0,
+ .interrupt = VIRT_UART_IRQ,
+ .baud_rate = 7, /* 115200 */
+ .parity = 0,
+ .stop_bits = 1,
+ .flow_control = 0,
+ .terminal_type = 3, /* ANSI */
+ .language = 0, /* Language */
+ .pci_device_id = 0xffff, /* not a PCI device*/
+ .pci_vendor_id = 0xffff, /* not a PCI device*/
+ .pci_bus = 0,
+ .pci_device = 0,
+ .pci_function = 0,
+ .pci_flags = 0,
+ .pci_segment = 0,
+ };
+
+ lvms = LOONGARCH_VIRT_MACHINE(machine);
+ build_spcr(table_data, linker, &serial, 2, lvms->oem_id,
+ lvms->oem_table_id);
+}
+
typedef
struct AcpiBuildState {
/* Copy of table in RAM (for patching). */
@@ -484,6 +522,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, machine);
+ acpi_add_table(table_offsets, tables_blob);
+ spcr_setup(tables_blob, tables->linker, machine);
if (machine->numa_state->num_nodes) {
if (machine->numa_state->have_numa_distance) {
--
2.39.1

View File

@ -0,0 +1,56 @@
From 7266141c658cd00426922534a7de4dd5d89486b2 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:51 +0800
Subject: [PATCH 16/78] hw/loongarch: Add cells missing from rtc node
rtc node need interrupts and interrupt-parent cells.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-18-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,52 @@
From 33994eff45e75e91acf0a4753fec77ad0027e4dd Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:50 +0800
Subject: [PATCH 15/78] hw/loongarch: Add cells missing from uart node
uart node need interrupts and interrupt-parent cells.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-17-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,117 @@
From 206b799cb8c218c744f4dcdaf161d11f14c21e0f Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:38 +0800
Subject: [PATCH 04/78] hw/loongarch: Add init_cmdline
Add init_cmline and set boot_info->a0, a1
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-5-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,64 @@
From 02c5f52da7f9458c0fc41e43f181f6e9b7101b57 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:36 +0800
Subject: [PATCH 02/78] hw/loongarch: Add load initrd
we load initrd ramdisk after kernel_high address
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-3-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,103 @@
From 2e3e7bcf92284f41c08fce29f6c6d45849721e71 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:37 +0800
Subject: [PATCH 03/78] hw/loongarch: Add slave cpu boot_code
Load the slave CPU boot code at pflash0 and set
the slave CPU elf_address to VIRT_FLASH0_BASE.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-4-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,46 @@
From 67c68371e457a85e460221a8c56d8dc93186f79f Mon Sep 17 00:00:00 2001
From: Xianglai Li <lixianglai@loongson.cn>
Date: Mon, 24 Jun 2024 11:23:00 +0800
Subject: [PATCH 31/78] hw/loongarch: Change the tpm support by default
Add devices that support tpm by default,
Fixed incomplete tpm acpi table information.
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240624032300.999157-1-lixianglai@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/loongarch/Kconfig | 1 +
hw/loongarch/acpi-build.c | 3 +++
2 files changed, 4 insertions(+)
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 7864050563..b2a3adb7dc 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -7,6 +7,7 @@ config LOONGARCH_VIRT
imply VIRTIO_VGA
imply PCI_DEVICES
imply NVDIMM
+ imply TPM_TIS_SYSBUS
select SERIAL
select VIRTIO_PCI
select PLATFORM_BUS
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 2555c6763c..6593476409 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -646,6 +646,9 @@ void loongarch_acpi_setup(LoongArchVirtMachineState *lvms)
build_state, tables.rsdp,
ACPI_BUILD_RSDP_FILE);
+ fw_cfg_add_file(lvms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data,
+ acpi_data_len(tables.tcpalog));
+
qemu_register_reset(acpi_build_reset, build_state);
acpi_build_reset(build_state);
vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
--
2.39.1

View File

@ -0,0 +1,39 @@
From 087201cd62e71801855775c3aa6395c7e1c00cee Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang@flygoat.com>
Date: Tue, 20 Aug 2024 19:42:33 +0100
Subject: [PATCH 33/78] hw/loongarch: Fix length for lowram in ACPI SRAT
The size of lowram should be "gap" instead of the whole node.
This is failing kernel's sanity check:
[ 0.000000] ACPI: SRAT: Node 0 PXM 0 [mem 0x00000000-0xffffffff]
[ 0.000000] ACPI: SRAT: Node 0 PXM 0 [mem 0x80000000-0x16fffffff]
[ 0.000000] ACPI: SRAT: Node 1 PXM 1 [mem 0x170000000-0x26fffffff]
[ 0.000000] Warning: node 0 [mem 0x00000000-0xffffffff] overlaps with itself [mem 0x80000000-0x16fffffff]
Fixes: fc100011f38d ("hw/loongarch: Refine acpi srat table for numa memory")
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/acpi-build.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 6593476409..1a9d25fc51 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -218,7 +218,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
* highram: [VIRT_HIGHMEM_BASE, +(len - gap))
*/
if (len >= gap) {
- build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+ build_srat_memory(table_data, base, gap, i, MEM_AFFINITY_ENABLED);
len -= gap;
base = VIRT_HIGHMEM_BASE;
gap = machine->ram_size - VIRT_LOWMEM_SIZE;
--
2.39.1

View File

@ -0,0 +1,169 @@
From 0245881108803abedf50e954d34ebcfff294d1c3 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:40 +0800
Subject: [PATCH 06/78] hw/loongarch: Init efi_boot_memmap table
The efi_system_table adds a efi_boot_memmap configuration table.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-7-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,105 @@
From 605b2b372f972fffa2d198d8dee4cf37f335559d Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:42 +0800
Subject: [PATCH 08/78] hw/loongarch: Init efi_fdt table
The efi_system_table adds a efi_fdt configuration table.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-9-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,101 @@
From ad674827da4ab972a30d51818f7768de47336984 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:41 +0800
Subject: [PATCH 07/78] hw/loongarch: Init efi_initrd table
The efi_system_table adds a efi_initrd configuration table.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-8-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,125 @@
From 65ae44689bfa6a1b697fea6ec0e72027fdddee95 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:39 +0800
Subject: [PATCH 05/78] hw/loongarch: Init efi_system_table
Add init_systab and set boot_info->a2
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-6-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,390 @@
From 2414b74bec88f4db58040a683191d3c3828f81ab Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:35 +0800
Subject: [PATCH 01/78] hw/loongarch: Move boot functions to boot.c
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Move some boot functions to boot.c and struct
loongarch_boot_info into struct LoongArchMachineState.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20240426091551.2397867-2-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,108 @@
From 1c9b7b7e76a63738721ac1092fdfff12ae87993a Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 15 May 2024 17:39:22 +0800
Subject: [PATCH 23/78] hw/loongarch: Refine acpi srat table for numa memory
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.
Limitations for minimum memory size for both total memory and numa
node0 is removed for acpi srat table creation.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240515093927.3453674-2-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/acpi-build.c | 58 +++++++++++++++++++++++----------------
1 file changed, 34 insertions(+), 24 deletions(-)
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 2b4e09bf37..2555c6763c 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -166,8 +166,9 @@ static void
build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
{
int i, arch_id, node_id;
- uint64_t mem_len, mem_base;
- int nb_numa_nodes = machine->numa_state->num_nodes;
+ hwaddr len, base, gap;
+ NodeInfo *numa_info;
+ int nodes, nb_numa_nodes = machine->numa_state->num_nodes;
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(lvms);
const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
@@ -196,35 +197,44 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
}
- /* Node0 */
- build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE,
- 0, MEM_AFFINITY_ENABLED);
- mem_base = VIRT_HIGHMEM_BASE;
- if (!nb_numa_nodes) {
- mem_len = machine->ram_size - VIRT_LOWMEM_SIZE;
- } else {
- mem_len = machine->numa_state->nodes[0].node_mem - VIRT_LOWMEM_SIZE;
+ base = VIRT_LOWMEM_BASE;
+ gap = VIRT_LOWMEM_SIZE;
+ numa_info = machine->numa_state->nodes;
+ nodes = nb_numa_nodes;
+ if (!nodes) {
+ nodes = 1;
}
- if (mem_len)
- build_srat_memory(table_data, mem_base, mem_len, 0, MEM_AFFINITY_ENABLED);
-
- /* Node1 - Nodemax */
- if (nb_numa_nodes) {
- mem_base += mem_len;
- for (i = 1; i < nb_numa_nodes; ++i) {
- if (machine->numa_state->nodes[i].node_mem > 0) {
- build_srat_memory(table_data, mem_base,
- machine->numa_state->nodes[i].node_mem, i,
- MEM_AFFINITY_ENABLED);
- mem_base += machine->numa_state->nodes[i].node_mem;
- }
+
+ for (i = 0; i < nodes; i++) {
+ if (nb_numa_nodes) {
+ len = numa_info[i].node_mem;
+ } else {
+ len = machine->ram_size;
+ }
+
+ /*
+ * memory for the node splited into two part
+ * lowram: [base, +gap)
+ * highram: [VIRT_HIGHMEM_BASE, +(len - gap))
+ */
+ if (len >= gap) {
+ build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+ len -= gap;
+ base = VIRT_HIGHMEM_BASE;
+ gap = machine->ram_size - VIRT_LOWMEM_SIZE;
+ }
+
+ if (len) {
+ build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+ base += len;
+ gap -= len;
}
}
if (machine->device_memory) {
build_srat_memory(table_data, machine->device_memory->base,
memory_region_size(&machine->device_memory->mr),
- nb_numa_nodes - 1,
+ nodes - 1,
MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
}
--
2.39.1

View File

@ -0,0 +1,57 @@
From a9f9a4a0a60596f2e738e6e434c20a3f5266fa17 Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Tue, 19 Mar 2024 10:26:06 +0800
Subject: [PATCH 21/78] hw/loongarch: Refine default numa id calculation
With numa_test test case, there is subcase named test_def_cpu_split(),
there are 8 sockets and 2 numa nodes. Here is command line:
"-machine smp.cpus=8,smp.sockets=8 -numa node,memdev=ram -numa node"
The required result is:
node 0 cpus: 0 2 4 6
node 1 cpus: 1 3 5 7
Test case numa_test fails on LoongArch, since the actual result is:
node 0 cpus: 0 1 2 3
node 1 cpus: 4 5 6 7
It will be better if all the cpus in one socket share the same numa
node. Here socket id is used to calculate numa id in function
virt_get_default_cpu_node_id().
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240319022606.2994565-1-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index e39989193e..e82e3b6792 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1278,15 +1278,14 @@ static CpuInstanceProperties virt_cpu_index_to_props(MachineState *ms,
static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx)
{
- int64_t nidx = 0;
+ int64_t socket_id;
if (ms->numa_state->num_nodes) {
- nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes);
- if (ms->numa_state->num_nodes <= nidx) {
- nidx = ms->numa_state->num_nodes - 1;
- }
+ socket_id = ms->possible_cpus->cpus[idx].props.socket_id;
+ return socket_id % ms->numa_state->num_nodes;
+ } else {
+ return 0;
}
- return nidx;
}
static void virt_class_init(ObjectClass *oc, void *data)
--
2.39.1

View File

@ -0,0 +1,106 @@
From d39247ec5d4ef52a4b9422aaecccc284cbd1a5dd Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 15 May 2024 17:39:23 +0800
Subject: [PATCH 24/78] hw/loongarch: Refine fadt memory table for numa memory
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.
Limitations for minimum memory size for both total memory and numa
node0 is removed for fadt numa memory table creation.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240515093927.3453674-3-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 46 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 43 insertions(+), 3 deletions(-)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c3514f9293..31a2598e7c 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -502,6 +502,48 @@ static void fdt_add_memory_node(MachineState *ms,
g_free(nodename);
}
+static void fdt_add_memory_nodes(MachineState *ms)
+{
+ hwaddr base, size, ram_size, gap;
+ int i, nb_numa_nodes, nodes;
+ NodeInfo *numa_info;
+
+ ram_size = ms->ram_size;
+ base = VIRT_LOWMEM_BASE;
+ gap = VIRT_LOWMEM_SIZE;
+ nodes = nb_numa_nodes = ms->numa_state->num_nodes;
+ numa_info = ms->numa_state->nodes;
+ if (!nodes) {
+ nodes = 1;
+ }
+
+ for (i = 0; i < nodes; i++) {
+ if (nb_numa_nodes) {
+ size = numa_info[i].node_mem;
+ } else {
+ size = ram_size;
+ }
+
+ /*
+ * memory for the node splited into two part
+ * lowram: [base, +gap)
+ * highram: [VIRT_HIGHMEM_BASE, +(len - gap))
+ */
+ if (size >= gap) {
+ fdt_add_memory_node(ms, base, gap, i);
+ size -= gap;
+ base = VIRT_HIGHMEM_BASE;
+ gap = ram_size - VIRT_LOWMEM_SIZE;
+ }
+
+ if (size) {
+ fdt_add_memory_node(ms, base, size, i);
+ base += size;
+ gap -= size;
+ }
+ }
+}
+
static void virt_build_smbios(LoongArchVirtMachineState *lvms)
{
MachineState *ms = MACHINE(lvms);
@@ -1008,10 +1050,10 @@ static void virt_init(MachineState *machine)
lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id;
}
fdt_add_cpu_nodes(lvms);
+ fdt_add_memory_nodes(machine);
/* Node0 memory */
memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
- fdt_add_memory_node(machine, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 0);
memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.node0.lowram",
machine->ram, offset, VIRT_LOWMEM_SIZE);
memory_region_add_subregion(address_space_mem, phyAddr, &lvms->lowmem);
@@ -1025,7 +1067,6 @@ static void virt_init(MachineState *machine)
}
phyAddr = VIRT_HIGHMEM_BASE;
memmap_add_entry(phyAddr, highram_size, 1);
- fdt_add_memory_node(machine, phyAddr, highram_size, 0);
memory_region_init_alias(&lvms->highmem, NULL, "loongarch.node0.highram",
machine->ram, offset, highram_size);
memory_region_add_subregion(address_space_mem, phyAddr, &lvms->highmem);
@@ -1041,7 +1082,6 @@ static void virt_init(MachineState *machine)
offset, numa_info[i].node_mem);
memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
memmap_add_entry(phyAddr, numa_info[i].node_mem, 1);
- fdt_add_memory_node(machine, phyAddr, numa_info[i].node_mem, i);
offset += numa_info[i].node_mem;
phyAddr += numa_info[i].node_mem;
}
--
2.39.1

View File

@ -0,0 +1,120 @@
From 88b12e40d6a479dfb376fb6a91ef24e07a59d33a Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 15 May 2024 17:39:24 +0800
Subject: [PATCH 25/78] hw/loongarch: Refine fwcfg memory map
Memory map table for fwcfg is used for UEFI BIOS, UEFI BIOS uses the first
entry from fwcfg memory map as the first memory HOB, the second memory HOB
will be used if the first memory HOB is used up.
Memory map table for fwcfg does not care about numa node, however in
generic the first memory HOB is part of numa node0, so that runtime
memory of UEFI which is allocated from the first memory HOB is located
at numa node0.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240515093927.3453674-4-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 60 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 57 insertions(+), 3 deletions(-)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 31a2598e7c..7e89921431 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1005,6 +1005,62 @@ static const MemoryRegionOps virt_iocsr_misc_ops = {
},
};
+static void fw_cfg_add_memory(MachineState *ms)
+{
+ hwaddr base, size, ram_size, gap;
+ int nb_numa_nodes, nodes;
+ NodeInfo *numa_info;
+
+ ram_size = ms->ram_size;
+ base = VIRT_LOWMEM_BASE;
+ gap = VIRT_LOWMEM_SIZE;
+ nodes = nb_numa_nodes = ms->numa_state->num_nodes;
+ numa_info = ms->numa_state->nodes;
+ if (!nodes) {
+ nodes = 1;
+ }
+
+ /* add fw_cfg memory map of node0 */
+ if (nb_numa_nodes) {
+ size = numa_info[0].node_mem;
+ } else {
+ size = ram_size;
+ }
+
+ if (size >= gap) {
+ memmap_add_entry(base, gap, 1);
+ size -= gap;
+ base = VIRT_HIGHMEM_BASE;
+ gap = ram_size - VIRT_LOWMEM_SIZE;
+ }
+
+ if (size) {
+ memmap_add_entry(base, size, 1);
+ base += size;
+ }
+
+ if (nodes < 2) {
+ return;
+ }
+
+ /* add fw_cfg memory map of other nodes */
+ size = ram_size - numa_info[0].node_mem;
+ gap = VIRT_LOWMEM_BASE + VIRT_LOWMEM_SIZE;
+ if (base < gap && (base + size) > gap) {
+ /*
+ * memory map for the maining nodes splited into two part
+ * lowram: [base, +(gap - base))
+ * highram: [VIRT_HIGHMEM_BASE, +(size - (gap - base)))
+ */
+ memmap_add_entry(base, gap - base, 1);
+ size -= gap - base;
+ base = VIRT_HIGHMEM_BASE;
+ }
+
+ if (size)
+ memmap_add_entry(base, size, 1);
+}
+
static void virt_init(MachineState *machine)
{
LoongArchCPU *lacpu;
@@ -1051,9 +1107,9 @@ static void virt_init(MachineState *machine)
}
fdt_add_cpu_nodes(lvms);
fdt_add_memory_nodes(machine);
+ fw_cfg_add_memory(machine);
/* Node0 memory */
- memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.node0.lowram",
machine->ram, offset, VIRT_LOWMEM_SIZE);
memory_region_add_subregion(address_space_mem, phyAddr, &lvms->lowmem);
@@ -1066,7 +1122,6 @@ static void virt_init(MachineState *machine)
highram_size = ram_size - VIRT_LOWMEM_SIZE;
}
phyAddr = VIRT_HIGHMEM_BASE;
- memmap_add_entry(phyAddr, highram_size, 1);
memory_region_init_alias(&lvms->highmem, NULL, "loongarch.node0.highram",
machine->ram, offset, highram_size);
memory_region_add_subregion(address_space_mem, phyAddr, &lvms->highmem);
@@ -1081,7 +1136,6 @@ static void virt_init(MachineState *machine)
memory_region_init_alias(nodemem, NULL, ramName, machine->ram,
offset, numa_info[i].node_mem);
memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
- memmap_add_entry(phyAddr, numa_info[i].node_mem, 1);
offset += numa_info[i].node_mem;
phyAddr += numa_info[i].node_mem;
}
--
2.39.1

View File

@ -0,0 +1,110 @@
From 1a7f567308756a2a26020802b24fe7fd106cf84a Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 15 May 2024 17:39:25 +0800
Subject: [PATCH 26/78] hw/loongarch: Refine system dram memory region
For system dram memory region, it is not necessary to use numa node
information. There is only low memory region and high memory region.
Remove numa node information for ddr memory region here, it can reduce
memory region number on LoongArch virt machine.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240515093927.3453674-5-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 53 +++++++++++++++------------------------------
1 file changed, 17 insertions(+), 36 deletions(-)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 7e89921431..96755f5deb 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1065,14 +1065,10 @@ static void virt_init(MachineState *machine)
{
LoongArchCPU *lacpu;
const char *cpu_model = machine->cpu_type;
- ram_addr_t offset = 0;
- ram_addr_t ram_size = machine->ram_size;
- uint64_t highram_size = 0, phyAddr = 0;
MemoryRegion *address_space_mem = get_system_memory();
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
- int nb_numa_nodes = machine->numa_state->num_nodes;
- NodeInfo *numa_info = machine->numa_state->nodes;
int i;
+ hwaddr base, size, ram_size = machine->ram_size;
const CPUArchIdList *possible_cpus;
MachineClass *mc = MACHINE_GET_CLASS(machine);
CPUState *cpu;
@@ -1110,40 +1106,27 @@ static void virt_init(MachineState *machine)
fw_cfg_add_memory(machine);
/* Node0 memory */
- memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.node0.lowram",
- machine->ram, offset, VIRT_LOWMEM_SIZE);
- memory_region_add_subregion(address_space_mem, phyAddr, &lvms->lowmem);
-
- offset += VIRT_LOWMEM_SIZE;
- if (nb_numa_nodes > 0) {
- assert(numa_info[0].node_mem > VIRT_LOWMEM_SIZE);
- highram_size = numa_info[0].node_mem - VIRT_LOWMEM_SIZE;
- } else {
- highram_size = ram_size - VIRT_LOWMEM_SIZE;
+ size = ram_size;
+ base = VIRT_LOWMEM_BASE;
+ if (size > VIRT_LOWMEM_SIZE) {
+ size = VIRT_LOWMEM_SIZE;
}
- phyAddr = VIRT_HIGHMEM_BASE;
- memory_region_init_alias(&lvms->highmem, NULL, "loongarch.node0.highram",
- machine->ram, offset, highram_size);
- memory_region_add_subregion(address_space_mem, phyAddr, &lvms->highmem);
-
- /* Node1 - Nodemax memory */
- offset += highram_size;
- phyAddr += highram_size;
-
- for (i = 1; i < nb_numa_nodes; i++) {
- MemoryRegion *nodemem = g_new(MemoryRegion, 1);
- g_autofree char *ramName = g_strdup_printf("loongarch.node%d.ram", i);
- memory_region_init_alias(nodemem, NULL, ramName, machine->ram,
- offset, numa_info[i].node_mem);
- memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
- offset += numa_info[i].node_mem;
- phyAddr += numa_info[i].node_mem;
+
+ memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.lowram",
+ machine->ram, base, size);
+ memory_region_add_subregion(address_space_mem, base, &lvms->lowmem);
+ base += size;
+ if (ram_size - size) {
+ base = VIRT_HIGHMEM_BASE;
+ memory_region_init_alias(&lvms->highmem, NULL, "loongarch.highram",
+ machine->ram, VIRT_LOWMEM_BASE + size, ram_size - size);
+ memory_region_add_subregion(address_space_mem, base, &lvms->highmem);
+ base += ram_size - size;
}
/* initialize device memory address space */
if (machine->ram_size < machine->maxram_size) {
ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
- hwaddr device_mem_base;
if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
error_report("unsupported amount of memory slots: %"PRIu64,
@@ -1157,9 +1140,7 @@ static void virt_init(MachineState *machine)
"%d bytes", TARGET_PAGE_SIZE);
exit(EXIT_FAILURE);
}
- /* device memory base is the top of high memory address. */
- device_mem_base = ROUND_UP(VIRT_HIGHMEM_BASE + highram_size, 1 * GiB);
- machine_memory_devices_init(machine, device_mem_base, device_mem_size);
+ machine_memory_devices_init(machine, base, device_mem_size);
}
/* load the BIOS image. */
--
2.39.1

View File

@ -0,0 +1,39 @@
From 94fa0b75c098ca6fc987f103760c1e07695ffd1a Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Fri, 23 Aug 2024 15:30:50 +0800
Subject: [PATCH 34/78] hw/loongarch: Remove default enable with VIRTIO_VGA
device
For virtio VGA deivce libvirt will select VIRTIO_VGA firstly rather than
VIRTIO_GPU, VIRTIO_VGA device supports frame buffer however it requires
legacy VGA compatible support. Frame buffer area 0xa0000 -- 0xc0000
conflicts with low memory area 0 -- 0x10000000.
Here remove default support for VIRTIO_VGA device, VIRTIO_GPU is prefered
on LoongArch system. For frame buffer video card support, standard VGA can
be used.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240823073050.2619484-1-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/Kconfig | 1 -
1 file changed, 1 deletion(-)
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index b2a3adb7dc..40944a8365 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -4,7 +4,6 @@ config LOONGARCH_VIRT
depends on LOONGARCH64
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
- imply VIRTIO_VGA
imply PCI_DEVICES
imply NVDIMM
imply TPM_TIS_SYSBUS
--
2.39.1

View File

@ -0,0 +1,46 @@
From 858f16ea09fbbac9966ca73b6b86d290a36be6f5 Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 15 May 2024 17:39:26 +0800
Subject: [PATCH 27/78] hw/loongarch: Remove minimum and default memory size
Some qtest test cases such as numa use default memory size of generic
machine class, which is 128M by fault.
Here generic default memory size is used, and also remove minimum memory
size which is 1G originally.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240515093927.3453674-6-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 96755f5deb..11ba879e52 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1077,10 +1077,6 @@ static void virt_init(MachineState *machine)
cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
}
- if (ram_size < 1 * GiB) {
- error_report("ram_size must be greater than 1G.");
- exit(1);
- }
create_fdt(lvms);
/* Create IOCSR space */
@@ -1369,7 +1365,6 @@ static void virt_class_init(ObjectClass *oc, void *data)
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
mc->init = virt_init;
- mc->default_ram_size = 1 * GiB;
mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
mc->default_ram_id = "loongarch.ram";
mc->max_cpus = LOONGARCH_MAX_CPUS;
--
2.39.1

View File

@ -0,0 +1,188 @@
From 8e2986a6fc5dda2afbe33f723efdacd01f147b7a Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 8 May 2024 11:11:06 +0800
Subject: [PATCH 19/78] hw/loongarch: Rename LOONGARCH_MACHINE with
LOONGARCH_VIRT_MACHINE
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
On LoongArch system, there is only virt machine type now, name
LOONGARCH_MACHINE is confused, rename it with LOONGARCH_VIRT_MACHINE.
Machine name about Other real hw boards can be added in future.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20240508031110.2507477-2-maobibo@loongson.cn>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/acpi-build.c | 8 ++++----
hw/loongarch/boot.c | 2 +-
hw/loongarch/virt.c | 19 +++++++++----------
include/hw/loongarch/virt.h | 4 ++--
4 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index f990405d04..fff3497c62 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -167,7 +167,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
int i, arch_id, node_id;
uint64_t mem_len, mem_base;
int nb_numa_nodes = machine->numa_state->num_nodes;
- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(lams);
const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
@@ -279,7 +279,7 @@ static void
build_la_ged_aml(Aml *dsdt, MachineState *machine)
{
uint32_t event;
- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
HOTPLUG_HANDLER(lams->acpi_ged),
@@ -391,7 +391,7 @@ static void
build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
{
Aml *dsdt, *scope, *pkg;
- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
.oem_table_id = lams->oem_table_id };
@@ -421,7 +421,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
{
- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
GArray *table_offsets;
AcpiFadtData fadt_data;
unsigned facs, rsdt, dsdt;
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 03f6301a77..e37512729d 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -319,7 +319,7 @@ static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
{
- LoongArchMachineState *lams = LOONGARCH_MACHINE(ms);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(ms);
int i;
/* register reset function */
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 76b36539e2..cca220cb5b 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -970,7 +970,7 @@ static void loongarch_init(MachineState *machine)
ram_addr_t ram_size = machine->ram_size;
uint64_t highram_size = 0, phyAddr = 0;
MemoryRegion *address_space_mem = get_system_memory();
- LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
int nb_numa_nodes = machine->numa_state->num_nodes;
NodeInfo *numa_info = machine->numa_state->nodes;
int i;
@@ -1121,7 +1121,7 @@ bool loongarch_is_acpi_enabled(LoongArchMachineState *lams)
static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj);
OnOffAuto acpi = lams->acpi;
visit_type_OnOffAuto(v, name, &acpi, errp);
@@ -1130,14 +1130,14 @@ static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name,
static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj);
visit_type_OnOffAuto(v, name, &lams->acpi, errp);
}
static void loongarch_machine_initfn(Object *obj)
{
- LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj);
if (tcg_enabled()) {
lams->veiointc = ON_OFF_AUTO_OFF;
@@ -1172,7 +1172,7 @@ static void virt_machine_device_pre_plug(HotplugHandler *hotplug_dev,
static void virt_mem_unplug_request(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev);
/* the acpi ged is always exist */
hotplug_handler_unplug_request(HOTPLUG_HANDLER(lams->acpi_ged), dev,
@@ -1190,7 +1190,7 @@ static void virt_machine_device_unplug_request(HotplugHandler *hotplug_dev,
static void virt_mem_unplug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev);
hotplug_handler_unplug(HOTPLUG_HANDLER(lams->acpi_ged), dev, errp);
pc_dimm_unplug(PC_DIMM(dev), MACHINE(lams));
@@ -1208,7 +1208,7 @@ static void virt_machine_device_unplug(HotplugHandler *hotplug_dev,
static void virt_mem_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev);
pc_dimm_plug(PC_DIMM(dev), MACHINE(lams));
hotplug_handler_plug(HOTPLUG_HANDLER(lams->acpi_ged),
@@ -1218,7 +1218,7 @@ static void virt_mem_plug(HotplugHandler *hotplug_dev,
static void loongarch_machine_device_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+ LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev);
MachineClass *mc = MACHINE_GET_CLASS(lams);
if (device_is_dynamic_sysbus(mc, dev)) {
@@ -1300,7 +1300,6 @@ static void loongarch_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
- mc->desc = "Loongson-3A5000 LS7A1000 machine";
mc->init = loongarch_init;
mc->default_ram_size = 1 * GiB;
mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
@@ -1341,7 +1340,7 @@ static void loongarch_class_init(ObjectClass *oc, void *data)
static const TypeInfo loongarch_machine_types[] = {
{
- .name = TYPE_LOONGARCH_MACHINE,
+ .name = TYPE_LOONGARCH_VIRT_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(LoongArchMachineState),
.class_init = loongarch_class_init,
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 36158c758f..0509b9a9af 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -66,8 +66,8 @@ struct LoongArchMachineState {
struct loongarch_boot_info bootinfo;
};
-#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt")
-OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_MACHINE)
+#define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
+OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_VIRT_MACHINE)
bool loongarch_is_acpi_enabled(LoongArchMachineState *lams);
void loongarch_acpi_setup(LoongArchMachineState *lams);
#endif
--
2.39.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
From b7217c8f9b3f1d611485bad1263e109484a743e3 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Wed, 30 Oct 2024 09:23:59 +0800
Subject: [PATCH 77/78] hw/loongarch/boot: Use warn_report when no kernel
filename
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When we run “qemu-system-loongarch64 -qmp stdio -vnc none -S”,
we get an error message “Need kernel filename” and then we can't use qmp cmd to query some information.
So, we just throw a warning and then the cpus starts running from address VIRT_FLASH0_BASE.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20241030012359.4040817-1-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,35 @@
From f9cc704bbcf8bb8a06095289921dc88944d0fe94 Mon Sep 17 00:00:00 2001
From: Dmitry Frolov <frolov@swemel.ru>
Date: Fri, 28 Jun 2024 15:39:10 +0300
Subject: [PATCH 30/78] hw/loongarch/boot.c: fix out-of-bound reading
memcpy() is trying to READ 512 bytes from memory,
pointed by info->kernel_cmdline,
which was (presumable) allocated by g_strdup("");
Found with ASAN, making check with enabled sanitizers.
Signed-off-by: Dmitry Frolov <frolov@swemel.ru>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240628123910.577740-1-frolov@swemel.ru>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/boot.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index b8e1aa18d5..cb668703bd 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -163,7 +163,7 @@ static void init_cmdline(struct loongarch_boot_info *info, void *p, void *start)
info->a0 = 1;
info->a1 = cmdline_addr;
- memcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE);
+ g_strlcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE);
}
static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
--
2.39.1

View File

@ -0,0 +1,197 @@
From 4a74147e1b2e276eb2ad2855bafc3c0136bc18a3 Mon Sep 17 00:00:00 2001
From: gaosong <gaosong@loongson.cn>
Date: Sun, 8 Sep 2024 22:34:57 +0800
Subject: [PATCH 76/78] hw/loongarch: clean code
remove some unused code
Signed-off-by: gaosong <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
target/loongarch/kvm/kvm.c | 103 ---------------------------
target/loongarch/kvm/kvm_loongarch.h | 2 -
target/loongarch/machine.c | 20 ------
3 files changed, 125 deletions(-)
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index ab1ea3d4fd..0acdd5c4c1 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -684,53 +684,6 @@ static int kvm_check_cpucfg2(CPUState *cs)
return ret;
}
-static int kvm_check_cpucfg6(CPUState *cs)
-{
- int ret;
- uint64_t val;
- struct kvm_device_attr attr = {
- .group = KVM_LOONGARCH_VCPU_CPUCFG,
- .attr = 6,
- .addr = (uint64_t)&val,
- };
- LoongArchCPU *cpu = LOONGARCH_CPU(cs);
- CPULoongArchState *env = &cpu->env;
-
- ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
- if (!ret) {
- kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
-
- if (FIELD_EX32(env->cpucfg[6], CPUCFG6, PMP)) {
- /* Check PMP */
- if (!FIELD_EX32(val, CPUCFG6, PMP)) {
- error_report("'pmu' feature not supported by KVM on this host"
- " Please disable 'pmu' with "
- "'... -cpu XXX,pmu=off ...'\n");
- exit(EXIT_FAILURE);
- }
- /* Check PMNUM */
- int guest_pmnum = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMNUM);
- int host_pmnum = FIELD_EX32(val, CPUCFG6, PMNUM);
- if (guest_pmnum > host_pmnum){
- warn_report("The guest pmnum %d larger than KVM support %d\n",
- guest_pmnum, host_pmnum);
- env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6,
- PMNUM, host_pmnum);
- }
- /* Check PMBITS */
- int guest_pmbits = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMBITS);
- int host_pmbits = FIELD_EX32(val, CPUCFG6, PMBITS);
- if (guest_pmbits != host_pmbits) {
- warn_report("The host not support PMBITS %d\n", guest_pmbits);
- env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6,
- PMBITS, host_pmbits);
- }
- }
- }
-
- return ret;
-}
-
static int kvm_loongarch_put_cpucfg(CPUState *cs)
{
int i, ret = 0;
@@ -745,12 +698,6 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs)
return ret;
}
}
- if (i == 6) {
- ret = kvm_check_cpucfg6(cs);
- if (ret) {
- return ret;
- }
- }
val = env->cpucfg[i];
ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
if (ret < 0) {
@@ -760,56 +707,6 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs)
return ret;
}
-int kvm_loongarch_put_pvtime(LoongArchCPU *cpu)
-{
- CPULoongArchState *env = &cpu->env;
- int err;
- struct kvm_device_attr attr = {
- .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL,
- .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA,
- .addr = (uint64_t)&env->st.guest_addr,
- };
-
- err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr);
- if (err != 0) {
- /* It's ok even though kvm has not such attr */
- return 0;
- }
-
- err = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_DEVICE_ATTR, attr);
- if (err != 0) {
- error_report("PVTIME IPA: KVM_SET_DEVICE_ATTR: %s", strerror(-err));
- return err;
- }
-
- return 0;
-}
-
-int kvm_loongarch_get_pvtime(LoongArchCPU *cpu)
-{
- CPULoongArchState *env = &cpu->env;
- int err;
- struct kvm_device_attr attr = {
- .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL,
- .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA,
- .addr = (uint64_t)&env->st.guest_addr,
- };
-
- err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr);
- if (err != 0) {
- /* It's ok even though kvm has not such attr */
- return 0;
- }
-
- err = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_DEVICE_ATTR, attr);
- if (err != 0) {
- error_report("PVTIME IPA: KVM_GET_DEVICE_ATTR: %s", strerror(-err));
- return err;
- }
-
- return 0;
-}
-
int kvm_arch_get_registers(CPUState *cs)
{
int ret;
diff --git a/target/loongarch/kvm/kvm_loongarch.h b/target/loongarch/kvm/kvm_loongarch.h
index 8482f9308d..1051a341ec 100644
--- a/target/loongarch/kvm/kvm_loongarch.h
+++ b/target/loongarch/kvm/kvm_loongarch.h
@@ -11,8 +11,6 @@
#define QEMU_KVM_LOONGARCH_H
int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level);
-int kvm_loongarch_put_pvtime(LoongArchCPU *cpu);
-int kvm_loongarch_get_pvtime(LoongArchCPU *cpu);
void kvm_arch_reset_vcpu(CPUState *cs);
#endif
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index fd69ea05dc..57abdddc09 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -112,24 +112,6 @@ static const VMStateDescription vmstate_lasx = {
},
};
-static int cpu_post_load(void *opaque, int version_id)
-{
-#ifdef CONFIG_KVM
- LoongArchCPU *cpu = opaque;
- kvm_loongarch_put_pvtime(cpu);
-#endif
- return 0;
-}
-
-static int cpu_pre_save(void *opaque)
-{
-#ifdef CONFIG_KVM
- LoongArchCPU *cpu = opaque;
- kvm_loongarch_get_pvtime(cpu);
-#endif
- return 0;
-}
-
static bool lbt_needed(void *opaque)
{
LoongArchCPU *cpu = opaque;
@@ -190,8 +172,6 @@ const VMStateDescription vmstate_loongarch_cpu = {
.name = "cpu",
.version_id = 3,
.minimum_version_id = 3,
- .post_load = cpu_post_load,
- .pre_save = cpu_pre_save,
.fields = (const VMStateField[]) {
VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32),
VMSTATE_UINTTL(env.pc, LoongArchCPU),
--
2.39.1

View File

@ -0,0 +1,91 @@
From ed42940a2d943fd0e666e46bbc9b599b9ed1bd75 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:45 +0800
Subject: [PATCH 10/78] hw/loongarch: fdt adds Extend I/O Interrupt Controller
fdt adds Extend I/O Interrupt Controller,
we use 'loongson,ls2k2000-eiointc'.
See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-eiointc.c
https://lore.kernel.org/r/764e02d924094580ac0f1d15535f4b98308705c6.1683279769.git.zhoubinbin@loongson.cn
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-12-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,69 @@
From cd506fbf0d9a00aa0f25de1e7bd26ad4335c8257 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:44 +0800
Subject: [PATCH 09/78] hw/loongarch: fdt adds cpu interrupt controller node
fdt adds cpu interrupt controller node,
we use 'loongson,cpu-interrupt-controller'.
See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongarch-cpu.c
https://lore.kernel.org/r/20221114113824.1880-2-liupeibao@loongson.cn
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-11-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,93 @@
From ea34d3896abfaf67cdf7fdb3cb205cc5a0e2e708 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:47 +0800
Subject: [PATCH 12/78] hw/loongarch: fdt adds pch_msi Controller
fdt adds pch msi controller, we use 'loongson,pch-msi-1.0'.
See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-msi.c
https://lore.kernel.org/r/20200528152757.1028711-6-jiaxun.yang@flygoat.com
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-14-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,90 @@
From 78222abb3bde044b4520f23c6fc2f0f0bd805d2a Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:46 +0800
Subject: [PATCH 11/78] hw/loongarch: fdt adds pch_pic Controller
fdt adds pch pic controller, we use 'loongson,pch-pic-1.0'
See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-pic.c
https://lore.kernel.org/r/20200528152757.1028711-4-jiaxun.yang@flygoat.com
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-13-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,137 @@
From 1325effbd595781b9ab75dceab9f87944156c606 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:48 +0800
Subject: [PATCH 13/78] hw/loongarch: fdt adds pcie irq_map node
This patch adds pcie irq_map node for FDT.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-15-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,67 @@
From e87697c72641ab2209d4004f573f47283d118235 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Fri, 26 Apr 2024 17:15:49 +0800
Subject: [PATCH 14/78] hw/loongarch: fdt remove unused irqchip node
This patch removes the unused fdt irqchip node.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240426091551.2397867-16-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,51 @@
From f3f7b49a8a323ebfe2be176985336aaf2c97c6c2 Mon Sep 17 00:00:00 2001
From: gaosong <gaosong@loongson.cn>
Date: Mon, 9 Sep 2024 04:14:49 +0800
Subject: [PATCH 78/78] hw/loongarch: fix cpu hotplug reset
Signed-off-by: gaosong <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/boot.c | 2 +-
hw/loongarch/virt.c | 1 +
include/hw/loongarch/virt.h | 1 +
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index f258eefe9a..53dcefbb55 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -216,7 +216,7 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info)
return kernel_entry;
}
-static void reset_load_elf(void *opaque)
+void reset_load_elf(void *opaque)
{
LoongArchCPU *cpu = opaque;
CPULoongArchState *env = &cpu->env;
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 5b0468f6cb..0c24e632bb 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1494,6 +1494,7 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev,
env = &(cpu->env);
env->address_space_iocsr = &lvms->as_iocsr;
+ qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(cs->cpu_index)));
env->ipistate = lvms->ipi;
if (!(kvm_enabled() && kvm_irqchip_in_kernel())) {
/* connect ipi irq to cpu irq, logic cpu index used here */
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 168b40c31b..a79ad41663 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -86,4 +86,5 @@ struct LoongArchVirtMachineState {
#define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchVirtMachineState, LOONGARCH_VIRT_MACHINE)
void loongarch_acpi_setup(LoongArchVirtMachineState *lvms);
+void reset_load_elf(void *opaque);
#endif
--
2.39.1

View File

@ -0,0 +1,113 @@
From 5e4d612de23539499b9a22986bebe9a3007edae1 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 7 May 2024 16:51:35 +0200
Subject: [PATCH 18/78] hw/loongarch: move memory map to boot.c
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Ensure that it can be used even if virt.c is not included in the build, as
is the case for --without-default-devices.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Message-ID: <20240507145135.270803-1-pbonzini@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
.gitlab-ci.d/buildtest.yml | 5 +++--
hw/loongarch/boot.c | 3 +++
hw/loongarch/virt.c | 3 ---
include/hw/loongarch/boot.h | 10 ++++++++++
include/hw/loongarch/virt.h | 10 ----------
5 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml
index 3fb99e79e9..983c3c132e 100644
--- a/.gitlab-ci.d/buildtest.yml
+++ b/.gitlab-ci.d/buildtest.yml
@@ -579,8 +579,9 @@ build-tci:
- make check-tcg
# Check our reduced build configurations
-# requires libfdt: aarch64, arm, i386, loongarch64, x86_64
-# does not build without boards: i386, loongarch64, x86_64
+# requires libfdt: aarch64, arm, i386, loongarch64, microblaze, microblazeel,
+# mips64el, or1k, ppc, ppc64, riscv32, riscv64, rx, x86_64
+# does not build without boards: i386, s390x, sh4, sh4eb, x86_64
build-without-defaults:
extends: .native_build_job_template
needs:
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 7d1630b2e7..03f6301a77 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,9 @@
#include "sysemu/reset.h"
#include "sysemu/qtest.h"
+struct memmap_entry *memmap_table;
+unsigned memmap_entries;
+
ram_addr_t initrd_offset;
uint64_t initrd_size;
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 0972ebd150..76b36539e2 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -543,9 +543,6 @@ static void virt_powerdown_req(Notifier *notifier, void *opaque)
acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS);
}
-struct memmap_entry *memmap_table;
-unsigned memmap_entries;
-
static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
{
/* Ensure there are no duplicate entries. */
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 4ebcc89dcf..b3b870df1f 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -104,6 +104,16 @@ struct loongarch_boot_info {
uint64_t a0, a1, a2;
};
+extern struct memmap_entry *memmap_table;
+extern unsigned memmap_entries;
+
+struct memmap_entry {
+ uint64_t address;
+ uint64_t length;
+ uint32_t type;
+ uint32_t reserved;
+};
+
void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info);
#endif /* HW_LOONGARCH_BOOT_H */
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 673b57aa2b..36158c758f 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -37,16 +37,6 @@
#define FDT_BASE 0x100000
-extern struct memmap_entry *memmap_table;
-extern unsigned memmap_entries;
-
-struct memmap_entry {
- uint64_t address;
- uint64_t length;
- uint32_t type;
- uint32_t reserved;
-};
-
struct LoongArchMachineState {
/*< private >*/
MachineState parent_obj;
--
2.39.1

View File

@ -0,0 +1,278 @@
From 8d440efd992fd6be0aca55118a9b60c224f6eade Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 23 Oct 2024 15:13:10 +0800
Subject: [PATCH 69/78] hw/loongarch/virt: Add CPU topology support
Add topological relationships for Loongarch VCPU and initialize
topology member variables. Also physical cpu id calculation
method comes from its topo information.
Co-developed-by: Xianglai Li <lixianglai@loongson.cn>
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Message-ID: <20241023071312.881866-2-maobibo@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,84 @@
From fa276847efb3fd47a730d279f1b14705fe3991b1 Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 18 Sep 2024 09:42:06 +0800
Subject: [PATCH 39/78] hw/loongarch/virt: Add FDT table support with acpi ged
pm register
ACPI ged is used for power management on LoongArch virt platform, in
general it is parsed from acpi table. However if system boot directly from
elf kernel, no UEFI bios is provided and acpi table cannot be used also.
Here acpi ged pm register is exposed with FDT table, it is compatbile
with syscon method in FDT table, only that acpi ged pm register is accessed
with 8-bit mode, rather with 32-bit mode.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Tested-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240918014206.2165821-3-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 9f47107379..9510aa7a7e 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -281,6 +281,44 @@ static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms,
g_free(nodename);
}
+static void fdt_add_ged_reset(LoongArchVirtMachineState *lvms)
+{
+ char *name;
+ uint32_t ged_handle;
+ MachineState *ms = MACHINE(lvms);
+ hwaddr base = VIRT_GED_REG_ADDR;
+ hwaddr size = ACPI_GED_REG_COUNT;
+
+ ged_handle = qemu_fdt_alloc_phandle(ms->fdt);
+ name = g_strdup_printf("/ged@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon");
+ qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, base, 0x0, size);
+ /* 8 bit registers */
+ qemu_fdt_setprop_cell(ms->fdt, name, "reg-shift", 0);
+ qemu_fdt_setprop_cell(ms->fdt, name, "reg-io-width", 1);
+ qemu_fdt_setprop_cell(ms->fdt, name, "phandle", ged_handle);
+ ged_handle = qemu_fdt_get_phandle(ms->fdt, name);
+ g_free(name);
+
+ name = g_strdup_printf("/reboot");
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot");
+ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle);
+ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_RESET);
+ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_RESET_VALUE);
+ g_free(name);
+
+ name = g_strdup_printf("/poweroff");
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff");
+ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle);
+ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_SLEEP_CTL);
+ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_SLP_EN |
+ (ACPI_GED_SLP_TYP_S5 << ACPI_GED_SLP_TYP_POS));
+ g_free(name);
+}
+
static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
uint32_t *pch_pic_phandle, hwaddr base,
int irq, bool chosen)
@@ -739,6 +777,7 @@ static void virt_devices_init(DeviceState *pch_pic,
qdev_get_gpio_in(pch_pic,
VIRT_RTC_IRQ - VIRT_GSI_BASE));
fdt_add_rtc_node(lvms, pch_pic_phandle);
+ fdt_add_ged_reset(lvms);
/* acpi ged */
lvms->acpi_ged = create_acpi_ged(pch_pic, lvms);
--
2.39.1

View File

@ -0,0 +1,346 @@
From 212ea93178ad1e65e625ec6942ee9aff93dd5321 Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 23 Oct 2024 15:13:11 +0800
Subject: [PATCH 70/78] hw/loongarch/virt: Add basic CPU plug support
Implement interface for cpu hotplug function, and enable cpu hotplug
feature on virt machine.
Co-developed-by: Xianglai Li <lixianglai@loongson.cn>
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Message-ID: <20241023071312.881866-3-maobibo@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,46 @@
From 080ca7865257d70b6be671cbc17a97c5ebffbd68 Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Fri, 13 Sep 2024 17:52:02 +0800
Subject: [PATCH 38/78] hw/loongarch/virt: Add description for virt machine
type
The description about virt machine type is removed by mistake, add
new description here. Here is output result with command
"./qemu-system-loongarch64 -M help"
Supported machines are:
none empty machine
virt QEMU LoongArch Virtual Machine (default)
x-remote Experimental remote machine
Without the patch, it shows as follows:
Supported machines are:
none empty machine
virt (null) (default)
x-remote Experimental remote machine
Fixes: ef2f11454c(hw/loongarch/virt: Replace Loongson IPI with LoongArch IPI)
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 79b16953d2..9f47107379 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1383,6 +1383,7 @@ static void virt_class_init(ObjectClass *oc, void *data)
mc->init = virt_init;
mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
mc->default_ram_id = "loongarch.ram";
+ mc->desc = "QEMU LoongArch Virtual Machine";
mc->max_cpus = LOONGARCH_MAX_CPUS;
mc->is_default = 1;
mc->default_kernel_irqchip_split = false;
--
2.39.1

View File

@ -0,0 +1,33 @@
From cbd62b91ecdd0ec5f4ccb4c726e0adcdd2808270 Mon Sep 17 00:00:00 2001
From: Susanooo <zhangchujun_yewu@cmss.chinamobile.com>
Date: Thu, 24 Oct 2024 10:34:17 +0800
Subject: [PATCH] hw/loongarch/virt: Remove unnecessary 'cpu.h' inclusion
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20240927213254.17552-2-philmd@linaro.org>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: zhangchujun <zhangchujun_yewu@cmss.chinamobile.com>
---
include/hw/loongarch/virt.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 99447fd1d6..17a792e596 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -8,7 +8,6 @@
#ifndef HW_LOONGARCH_H
#define HW_LOONGARCH_H
-#include "target/loongarch/cpu.h"
#include "hw/boards.h"
#include "qemu/queue.h"
#include "hw/intc/loongarch_ipi.h"
--
2.41.0.windows.1

View File

@ -0,0 +1,59 @@
From 5e0ec61ac98a025124912fc47552550b471ab638 Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 12 Jun 2024 11:36:37 +0800
Subject: [PATCH 32/78] hw/loongarch/virt: Remove unused assignment
There is abuse usage about local variable gap. Remove
duplicated assignment and solve Coverity reported error.
Resolves: Coverity CID 1546441
Fixes: 3cc451cbce ("hw/loongarch: Refine fwcfg memory map")
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240612033637.167787-1-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 12816c6023..a7283e6755 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1034,7 +1034,6 @@ static void fw_cfg_add_memory(MachineState *ms)
memmap_add_entry(base, gap, 1);
size -= gap;
base = VIRT_HIGHMEM_BASE;
- gap = ram_size - VIRT_LOWMEM_SIZE;
}
if (size) {
@@ -1047,17 +1046,17 @@ static void fw_cfg_add_memory(MachineState *ms)
}
/* add fw_cfg memory map of other nodes */
- size = ram_size - numa_info[0].node_mem;
- gap = VIRT_LOWMEM_BASE + VIRT_LOWMEM_SIZE;
- if (base < gap && (base + size) > gap) {
+ if (numa_info[0].node_mem < gap && ram_size > gap) {
/*
* memory map for the maining nodes splited into two part
- * lowram: [base, +(gap - base))
- * highram: [VIRT_HIGHMEM_BASE, +(size - (gap - base)))
+ * lowram: [base, +(gap - numa_info[0].node_mem))
+ * highram: [VIRT_HIGHMEM_BASE, +(ram_size - gap))
*/
- memmap_add_entry(base, gap - base, 1);
- size -= gap - base;
+ memmap_add_entry(base, gap - numa_info[0].node_mem, 1);
+ size = ram_size - gap;
base = VIRT_HIGHMEM_BASE;
+ } else {
+ size = ram_size - numa_info[0].node_mem;
}
if (size)
--
2.39.1

View File

@ -0,0 +1,143 @@
From a3728999125cd9fc9e3e841b66a1677663933c27 Mon Sep 17 00:00:00 2001
From: Bibo Mao <maobibo@loongson.cn>
Date: Wed, 23 Oct 2024 15:13:12 +0800
Subject: [PATCH 71/78] hw/loongarch/virt: Update the ACPI table for hotplug
cpu
On LoongArch virt machine, ACPI GED hardware is used for cpu
hotplug, here cpu hotplug support feature is added on GED device,
also cpu scan and reject method is added about CPU device in
DSDT table.
Co-developed-by: Xianglai Li <lixianglai@loongson.cn>
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Message-ID: <20241023071312.881866-4-maobibo@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,77 @@
From b63b7b0b6c9bed8e1a316f3838aab7db2e8f2037 Mon Sep 17 00:00:00 2001
From: Song Gao <gaosong@loongson.cn>
Date: Tue, 28 May 2024 16:38:54 +0800
Subject: [PATCH 29/78] hw/loongarch/virt: Use MemTxAttrs interface for misc
ops
Use MemTxAttrs interface read_with_attrs/write_with_attrs
for virt_iocsr_misc_ops.
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-Id: <20240528083855.1912757-3-gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@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.39.1

View File

@ -0,0 +1,66 @@
From 573f3bec8137caf829457620380d794165c96a92 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Thu, 5 Sep 2024 17:33:16 +0200
Subject: [PATCH 36/78] hw/loongarch: virt: pass random seed to fdt
If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to
initialize early. Set this using the usual guest random number
generation function.
This is the same procedure that's done in b91b6b5a2c ("hw/microblaze:
pass random seed to fdt"), e4b4f0b71c ("hw/riscv: virt: pass random seed
to fdt"), c6fe3e6b4c ("hw/openrisc: virt: pass random seed to fdt"),
67f7e426e5 ("hw/i386: pass RNG seed via setup_data entry"), c287941a4d
("hw/rx: pass random seed to fdt"), 5e19cc68fb ("hw/mips: boston: pass
random seed to fdt"), 6b23a67916 ("hw/nios2: virt: pass random seed to fdt")
c4b075318e ("hw/ppc: pass random seed to fdt"), and 5242876f37
("hw/arm/virt: dt: add rng-seed property").
These earlier commits later were amended to rerandomize the RNG seed on
snapshot load, but the LoongArch code somehow already does that, despite
not having this patch here, presumably due to some lucky copy and
pasting.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240905153316.2038769-1-Jason@zx2c4.com>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/virt.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index a6e9309064..79b16953d2 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -49,6 +49,7 @@
#include "hw/block/flash.h"
#include "hw/virtio/virtio-iommu.h"
#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
{
@@ -304,6 +305,7 @@ static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
static void create_fdt(LoongArchVirtMachineState *lvms)
{
MachineState *ms = MACHINE(lvms);
+ uint8_t rng_seed[32];
ms->fdt = create_device_tree(&lvms->fdt_size);
if (!ms->fdt) {
@@ -317,6 +319,10 @@ static void create_fdt(LoongArchVirtMachineState *lvms)
qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
qemu_fdt_add_subnode(ms->fdt, "/chosen");
+
+ /* Pass seed to RNG */
+ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
+ qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
}
static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms)
--
2.39.1

View File

@ -0,0 +1,172 @@
From 04895c794652c5da1ece0cad82741bed9aa8ad02 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sat, 7 Sep 2024 16:34:39 +0200
Subject: [PATCH 35/78] hw/loongarch: virt: support up to 4 serial ports
In order to support additional channels of communication using
`-serial`, add several serial ports, up to the standard 4 generally
supported by the 8250 driver.
Fixed: https://lore.kernel.org/all/20240907143439.2792924-1-Jason@zx2c4.com/
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Tested-by: Bibo Mao <maobibo@loongson.cn>
[gaosong: ACPI uart need't reverse order]
Signed-off-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240907143439.2792924-1-Jason@zx2c4.com>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/loongarch/acpi-build.c | 23 +++++++++++++++--------
hw/loongarch/virt.c | 27 +++++++++++++++++----------
include/hw/pci-host/ls7a.h | 9 +++++----
3 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 1a9d25fc51..33a92223d8 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -31,6 +31,7 @@
#include "hw/acpi/generic_event_device.h"
#include "hw/pci-host/gpex.h"
+#include "sysemu/sysemu.h"
#include "sysemu/tpm.h"
#include "hw/platform-bus.h"
#include "hw/acpi/aml-build.h"
@@ -252,23 +253,27 @@ struct AcpiBuildState {
MemoryRegion *linker_mr;
} AcpiBuildState;
-static void build_uart_device_aml(Aml *table)
+static void build_uart_device_aml(Aml *table, int index)
{
Aml *dev;
Aml *crs;
Aml *pkg0, *pkg1, *pkg2;
- uint32_t uart_irq = VIRT_UART_IRQ;
-
- Aml *scope = aml_scope("_SB");
- dev = aml_device("COMA");
+ Aml *scope;
+ uint32_t uart_irq;
+ uint64_t base;
+
+ uart_irq = VIRT_UART_IRQ + index;
+ base = VIRT_UART_BASE + index * VIRT_UART_SIZE;
+ scope = aml_scope("_SB");
+ dev = aml_device("COM%d", index);
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
- aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(index)));
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
crs = aml_resource_template();
aml_append(crs,
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
AML_NON_CACHEABLE, AML_READ_WRITE,
- 0, VIRT_UART_BASE, VIRT_UART_BASE + VIRT_UART_SIZE - 1,
+ 0, base, base + VIRT_UART_SIZE - 1,
0, VIRT_UART_SIZE));
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
AML_SHARED, &uart_irq, 1));
@@ -401,6 +406,7 @@ static void acpi_dsdt_add_tpm(Aml *scope, LoongArchVirtMachineState *vms)
static void
build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
{
+ int i;
Aml *dsdt, *scope, *pkg;
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lvms->oem_id,
@@ -408,7 +414,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
acpi_table_begin(&table, table_data);
dsdt = init_aml_allocator();
- build_uart_device_aml(dsdt);
+ for (i = 0; i < VIRT_UART_COUNT; i++)
+ build_uart_device_aml(dsdt, i);
build_pci_device_aml(dsdt, lvms);
build_la_ged_aml(dsdt, machine);
build_flash_aml(dsdt, lvms);
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index a7283e6755..a6e9309064 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -281,10 +281,10 @@ static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms,
}
static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
- uint32_t *pch_pic_phandle)
+ uint32_t *pch_pic_phandle, hwaddr base,
+ int irq, bool chosen)
{
char *nodename;
- hwaddr base = VIRT_UART_BASE;
hwaddr size = VIRT_UART_SIZE;
MachineState *ms = MACHINE(lvms);
@@ -293,9 +293,9 @@ static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a");
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000);
- qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
- VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4);
+ if (chosen)
+ qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0x4);
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
*pch_pic_phandle);
g_free(nodename);
@@ -706,11 +706,18 @@ static void virt_devices_init(DeviceState *pch_pic,
/* Add pcie node */
fdt_add_pcie_node(lvms, pch_pic_phandle, pch_msi_phandle);
- serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0,
- qdev_get_gpio_in(pch_pic,
- VIRT_UART_IRQ - VIRT_GSI_BASE),
- 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
- fdt_add_uart_node(lvms, pch_pic_phandle);
+ /*
+ * Create uart fdt node in reverse order so that they appear
+ * in the finished device tree lowest address first
+ */
+ for (i = VIRT_UART_COUNT; i --> 0;) {
+ hwaddr base = VIRT_UART_BASE + i * VIRT_UART_SIZE;
+ int irq = VIRT_UART_IRQ + i - VIRT_GSI_BASE;
+ serial_mm_init(get_system_memory(), base, 0,
+ qdev_get_gpio_in(pch_pic, irq),
+ 115200, serial_hd(i), DEVICE_LITTLE_ENDIAN);
+ fdt_add_uart_node(lvms, pch_pic_phandle, base, irq, i == 0);
+ }
/* Network init */
for (i = 0; i < nb_nics; i++) {
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index cd7c9ec7bc..79d4ea8501 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -36,17 +36,18 @@
#define VIRT_PCH_PIC_IRQ_NUM 32
#define VIRT_GSI_BASE 64
#define VIRT_DEVICE_IRQS 16
+#define VIRT_UART_COUNT 4
#define VIRT_UART_IRQ (VIRT_GSI_BASE + 2)
#define VIRT_UART_BASE 0x1fe001e0
-#define VIRT_UART_SIZE 0X100
-#define VIRT_RTC_IRQ (VIRT_GSI_BASE + 3)
+#define VIRT_UART_SIZE 0x100
+#define VIRT_RTC_IRQ (VIRT_GSI_BASE + 6)
#define VIRT_MISC_REG_BASE (VIRT_PCH_REG_BASE + 0x00080000)
#define VIRT_RTC_REG_BASE (VIRT_MISC_REG_BASE + 0x00050100)
#define VIRT_RTC_LEN 0x100
-#define VIRT_SCI_IRQ (VIRT_GSI_BASE + 4)
+#define VIRT_SCI_IRQ (VIRT_GSI_BASE + 7)
#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000
#define VIRT_PLATFORM_BUS_SIZE 0x2000000
#define VIRT_PLATFORM_BUS_NUM_IRQS 2
-#define VIRT_PLATFORM_BUS_IRQ (VIRT_GSI_BASE + 5)
+#define VIRT_PLATFORM_BUS_IRQ (VIRT_GSI_BASE + 8)
#endif
--
2.39.1

View File

@ -0,0 +1,212 @@
From ddaa38853d386e5b9f9fa1c3813048872c8ad687 Mon Sep 17 00:00:00 2001
From: niuyongwen <niuyongwen@hygon.cn>
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 <niuyongwen@hygon.cn>
---
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 <sys/ioctl.h>
@@ -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

View File

@ -0,0 +1,123 @@
From 884c4d6bc101454f0e0f3c779bc1155024b056c3 Mon Sep 17 00:00:00 2001
From: xiongmengbiao <xiongmengbiao@hygon.cn>
Date: Wed, 29 May 2024 15:18:55 +0800
Subject: [PATCH] hw/misc: support tkm use mem2 memory
Signed-off-by: xiongmengbiao <xiongmengbiao@hygon.cn>
---
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 <sys/ioctl.h>
#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

View File

@ -0,0 +1,43 @@
From 0b89dd1ae05d17f0bacbd34218799f00d04c8174 Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
Date: Thu, 17 Oct 2024 11:13:06 +0800
Subject: [PATCH] hw/net/can/sja1000: fix bug for single acceptance filter and
standard frame
cheery-pick from 25145a7d7735344a469551946fc2a7f19eb4aa3d
A CAN sja1000 standard frame filter mask has been computed and applied
incorrectly for standard frames when single Acceptance Filter Mode
(MOD_AFM = 1) has been selected. The problem has not been found
by Linux kernel testing because it uses dual filter mode (MOD_AFM = 0)
and leaves falters fully open.
The problem has been noticed by Grant Ramsay when testing with Zephyr
RTOS which uses single filter mode.
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Reported-by: Grant Ramsay <gramsay@enphaseenergy.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2028
Fixes: 733210e754 ("hw/net/can: SJA1000 chip register level emulation")
Message-ID: <20240103231426.5685-1-pisa@fel.cvut.cz>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
hw/net/can/can_sja1000.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c
index 73201f9139..575df7d2f8 100644
--- a/hw/net/can/can_sja1000.c
+++ b/hw/net/can/can_sja1000.c
@@ -108,7 +108,7 @@ void can_sja_single_filter(struct qemu_can_filter *filter,
}
filter->can_mask = (uint32_t)amr[0] << 3;
- filter->can_mask |= (uint32_t)amr[1] << 5;
+ filter->can_mask |= (uint32_t)amr[1] >> 5;
filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK;
if (!(amr[1] & 0x10)) {
filter->can_mask |= QEMU_CAN_RTR_FLAG;
--
2.41.0.windows.1

View File

@ -0,0 +1,102 @@
From c4423b70160eb7ae91dac9f2cf61513758ee017d Mon Sep 17 00:00:00 2001
From: Klaus Jensen <k.jensen@samsung.com>
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 <jwkozaczuk@gmail.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Signed-off-by: Zhongrui Tang <tangzhongrui_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,52 @@
From 3c108b874b8b142a42939d785d6706a44e7035d7 Mon Sep 17 00:00:00 2001
From: Roque Arcudia Hernandez <roqueh@google.com>
Date: Fri, 1 Nov 2024 21:59:23 +0000
Subject: [PATCH] hw/pci: Add parenthesis to PCI_BUILD_BDF macro
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The bus parameter in the macro PCI_BUILD_BDF is not surrounded by
parenthesis. This can create a compile error when warnings are
treated as errors or can potentially create runtime errors due to the
operator precedence.
For instance:
file.c:x:32: error: suggest parentheses around '-' inside '<<'
[-Werror=parentheses]
171 | uint16_t bdf = PCI_BUILD_BDF(a - b, sdev->devfn);
| ~~^~~
include/hw/pci/pci.h:19:41: note: in definition of macro
'PCI_BUILD_BDF'
19 | #define PCI_BUILD_BDF(bus, devfn) ((bus << 8) | (devfn))
| ^~~
cc1: all warnings being treated as errors
Signed-off-by: Roque Arcudia Hernandez <roqueh@google.com>
Reviewed-by: Nabih Estefan <nabihestefan@google.com>
Message-Id: <20241101215923.3399311-1-roqueh@google.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Zhongrui Tang <tangzhongrui_yewu@cmss.chinamobile.com>
---
include/hw/pci/pci.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index fa6313aabc..7cf7b5619a 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -15,7 +15,7 @@ extern bool pci_available;
#define PCI_BUS_NUM(x) (((x) >> 8) & 0xff)
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07)
-#define PCI_BUILD_BDF(bus, devfn) ((bus << 8) | (devfn))
+#define PCI_BUILD_BDF(bus, devfn) (((bus) << 8) | (devfn))
#define PCI_BDF_TO_DEVFN(x) ((x) & 0xff)
#define PCI_BUS_MAX 256
#define PCI_DEVFN_MAX 256
--
2.41.0.windows.1

View File

@ -0,0 +1,50 @@
From 55ea1e473095ea5be692bb4ba2e44131a4a88e73 Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
Date: Wed, 23 Oct 2024 13:40:51 +0800
Subject: [PATCH] hw/pci-bridge: Add a Kconfig switch for the normal PCI bridge
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
cheery-pick from e779e5c05ad5d8237e2a7d8ba8b432cd24c1708b
The pci-bridge device is not usable on s390x, so introduce a Kconfig
switch that allows to disable it.
Message-ID: <20240913144844.427899-1-thuth@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
hw/pci-bridge/Kconfig | 5 +++++
hw/pci-bridge/meson.build | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/hw/pci-bridge/Kconfig b/hw/pci-bridge/Kconfig
index 67077366cc..449ec98643 100644
--- a/hw/pci-bridge/Kconfig
+++ b/hw/pci-bridge/Kconfig
@@ -1,3 +1,8 @@
+config PCI_BRIDGE
+ bool
+ default y if PCI_DEVICES
+ depends on PCI
+
config PCIE_PORT
bool
default y if PCI_DEVICES
diff --git a/hw/pci-bridge/meson.build b/hw/pci-bridge/meson.build
index 6d5ad9f37b..a8b88e9099 100644
--- a/hw/pci-bridge/meson.build
+++ b/hw/pci-bridge/meson.build
@@ -1,5 +1,5 @@
pci_ss = ss.source_set()
-pci_ss.add(files('pci_bridge_dev.c'))
+pci_ss.add(when: 'CONFIG_PCI_BRIDGE', if_true: files('pci_bridge_dev.c'))
pci_ss.add(when: 'CONFIG_I82801B11', if_true: files('i82801b11.c'))
pci_ss.add(when: 'CONFIG_IOH3420', if_true: files('ioh3420.c'))
pci_ss.add(when: 'CONFIG_PCIE_PORT', if_true: files('pcie_root_port.c', 'gen_pcie_root_port.c'))
--
2.41.0.windows.1

View File

@ -0,0 +1,44 @@
From e025c40fac7d6cc5b4752c392a9c66a074dcaa0b Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
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 <clg@redhat.com>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Message-ID: <20241103133412.73536-6-shentey@gmail.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,44 @@
From b85c8374d8b78a6ec1c250bb7562423e6f5d89a0 Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
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 <balaton@eik.bme.hu>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Message-ID: <20241103133412.73536-4-shentey@gmail.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,44 @@
From 239e256d5510b9aaa3e099359dcda54970e2f08a Mon Sep 17 00:00:00 2001
From: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
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 <balaton@eik.bme.hu>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Message-ID: <20241103133412.73536-5-shentey@gmail.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Zhang Jiao <zhangjiao2_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,593 @@
From ebafa8d737b5f08e787803375d6e942ecdaef1a9 Mon Sep 17 00:00:00 2001
From: Yabin Li <liyabin@hygon.cn>
Date: Fri, 4 Aug 2023 21:09:08 +0800
Subject: [PATCH] hw/vfio: add device hct based on vfio.
add hct device based on vfio, used to simulate ccp devices
Signed-off-by: Yabin Li <liyabin@hygon.cn>
Signed-off-by: yangdepei <yangdepei@hygon.cn>
---
hw/vfio/Kconfig | 6 +
hw/vfio/hct.c | 543 ++++++++++++++++++++++++++++++++++++++++++++
hw/vfio/meson.build | 1 +
3 files changed, 550 insertions(+)
create mode 100644 hw/vfio/hct.c
diff --git a/hw/vfio/Kconfig b/hw/vfio/Kconfig
index 7cdba0560a..5f0d3c2d2b 100644
--- a/hw/vfio/Kconfig
+++ b/hw/vfio/Kconfig
@@ -41,3 +41,9 @@ config VFIO_IGD
bool
default y if PC_PCI
depends on VFIO_PCI
+
+config VFIO_HCT
+ bool
+ default y
+ select VFIO
+ depends on LINUX && PCI
diff --git a/hw/vfio/hct.c b/hw/vfio/hct.c
new file mode 100644
index 0000000000..476e86c61d
--- /dev/null
+++ b/hw/vfio/hct.c
@@ -0,0 +1,543 @@
+/*
+ * vfio based mediated ccp(hct) assignment support
+ *
+ * Copyright 2023 HYGON Corp.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include <linux/vfio.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "qemu/osdep.h"
+#include "qemu/queue.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/pci/pci.h"
+#include "hw/vfio/pci.h"
+#include "qemu/range.h"
+#include "sysemu/kvm.h"
+#include "hw/pci/msi.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+
+#define MAX_CCP_CNT 16
+#define PAGE_SIZE 4096
+#define HCT_SHARED_MEMORY_SIZE (PAGE_SIZE * MAX_CCP_CNT)
+#define CCP_INDEX_BYTES 4
+#define PATH_MAX 4096
+#define TYPE_HCT_DEV "hct"
+#define PCI_HCT_DEV(obj) OBJECT_CHECK(HCTDevState, (obj), TYPE_HCT_DEV)
+#define HCT_MMIO_SIZE (1 << 20)
+#define HCT_MAX_PASID (1 << 8)
+
+#define PCI_VENDOR_ID_HYGON_CCP 0x1d94
+#define PCI_DEVICE_ID_HYGON_CCP 0x1468
+
+#define HCT_SHARE_DEV "/dev/hct_share"
+
+#define HCT_VERSION_STRING "0.2"
+#define DEF_VERSION_STRING "0.1"
+#define VERSION_SIZE 16
+
+#define HCT_SHARE_IOC_TYPE 'C'
+#define HCT_SHARE_OP_TYPE 0x01
+#define HCT_SHARE_OP _IOWR(HCT_SHARE_IOC_TYPE, \
+ HCT_SHARE_OP_TYPE, \
+ struct hct_dev_ctrl)
+#define HCT_SHARE_OP_DMA_MAP 0x01
+#define HCT_SHARE_OP_GET_ID 0x03
+#define HCT_SHARE_OP_GET_PASID 0x04
+#define HCT_SHARE_OP_DMA_UNMAP 0x05
+#define HCT_SHARE_OP_GET_VERSION 0x06
+
+/* BARS */
+#define HCT_REG_BAR_IDX 2
+#define HCT_SHARED_BAR_IDX 3
+#define HCT_PASID_BAR_IDX 4
+
+#define PASID_OFFSET 40
+
+static volatile struct hct_data {
+ int init;
+ int hct_fd;
+ unsigned long pasid;
+ uint8_t *pasid_memory;
+ uint8_t *hct_shared_memory;
+ uint8_t ccp_index[MAX_CCP_CNT];
+ uint8_t ccp_cnt;
+} hct_data;
+
+typedef struct SharedDevice {
+ PCIDevice dev;
+ int shared_memory_offset;
+} SharedDevice;
+
+typedef struct HctDevState {
+ SharedDevice sdev;
+ VFIODevice vdev;
+ MemoryRegion mmio;
+ MemoryRegion shared;
+ MemoryRegion pasid;
+ void *maps[PCI_NUM_REGIONS];
+} HCTDevState;
+
+struct hct_dev_ctrl {
+ unsigned char op;
+ unsigned char rsvd[3];
+ union {
+ unsigned char version[VERSION_SIZE];
+ struct {
+ unsigned long vaddr;
+ unsigned long iova;
+ unsigned long size;
+ };
+ unsigned int id;
+ };
+};
+
+static int pasid_get_and_init(HCTDevState *state)
+{
+ struct hct_dev_ctrl ctrl;
+ int ret;
+
+ ctrl.op = HCT_SHARE_OP_GET_PASID;
+ ctrl.id = -1;
+ ret = ioctl(hct_data.hct_fd, HCT_SHARE_OP, &ctrl);
+ if (ret < 0) {
+ ret = -errno;
+ error_report("GET_PASID fail: %d", -errno);
+ goto out;
+ }
+
+ *hct_data.pasid_memory = ctrl.id;
+ hct_data.pasid = ctrl.id;
+
+out:
+ return ret;
+}
+
+static const MemoryRegionOps hct_mmio_ops = {
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid =
+ {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void vfio_hct_detach_device(HCTDevState *state)
+{
+ vfio_detach_device(&state->vdev);
+ g_free(state->vdev.name);
+}
+
+static void vfio_hct_exit(PCIDevice *dev)
+{
+ HCTDevState *state = PCI_HCT_DEV(dev);
+
+ vfio_hct_detach_device(state);
+
+ if (hct_data.hct_fd) {
+ qemu_close(hct_data.hct_fd);
+ hct_data.hct_fd = 0;
+ }
+}
+
+static Property vfio_hct_properties[] = {
+ DEFINE_PROP_STRING("sysfsdev", HCTDevState, vdev.sysfsdev),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vfio_ccp_compute_needs_reset(VFIODevice *vdev)
+{
+ vdev->needs_reset = false;
+}
+
+struct VFIODeviceOps vfio_ccp_ops = {
+ .vfio_compute_needs_reset = vfio_ccp_compute_needs_reset,
+};
+
+/* create BAR2, BAR3 and BAR4 space for the virtual machine. */
+static int vfio_hct_region_mmap(HCTDevState *state)
+{
+ int ret;
+ int i;
+ struct vfio_region_info *info;
+
+ for (i = 0; i < PCI_ROM_SLOT; i++) {
+ ret = vfio_get_region_info(&state->vdev, i, &info);
+ if (ret)
+ goto out;
+
+ if (info->size) {
+ state->maps[i] = mmap(NULL, info->size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, state->vdev.fd, info->offset);
+ if (state->maps[i] == MAP_FAILED) {
+ ret = -errno;
+ g_free(info);
+ error_report("vfio mmap fail\n");
+ goto out;
+ }
+ }
+ g_free(info);
+ }
+
+ memory_region_init_io(&state->mmio, OBJECT(state), &hct_mmio_ops, state,
+ "hct mmio", HCT_MMIO_SIZE);
+ memory_region_init_ram_device_ptr(&state->mmio, OBJECT(state), "hct mmio",
+ HCT_MMIO_SIZE,
+ state->maps[HCT_REG_BAR_IDX]);
+
+ memory_region_init_io(&state->shared, OBJECT(state), &hct_mmio_ops, state,
+ "hct shared memory", PAGE_SIZE);
+ memory_region_init_ram_device_ptr(
+ &state->shared, OBJECT(state), "hct shared memory", PAGE_SIZE,
+ (void *)hct_data.hct_shared_memory +
+ state->sdev.shared_memory_offset * PAGE_SIZE);
+
+ memory_region_init_io(&state->pasid, OBJECT(state), &hct_mmio_ops, state,
+ "hct pasid", PAGE_SIZE);
+ memory_region_init_ram_device_ptr(&state->pasid, OBJECT(state), "hct pasid",
+ PAGE_SIZE, hct_data.pasid_memory);
+
+ pci_register_bar(&state->sdev.dev, HCT_REG_BAR_IDX,
+ PCI_BASE_ADDRESS_SPACE_MEMORY, &state->mmio);
+ pci_register_bar(&state->sdev.dev, HCT_SHARED_BAR_IDX,
+ PCI_BASE_ADDRESS_SPACE_MEMORY, &state->shared);
+ pci_register_bar(&state->sdev.dev, HCT_PASID_BAR_IDX,
+ PCI_BASE_ADDRESS_SPACE_MEMORY, &state->pasid);
+out:
+ return ret;
+}
+
+static int hct_check_duplicated_index(int index)
+{
+ int cnt;
+ for (cnt = 0; cnt < hct_data.ccp_cnt; cnt++) {
+ if (hct_data.ccp_index[cnt] == index) {
+ error_report("many mdev shouldn't be mapped to one ccp in a "
+ "virtual machine!\n");
+ return -1;
+ }
+ }
+
+ hct_data.ccp_index[hct_data.ccp_cnt++] = index;
+ return 0;
+}
+
+static int hct_get_ccp_index(HCTDevState *state)
+{
+ char path[PATH_MAX];
+ char buf[CCP_INDEX_BYTES];
+ int fd;
+ int ret;
+ int ccp_index;
+
+ snprintf(path, PATH_MAX, "%s/vendor/id", state->vdev.sysfsdev);
+ fd = qemu_open_old(path, O_RDONLY);
+ if (fd < 0) {
+ error_report("open %s fail\n", path);
+ return -errno;
+ }
+
+ ret = read(fd, buf, sizeof(buf));
+ if (ret < 0) {
+ ret = -errno;
+ error_report("read %s fail\n", path);
+ goto out;
+ }
+
+ if (1 != sscanf(buf, "%d", &ccp_index)) {
+ ret = -errno;
+ error_report("format addr %s fail\n", buf);
+ goto out;
+ }
+
+ if (!hct_check_duplicated_index(ccp_index)) {
+ state->sdev.shared_memory_offset = ccp_index;
+ } else {
+ ret = -1;
+ }
+
+out:
+ qemu_close(fd);
+ return ret;
+}
+
+static int hct_api_version_check(void)
+{
+ struct hct_dev_ctrl ctrl;
+ int ret;
+
+ ctrl.op = HCT_SHARE_OP_GET_VERSION;
+ memcpy(ctrl.version, DEF_VERSION_STRING, sizeof(DEF_VERSION_STRING));
+ ret = ioctl(hct_data.hct_fd, HCT_SHARE_OP, &ctrl);
+ if (ret < 0) {
+ error_report("ret %d, errno %d: fail to get hct.ko version, please "
+ "update hct.ko to version 0.2.\n",
+ ret, errno);
+ return -1;
+ } else if (memcmp(ctrl.version, HCT_VERSION_STRING,
+ sizeof(HCT_VERSION_STRING)) < 0) {
+ error_report("The API version %s is larger than hct.ko version %s, "
+ "please update hct.ko to version 0.2\n",
+ HCT_VERSION_STRING, ctrl.version);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int hct_shared_memory_init(void)
+{
+ int ret = 0;
+
+ hct_data.hct_shared_memory =
+ mmap(NULL, HCT_SHARED_MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+ hct_data.hct_fd, 0);
+ if (hct_data.hct_shared_memory == MAP_FAILED) {
+ ret = -errno;
+ error_report("map hct shared memory fail\n");
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void hct_listener_region_add(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ struct hct_dev_ctrl ctrl;
+ hwaddr iova;
+ Int128 llend, llsize;
+ void *vaddr;
+ int ret;
+
+ iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space);
+ llend = int128_make64(section->offset_within_address_space);
+ llend = int128_add(llend, section->size);
+ llend = int128_add(llend, int128_exts64(qemu_real_host_page_mask()));
+
+ if (int128_ge(int128_make64(iova), llend)) {
+ return;
+ }
+
+ if (!section->mr->ram) {
+ return;
+ }
+
+ vaddr = memory_region_get_ram_ptr(section->mr) +
+ section->offset_within_region +
+ (iova - section->offset_within_address_space);
+ llsize = int128_sub(llend, int128_make64(iova));
+
+ ctrl.op = HCT_SHARE_OP_DMA_MAP;
+ ctrl.iova = iova | (hct_data.pasid << PASID_OFFSET);
+ ctrl.vaddr = (uint64_t)vaddr;
+ ctrl.size = llsize;
+ ret = ioctl(hct_data.hct_fd, HCT_SHARE_OP, &ctrl);
+ if (ret < 0)
+ error_report("VFIO_MAP_DMA: %d, iova=%lx", -errno, iova);
+}
+
+static void hct_listener_region_del(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ struct hct_dev_ctrl ctrl;
+ hwaddr iova;
+ Int128 llend, llsize;
+ int ret;
+
+ iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space);
+ llend = int128_make64(section->offset_within_address_space);
+ llend = int128_add(llend, section->size);
+ llend = int128_add(llend, int128_exts64(qemu_real_host_page_mask()));
+
+ if (int128_ge(int128_make64(iova), llend)) {
+ return;
+ }
+
+ if (!section->mr->ram) {
+ return;
+ }
+
+ llsize = int128_sub(llend, int128_make64(iova));
+
+ ctrl.op = HCT_SHARE_OP_DMA_UNMAP;
+ ctrl.iova = iova | (hct_data.pasid << PASID_OFFSET);
+ ctrl.size = llsize;
+ ret = ioctl(hct_data.hct_fd, HCT_SHARE_OP, &ctrl);
+ if (ret < 0)
+ error_report("VFIO_UNMAP_DMA: %d", -errno);
+}
+
+static MemoryListener hct_memory_listener = {
+ .region_add = hct_listener_region_add,
+ .region_del = hct_listener_region_del,
+};
+
+static void hct_data_uninit(HCTDevState *state)
+{
+ if (hct_data.hct_fd) {
+ qemu_close(hct_data.hct_fd);
+ hct_data.hct_fd = 0;
+ }
+
+ if (hct_data.pasid) {
+ hct_data.pasid = 0;
+ }
+
+ if (hct_data.pasid_memory) {
+ munmap(hct_data.pasid_memory, PAGE_SIZE);
+ hct_data.pasid_memory = NULL;
+ }
+
+ if (hct_data.hct_shared_memory) {
+ munmap((void *)hct_data.hct_shared_memory, HCT_SHARED_MEMORY_SIZE);
+ hct_data.hct_shared_memory = NULL;
+ }
+
+ memory_listener_unregister(&hct_memory_listener);
+}
+
+static int hct_data_init(HCTDevState *state)
+{
+ int ret;
+
+ if (hct_data.init == 0) {
+
+ hct_data.hct_fd = qemu_open_old(HCT_SHARE_DEV, O_RDWR);
+ if (hct_data.hct_fd < 0) {
+ error_report("fail to open %s, errno %d.", HCT_SHARE_DEV, errno);
+ ret = -errno;
+ goto out;
+ }
+
+ /* The hct.ko version number needs not to be less than 0.2. */
+ ret = hct_api_version_check();
+ if (ret)
+ goto out;
+
+ /* assign a page to the virtual BAR3 of each CCP. */
+ ret = hct_shared_memory_init();
+ if (ret)
+ goto out;
+
+ hct_data.pasid_memory = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (hct_data.pasid_memory < 0)
+ goto unmap_shared_memory_exit;
+
+ /* assign a unique pasid to each virtual machine. */
+ ret = pasid_get_and_init(state);
+ if (ret < 0)
+ goto unmap_pasid_memory_exit;
+
+ /* perform DMA_MAP and DMA_UNMAP operations on all memories of the
+ * virtual machine. */
+ memory_listener_register(&hct_memory_listener, &address_space_memory);
+
+ hct_data.init = 1;
+ }
+
+ return hct_get_ccp_index(state);
+
+unmap_pasid_memory_exit:
+ munmap(hct_data.pasid_memory, PAGE_SIZE);
+
+unmap_shared_memory_exit:
+ munmap((void *)hct_data.hct_shared_memory, HCT_SHARED_MEMORY_SIZE);
+
+out:
+ return ret;
+}
+
+/* When device is loaded */
+static void vfio_hct_realize(PCIDevice *pci_dev, Error **errp)
+{
+ int ret;
+ char *mdevid;
+ Error *err = NULL;
+ HCTDevState *state = PCI_HCT_DEV(pci_dev);
+
+ /* parsing mdev device name from startup scripts */
+ mdevid = g_path_get_basename(state->vdev.sysfsdev);
+ state->vdev.name = g_strdup_printf("%s", mdevid);
+
+ ret = hct_data_init(state);
+ if (ret < 0) {
+ g_free(state->vdev.name);
+ goto out;
+ }
+
+ ret = vfio_attach_device(state->vdev.name, &state->vdev,
+ pci_device_iommu_address_space(pci_dev), &err);
+
+ if (ret) {
+ error_report("attach device failed, name = %s", state->vdev.name);
+ goto data_uninit_out;
+ }
+
+ state->vdev.ops = &vfio_ccp_ops;
+ state->vdev.dev = &state->sdev.dev.qdev;
+
+ ret = vfio_hct_region_mmap(state);
+ if (ret < 0)
+ goto detach_device_out;
+
+ return;
+
+detach_device_out:
+ vfio_hct_detach_device(state);
+
+data_uninit_out:
+ hct_data_uninit(state);
+
+out:
+ return;
+}
+
+static void hct_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
+
+ dc->desc = "HCT Device";
+ device_class_set_props(dc, vfio_hct_properties);
+
+ pdc->realize = vfio_hct_realize;
+ pdc->exit = vfio_hct_exit;
+ pdc->vendor_id = PCI_VENDOR_ID_HYGON_CCP;
+ pdc->device_id = PCI_DEVICE_ID_HYGON_CCP;
+ pdc->class_id = PCI_CLASS_CRYPT_OTHER;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+
+ return;
+}
+
+static const TypeInfo pci_hct_info = {
+ .name = TYPE_HCT_DEV,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(HCTDevState),
+ .class_init = hct_dev_class_init,
+ .interfaces =
+ (InterfaceInfo[]){
+ {INTERFACE_CONVENTIONAL_PCI_DEVICE},
+ {},
+ },
+};
+
+static void hct_register_types(void) {
+ type_register_static(&pci_hct_info);
+}
+
+type_init(hct_register_types);
diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build
index 2a6912c940..b1db4c8605 100644
--- a/hw/vfio/meson.build
+++ b/hw/vfio/meson.build
@@ -17,5 +17,6 @@ vfio_ss.add(when: 'CONFIG_VFIO_XGMAC', if_true: files('calxeda-xgmac.c'))
vfio_ss.add(when: 'CONFIG_VFIO_AMD_XGBE', if_true: files('amd-xgbe.c'))
vfio_ss.add(when: 'CONFIG_VFIO_AP', if_true: files('ap.c'))
vfio_ss.add(when: 'CONFIG_VFIO_IGD', if_true: files('igd.c'))
+vfio_ss.add(when: 'CONFIG_VFIO_HCT', if_true: files('hct.c'))
specific_ss.add_all(when: 'CONFIG_VFIO', if_true: vfio_ss)
--
2.41.0.windows.1

View File

@ -0,0 +1,28 @@
From 360bd43ff3c4e4938ee8af1a5ccf981152f7ca95 Mon Sep 17 00:00:00 2001
From: yangdepei <yangdepei@hygon.cn>
Date: Mon, 26 Aug 2024 15:40:25 +0800
Subject: [PATCH] hw/vfio/hct: fix ccp_index error caused by uninitialized buf
Signed-off-by: yangdepei <yangdepei@hygon.cn>
---
hw/vfio/hct.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/vfio/hct.c b/hw/vfio/hct.c
index 790bb78439..9374e95e85 100644
--- a/hw/vfio/hct.c
+++ b/hw/vfio/hct.c
@@ -235,8 +235,8 @@ static int hct_check_duplicated_index(int index)
static int hct_get_ccp_index(HCTDevState *state)
{
- char path[PATH_MAX];
- char buf[CCP_INDEX_BYTES];
+ char path[PATH_MAX] = {0};
+ char buf[CCP_INDEX_BYTES] = {0};
int fd;
int ret;
int ccp_index;
--
2.41.0.windows.1

View File

@ -0,0 +1,79 @@
From 32855e315c3050f09388f1335c0869bba065fbae Mon Sep 17 00:00:00 2001
From: yangdepei <yangdepei@hygon.cn>
Date: Fri, 27 Sep 2024 17:08:08 +0800
Subject: [PATCH] hw/vfio/hct: qemu startup terminate once error happened in
hct
Signed-off-by: yangdepei <yangdepei@hygon.cn>
---
hw/vfio/hct.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/hw/vfio/hct.c b/hw/vfio/hct.c
index 9374e95e85..7fd3977182 100644
--- a/hw/vfio/hct.c
+++ b/hw/vfio/hct.c
@@ -136,7 +136,9 @@ static const MemoryRegionOps hct_mmio_ops = {
static void vfio_hct_detach_device(HCTDevState *state)
{
vfio_detach_device(&state->vdev);
- g_free(state->vdev.name);
+
+ if (state->vdev.name)
+ g_free(state->vdev.name);
}
static void vfio_hct_exit(PCIDevice *dev)
@@ -413,7 +415,6 @@ static int hct_data_init(HCTDevState *state)
int ret;
if (hct_data.init == 0) {
-
hct_data.hct_fd = qemu_open_old(HCT_SHARE_DEV, O_RDWR);
if (hct_data.hct_fd < 0) {
error_report("fail to open %s, errno %d.", HCT_SHARE_DEV, errno);
@@ -465,7 +466,6 @@ static void vfio_hct_realize(PCIDevice *pci_dev, Error **errp)
{
int ret;
char *mdevid;
- Error *err = NULL;
HCTDevState *state = PCI_HCT_DEV(pci_dev);
/* parsing mdev device name from startup scripts */
@@ -475,14 +475,18 @@ static void vfio_hct_realize(PCIDevice *pci_dev, Error **errp)
ret = hct_data_init(state);
if (ret < 0) {
g_free(state->vdev.name);
+ state->vdev.name = NULL;
+ error_setg(errp, "hct data init failed");
goto out;
}
ret = vfio_attach_device(state->vdev.name, &state->vdev,
- pci_device_iommu_address_space(pci_dev), &err);
+ pci_device_iommu_address_space(pci_dev), errp);
if (ret) {
- error_report("attach device failed, name = %s", state->vdev.name);
+ g_free(state->vdev.name);
+ state->vdev.name = NULL;
+ error_setg(errp, "attach device failed, name = %s", state->vdev.name);
goto data_uninit_out;
}
@@ -491,7 +495,12 @@ static void vfio_hct_realize(PCIDevice *pci_dev, Error **errp)
ret = vfio_hct_region_mmap(state);
if (ret < 0)
+ {
+ g_free(state->vdev.name);
+ state->vdev.name = NULL;
+ error_setg(errp, "region mmap failed, name = %s", state->vdev.name);
goto detach_device_out;
+ }
return;
--
2.41.0.windows.1

Some files were not shown because too many files have changed in this diff Show More